discovery.c revision 290145
147398Sdfr/*- 247398Sdfr * Copyright (c) 2012 The FreeBSD Foundation 347398Sdfr * All rights reserved. 447398Sdfr * 547398Sdfr * This software was developed by Edward Tomasz Napierala under sponsorship 647398Sdfr * from the FreeBSD Foundation. 747398Sdfr * 847398Sdfr * Redistribution and use in source and binary forms, with or without 947398Sdfr * modification, are permitted provided that the following conditions 1047398Sdfr * are met: 1147398Sdfr * 1. Redistributions of source code must retain the above copyright 1247398Sdfr * notice, this list of conditions and the following disclaimer. 1347398Sdfr * 2. Redistributions in binary form must reproduce the above copyright 1447398Sdfr * notice, this list of conditions and the following disclaimer in the 1547398Sdfr * documentation and/or other materials provided with the distribution. 1647398Sdfr * 1747398Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1847398Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1947398Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2047398Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2147398Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2247398Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2347398Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2447398Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2547398Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2647398Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2747398Sdfr * SUCH DAMAGE. 2847398Sdfr * 2947398Sdfr */ 3047398Sdfr 3147398Sdfr#include <sys/cdefs.h> 3247398Sdfr__FBSDID("$FreeBSD: stable/10/usr.sbin/iscsid/discovery.c 290145 2015-10-29 16:34:55Z delphij $"); 3347398Sdfr 3447398Sdfr#include <sys/types.h> 3547398Sdfr#include <sys/ioctl.h> 3647398Sdfr#include <stdbool.h> 3747398Sdfr#include <string.h> 3847398Sdfr#include <netinet/in.h> 3947398Sdfr 4047398Sdfr#include "iscsid.h" 4147398Sdfr#include "iscsi_proto.h" 4247398Sdfr 4347398Sdfrstatic struct pdu * 4447398Sdfrtext_receive(struct connection *conn) 4547398Sdfr{ 4647398Sdfr struct pdu *response; 4747398Sdfr struct iscsi_bhs_text_response *bhstr; 4847398Sdfr 4947398Sdfr response = pdu_new(conn); 5047398Sdfr pdu_receive(response); 5147398Sdfr if (response->pdu_bhs->bhs_opcode != ISCSI_BHS_OPCODE_TEXT_RESPONSE) 5247398Sdfr log_errx(1, "protocol error: received invalid opcode 0x%x", 5347398Sdfr response->pdu_bhs->bhs_opcode); 5447398Sdfr bhstr = (struct iscsi_bhs_text_response *)response->pdu_bhs; 5547398Sdfr#if 0 5647398Sdfr if ((bhstr->bhstr_flags & BHSTR_FLAGS_FINAL) == 0) 5747398Sdfr log_errx(1, "received Text PDU without the \"F\" flag"); 5847398Sdfr#endif 5947398Sdfr /* 60116181Sobrien * XXX: Implement the C flag some day. 61116181Sobrien */ 62116181Sobrien if ((bhstr->bhstr_flags & BHSTR_FLAGS_CONTINUE) != 0) 6347398Sdfr log_errx(1, "received Text PDU with unsupported \"C\" flag"); 6447398Sdfr if (ntohl(bhstr->bhstr_statsn) != conn->conn_statsn + 1) { 6547398Sdfr log_errx(1, "received Text PDU with wrong StatSN: " 6647398Sdfr "is %u, should be %u", ntohl(bhstr->bhstr_statsn), 6747398Sdfr conn->conn_statsn + 1); 6847398Sdfr } 6947398Sdfr conn->conn_statsn = ntohl(bhstr->bhstr_statsn); 7047398Sdfr 7147398Sdfr return (response); 7247398Sdfr} 7347398Sdfr 7447398Sdfrstatic struct pdu * 7547398Sdfrtext_new_request(struct connection *conn) 7647398Sdfr{ 7747398Sdfr struct pdu *request; 7847398Sdfr struct iscsi_bhs_text_request *bhstr; 7947398Sdfr 8062987Sjhb request = pdu_new(conn); 8162987Sjhb bhstr = (struct iscsi_bhs_text_request *)request->pdu_bhs; 8269774Sphk bhstr->bhstr_opcode = ISCSI_BHS_OPCODE_TEXT_REQUEST | 8347398Sdfr ISCSI_BHS_OPCODE_IMMEDIATE; 8453094Sdfr bhstr->bhstr_flags = BHSTR_FLAGS_FINAL; 8547398Sdfr bhstr->bhstr_initiator_task_tag = 0; 8647398Sdfr bhstr->bhstr_target_transfer_tag = 0xffffffff; 8747398Sdfr 8847398Sdfr bhstr->bhstr_initiator_task_tag = 0; /* XXX */ 8947398Sdfr bhstr->bhstr_cmdsn = 0; /* XXX */ 9047398Sdfr bhstr->bhstr_expstatsn = htonl(conn->conn_statsn + 1); 9147398Sdfr 9247398Sdfr return (request); 9347398Sdfr} 9447398Sdfr 9588376Stmmstatic struct pdu * 96139273Simplogout_receive(struct connection *conn) 9747398Sdfr{ 9847398Sdfr struct pdu *response; 9947398Sdfr struct iscsi_bhs_logout_response *bhslr; 10047398Sdfr 10147398Sdfr response = pdu_new(conn); 10247398Sdfr pdu_receive(response); 10347398Sdfr if (response->pdu_bhs->bhs_opcode != ISCSI_BHS_OPCODE_LOGOUT_RESPONSE) 10447398Sdfr log_errx(1, "protocol error: received invalid opcode 0x%x", 10550769Sdfr response->pdu_bhs->bhs_opcode); 10647398Sdfr bhslr = (struct iscsi_bhs_logout_response *)response->pdu_bhs; 10747398Sdfr if (ntohs(bhslr->bhslr_response) != BHSLR_RESPONSE_CLOSED_SUCCESSFULLY) 108139273Simp log_warnx("received Logout Response with reason %d", 10947398Sdfr ntohs(bhslr->bhslr_response)); 11047398Sdfr if (ntohl(bhslr->bhslr_statsn) != conn->conn_statsn + 1) { 11147398Sdfr log_errx(1, "received Logout PDU with wrong StatSN: " 11250769Sdfr "is %u, should be %u", ntohl(bhslr->bhslr_statsn), 11350769Sdfr conn->conn_statsn + 1); 11450769Sdfr } 11550769Sdfr conn->conn_statsn = ntohl(bhslr->bhslr_statsn); 11650769Sdfr 117139273Simp return (response); 118139273Simp} 11950769Sdfr 12050769Sdfrstatic struct pdu * 12150769Sdfrlogout_new_request(struct connection *conn) 12250769Sdfr{ 12350769Sdfr struct pdu *request; 12450769Sdfr struct iscsi_bhs_logout_request *bhslr; 12550769Sdfr 12650769Sdfr request = pdu_new(conn); 12752174Sdfr bhslr = (struct iscsi_bhs_logout_request *)request->pdu_bhs; 12850769Sdfr bhslr->bhslr_opcode = ISCSI_BHS_OPCODE_LOGOUT_REQUEST | 12950769Sdfr ISCSI_BHS_OPCODE_IMMEDIATE; 13050769Sdfr bhslr->bhslr_reason = BHSLR_REASON_CLOSE_SESSION; 13150769Sdfr bhslr->bhslr_reason |= 0x80; 13250769Sdfr bhslr->bhslr_initiator_task_tag = 0; /* XXX */ 13350769Sdfr bhslr->bhslr_cmdsn = 0; /* XXX */ 134139273Simp bhslr->bhslr_expstatsn = htonl(conn->conn_statsn + 1); 13583051Syokota 13683051Syokota return (request); 13783051Syokota} 13883051Syokota 13983051Syokotastatic void 14083051Syokotakernel_add(const struct connection *conn, const char *target) 14183051Syokota{ 14283051Syokota struct iscsi_session_add isa; 14383051Syokota int error; 14483051Syokota 14583051Syokota memset(&isa, 0, sizeof(isa)); 14683051Syokota memcpy(&isa.isa_conf, &conn->conn_conf, sizeof(isa.isa_conf)); 14750769Sdfr strlcpy(isa.isa_conf.isc_target, target, 14850769Sdfr sizeof(isa.isa_conf.isc_target)); 14950769Sdfr isa.isa_conf.isc_discovery = 0; 150140647Simp error = ioctl(conn->conn_iscsi_fd, ISCSISADD, &isa); 15150769Sdfr if (error != 0) 15252174Sdfr log_warn("failed to add %s: ISCSISADD", target); 15350769Sdfr} 154139360Simp 155139360Simpstatic void 156139360Simpkernel_remove(const struct connection *conn) 15750769Sdfr{ 15850769Sdfr struct iscsi_session_remove isr; 15950769Sdfr int error; 16050769Sdfr 16150769Sdfr memset(&isr, 0, sizeof(isr)); 16250769Sdfr isr.isr_session_id = conn->conn_session_id; 16350769Sdfr error = ioctl(conn->conn_iscsi_fd, ISCSISREMOVE, &isr); 16450769Sdfr if (error != 0) 16550769Sdfr log_warn("ISCSISREMOVE"); 16650769Sdfr} 16750769Sdfr 16850769Sdfrvoid 16950769Sdfrdiscovery(struct connection *conn) 17050769Sdfr{ 17150769Sdfr struct pdu *request, *response; 17250769Sdfr struct keys *request_keys, *response_keys; 17350769Sdfr int i; 17450769Sdfr 17550769Sdfr log_debugx("beginning discovery session"); 17650769Sdfr request = text_new_request(conn); 17750769Sdfr request_keys = keys_new(); 17850769Sdfr keys_add(request_keys, "SendTargets", "All"); 17950769Sdfr keys_save(request_keys, request); 18050769Sdfr keys_delete(request_keys); 18150769Sdfr request_keys = NULL; 182139273Simp pdu_send(request); 18350769Sdfr pdu_delete(request); 18450769Sdfr request = NULL; 18550769Sdfr 18650769Sdfr log_debugx("waiting for Text Response"); 18750769Sdfr response = text_receive(conn); 18850769Sdfr response_keys = keys_new(); 18950769Sdfr keys_load(response_keys, response); 19050769Sdfr for (i = 0; i < KEYS_MAX; i++) { 191139273Simp if (response_keys->keys_names[i] == NULL) 192139273Simp break; 19350769Sdfr 19450769Sdfr if (strcmp(response_keys->keys_names[i], "TargetName") != 0) 19550769Sdfr continue; 19650769Sdfr 19750769Sdfr log_debugx("adding target %s", response_keys->keys_values[i]); 19850769Sdfr /* 19950769Sdfr * XXX: Validate the target name? 20050769Sdfr */ 20152174Sdfr kernel_add(conn, response_keys->keys_values[i]); 20250769Sdfr } 20350769Sdfr keys_delete(response_keys); 20450769Sdfr pdu_delete(response); 20550769Sdfr 20650769Sdfr log_debugx("removing temporary discovery session"); 20750769Sdfr kernel_remove(conn); 208139273Simp 20983051Syokota log_debugx("discovery done; logging out"); 21083051Syokota request = logout_new_request(conn); 21183051Syokota pdu_send(request); 21283051Syokota pdu_delete(request); 21383051Syokota request = NULL; 21483051Syokota 21583051Syokota log_debugx("waiting for Logout Response"); 21683051Syokota response = logout_receive(conn); 21783051Syokota pdu_delete(response); 21883051Syokota 21983051Syokota log_debugx("discovery session done"); 22083051Syokota} 22150769Sdfr