discovery.c revision 256194
117651Speter/*- 217651Speter * Copyright (c) 2012 The FreeBSD Foundation 317651Speter * All rights reserved. 417651Speter * 517651Speter * This software was developed by Edward Tomasz Napierala under sponsorship 617651Speter * from the FreeBSD Foundation. 717651Speter * 817651Speter * Redistribution and use in source and binary forms, with or without 917651Speter * modification, are permitted provided that the following conditions 1017651Speter * are met: 1117651Speter * 1. Redistributions of source code must retain the above copyright 1217651Speter * notice, this list of conditions and the following disclaimer. 1317651Speter * 2. Redistributions in binary form must reproduce the above copyright 1417651Speter * notice, this list of conditions and the following disclaimer in the 1517651Speter * documentation and/or other materials provided with the distribution. 1617651Speter * 1717651Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1817651Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1917651Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2017651Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2117651Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2217651Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2317651Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2417651Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2517651Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2617651Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2717651Speter * SUCH DAMAGE. 2817651Speter * 2917651Speter * $FreeBSD: head/usr.sbin/iscsid/discovery.c 256194 2013-10-09 13:48:08Z trasz $ 3017651Speter */ 3117651Speter 3217651Speter#include <sys/types.h> 3317651Speter#include <sys/ioctl.h> 3417651Speter#include <assert.h> 3517651Speter#include <stdbool.h> 3617651Speter#include <stdio.h> 3717651Speter#include <stdlib.h> 3817651Speter#include <string.h> 3917651Speter#include <netinet/in.h> 4017651Speter 4117651Speter#include "iscsid.h" 4217651Speter#include "iscsi_proto.h" 4317651Speter 4417651Speterstatic struct pdu * 4517651Spetertext_receive(struct connection *conn) 4617651Speter{ 4717651Speter struct pdu *response; 4817651Speter struct iscsi_bhs_text_response *bhstr; 4917651Speter 5017651Speter response = pdu_new(conn); 5117651Speter pdu_receive(response); 5217651Speter if (response->pdu_bhs->bhs_opcode != ISCSI_BHS_OPCODE_TEXT_RESPONSE) 5317651Speter log_errx(1, "protocol error: received invalid opcode 0x%x", 5417651Speter response->pdu_bhs->bhs_opcode); 5517651Speter bhstr = (struct iscsi_bhs_text_response *)response->pdu_bhs; 5617651Speter#if 0 5717651Speter if ((bhstr->bhstr_flags & BHSTR_FLAGS_FINAL) == 0) 5817651Speter log_errx(1, "received Text PDU without the \"F\" flag"); 5917651Speter#endif 6017651Speter /* 6117651Speter * XXX: Implement the C flag some day. 6217651Speter */ 6317651Speter if ((bhstr->bhstr_flags & BHSTR_FLAGS_CONTINUE) != 0) 6417651Speter log_errx(1, "received Text PDU with unsupported \"C\" flag"); 6517651Speter if (response->pdu_data_len == 0) 6617651Speter log_errx(1, "received Text PDU with empty data segment"); 6717651Speter if (ntohl(bhstr->bhstr_statsn) != conn->conn_statsn + 1) { 6817651Speter log_errx(1, "received Text PDU with wrong StatSN: " 6917651Speter "is %d, should be %d", ntohl(bhstr->bhstr_statsn), 7017651Speter conn->conn_statsn + 1); 7117651Speter } 7217651Speter conn->conn_statsn = ntohl(bhstr->bhstr_statsn); 7317651Speter 7417651Speter return (response); 7517651Speter} 7617651Speter 7717651Speterstatic struct pdu * 7817651Spetertext_new_request(struct connection *conn) 7917651Speter{ 8017651Speter struct pdu *request; 8117651Speter struct iscsi_bhs_text_request *bhstr; 8217651Speter 8317651Speter request = pdu_new(conn); 8417651Speter bhstr = (struct iscsi_bhs_text_request *)request->pdu_bhs; 8517651Speter bhstr->bhstr_opcode = ISCSI_BHS_OPCODE_TEXT_REQUEST | 8617651Speter ISCSI_BHS_OPCODE_IMMEDIATE; 8717651Speter bhstr->bhstr_flags = BHSTR_FLAGS_FINAL; 8817651Speter bhstr->bhstr_initiator_task_tag = 0; 8917651Speter bhstr->bhstr_target_transfer_tag = 0xffffffff; 9017651Speter 9117651Speter bhstr->bhstr_initiator_task_tag = 0; /* XXX */ 9217651Speter bhstr->bhstr_cmdsn = 0; /* XXX */ 9317651Speter bhstr->bhstr_expstatsn = htonl(conn->conn_statsn + 1); 9417651Speter 9517651Speter return (request); 9617651Speter} 9717651Speter 9817651Speterstatic struct pdu * 9917651Speterlogout_receive(struct connection *conn) 10017651Speter{ 10117651Speter struct pdu *response; 10217651Speter struct iscsi_bhs_logout_response *bhslr; 10317651Speter 10417651Speter response = pdu_new(conn); 10517651Speter pdu_receive(response); 10617651Speter if (response->pdu_bhs->bhs_opcode != ISCSI_BHS_OPCODE_LOGOUT_RESPONSE) 10717651Speter log_errx(1, "protocol error: received invalid opcode 0x%x", 10817651Speter response->pdu_bhs->bhs_opcode); 10917651Speter bhslr = (struct iscsi_bhs_logout_response *)response->pdu_bhs; 11017651Speter if (ntohs(bhslr->bhslr_response) != BHSLR_RESPONSE_CLOSED_SUCCESSFULLY) 11117651Speter log_warnx("received Logout Response with reason %d", 11217651Speter ntohs(bhslr->bhslr_response)); 11317651Speter if (ntohl(bhslr->bhslr_statsn) != conn->conn_statsn + 1) { 11417651Speter log_errx(1, "received Logout PDU with wrong StatSN: " 11517651Speter "is %d, should be %d", ntohl(bhslr->bhslr_statsn), 11617651Speter conn->conn_statsn + 1); 11717651Speter } 11817651Speter conn->conn_statsn = ntohl(bhslr->bhslr_statsn); 11917651Speter 12017651Speter return (response); 12117651Speter} 12217651Speter 12317651Speterstatic struct pdu * 12417651Speterlogout_new_request(struct connection *conn) 12517651Speter{ 12617651Speter struct pdu *request; 12717651Speter struct iscsi_bhs_logout_request *bhslr; 12817651Speter 12917651Speter request = pdu_new(conn); 13017651Speter bhslr = (struct iscsi_bhs_logout_request *)request->pdu_bhs; 13117651Speter bhslr->bhslr_opcode = ISCSI_BHS_OPCODE_LOGOUT_REQUEST | 13217651Speter ISCSI_BHS_OPCODE_IMMEDIATE; 13317651Speter bhslr->bhslr_reason = BHSLR_REASON_CLOSE_SESSION; 13417651Speter bhslr->bhslr_reason |= 0x80; 13517651Speter bhslr->bhslr_initiator_task_tag = 0; /* XXX */ 13617651Speter bhslr->bhslr_cmdsn = 0; /* XXX */ 13717651Speter bhslr->bhslr_expstatsn = htonl(conn->conn_statsn + 1); 13817651Speter 13917651Speter return (request); 14017651Speter} 14117651Speter 14217651Speterstatic void 14317651Speterkernel_add(const struct connection *conn, const char *target) 14417651Speter{ 14517651Speter struct iscsi_session_add isa; 14617651Speter int error; 14717651Speter 14817651Speter memset(&isa, 0, sizeof(isa)); 14917651Speter memcpy(&isa.isa_conf, &conn->conn_conf, sizeof(isa.isa_conf)); 15017651Speter strlcpy(isa.isa_conf.isc_target, target, 15117651Speter sizeof(isa.isa_conf.isc_target)); 15217651Speter isa.isa_conf.isc_discovery = 0; 15317651Speter error = ioctl(conn->conn_iscsi_fd, ISCSISADD, &isa); 15417651Speter if (error != 0) 15517651Speter log_warn("failed to add %s: ISCSISADD", target); 15617651Speter} 15717651Speter 15817651Speterstatic void 15917651Speterkernel_remove(const struct connection *conn) 16017651Speter{ 16117651Speter struct iscsi_session_remove isr; 16217651Speter int error; 16317651Speter 16417651Speter memset(&isr, 0, sizeof(isr)); 16517651Speter isr.isr_session_id = conn->conn_session_id; 16617651Speter error = ioctl(conn->conn_iscsi_fd, ISCSISREMOVE, &isr); 16717651Speter if (error != 0) 16817651Speter log_warn("ISCSISREMOVE"); 16917651Speter} 17017651Speter 17117651Spetervoid 17217651Speterdiscovery(struct connection *conn) 17317651Speter{ 17417651Speter struct pdu *request, *response; 17517651Speter struct keys *request_keys, *response_keys; 17617651Speter int i; 17717651Speter 17817651Speter log_debugx("beginning discovery session"); 17917651Speter request = text_new_request(conn); 18017651Speter request_keys = keys_new(); 18117651Speter keys_add(request_keys, "SendTargets", "All"); 18217651Speter keys_save(request_keys, request); 18317651Speter keys_delete(request_keys); 18417651Speter request_keys = NULL; 18517651Speter pdu_send(request); 18617651Speter pdu_delete(request); 18717651Speter request = NULL; 18817651Speter 18917651Speter log_debugx("waiting for Text Response"); 19017651Speter response = text_receive(conn); 19117651Speter response_keys = keys_new(); 19217651Speter keys_load(response_keys, response); 19317651Speter for (i = 0; i < KEYS_MAX; i++) { 19417651Speter if (response_keys->keys_names[i] == NULL) 19517651Speter break; 19617651Speter 19717651Speter if (strcmp(response_keys->keys_names[i], "TargetName") != 0) 19817651Speter continue; 19917651Speter 20017651Speter log_debugx("adding target %s", response_keys->keys_values[i]); 20117651Speter /* 20217651Speter * XXX: Validate the target name? 20317651Speter */ 20417651Speter kernel_add(conn, response_keys->keys_values[i]); 20517651Speter } 20617651Speter keys_delete(response_keys); 20717651Speter pdu_delete(response); 20817651Speter 20917651Speter log_debugx("removing temporary discovery session"); 21017651Speter kernel_remove(conn); 21117651Speter 21217651Speter log_debugx("discovery done; logging out"); 21317651Speter request = logout_new_request(conn); 21417651Speter pdu_send(request); 21517651Speter pdu_delete(request); 21617651Speter request = NULL; 21717651Speter 21817651Speter log_debugx("waiting for Logout Response"); 21917651Speter response = logout_receive(conn); 22017651Speter pdu_delete(response); 22117651Speter 22217651Speter log_debugx("discovery session done"); 22317651Speter} 22417651Speter