discovery.c revision 276613
178556Sobrien/*- 278556Sobrien * Copyright (c) 2012 The FreeBSD Foundation 378556Sobrien * All rights reserved. 478556Sobrien * 578556Sobrien * This software was developed by Edward Tomasz Napierala under sponsorship 678556Sobrien * from the FreeBSD Foundation. 7167974Sdelphij * 8167974Sdelphij * Redistribution and use in source and binary forms, with or without 9167974Sdelphij * modification, are permitted provided that the following conditions 1078556Sobrien * are met: 11215041Sobrien * 1. Redistributions of source code must retain the above copyright 12215041Sobrien * notice, this list of conditions and the following disclaimer. 1378556Sobrien * 2. Redistributions in binary form must reproduce the above copyright 14167974Sdelphij * notice, this list of conditions and the following disclaimer in the 15167974Sdelphij * documentation and/or other materials provided with the distribution. 1678556Sobrien * 17167974Sdelphij * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18167974Sdelphij * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19167974Sdelphij * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2078556Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2178556Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2278556Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2378556Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2478556Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2578556Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2678556Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2778556Sobrien * SUCH DAMAGE. 2878556Sobrien * 2978556Sobrien */ 3078556Sobrien 3178556Sobrien#include <sys/cdefs.h> 3278556Sobrien__FBSDID("$FreeBSD: stable/10/usr.sbin/iscsid/discovery.c 276613 2015-01-03 13:08:08Z mav $"); 3378556Sobrien 3478556Sobrien#include <sys/types.h> 3578556Sobrien#include <sys/ioctl.h> 3678556Sobrien#include <assert.h> 3778556Sobrien#include <stdbool.h> 3878556Sobrien#include <stdio.h> 3978556Sobrien#include <stdlib.h> 4078556Sobrien#include <string.h> 4178556Sobrien#include <netinet/in.h> 4278556Sobrien 4378556Sobrien#include "iscsid.h" 4478556Sobrien#include "iscsi_proto.h" 4578556Sobrien 4678556Sobrienstatic struct pdu * 4778556Sobrientext_receive(struct connection *conn) 4878556Sobrien{ 4978556Sobrien struct pdu *response; 5078556Sobrien struct iscsi_bhs_text_response *bhstr; 5178556Sobrien 5278556Sobrien response = pdu_new(conn); 5378556Sobrien pdu_receive(response); 5478556Sobrien if (response->pdu_bhs->bhs_opcode != ISCSI_BHS_OPCODE_TEXT_RESPONSE) 5578556Sobrien log_errx(1, "protocol error: received invalid opcode 0x%x", 5678556Sobrien response->pdu_bhs->bhs_opcode); 5778556Sobrien bhstr = (struct iscsi_bhs_text_response *)response->pdu_bhs; 5878556Sobrien#if 0 5978556Sobrien if ((bhstr->bhstr_flags & BHSTR_FLAGS_FINAL) == 0) 6078556Sobrien log_errx(1, "received Text PDU without the \"F\" flag"); 6178556Sobrien#endif 6278556Sobrien /* 6378556Sobrien * XXX: Implement the C flag some day. 6478556Sobrien */ 6578556Sobrien if ((bhstr->bhstr_flags & BHSTR_FLAGS_CONTINUE) != 0) 6678556Sobrien log_errx(1, "received Text PDU with unsupported \"C\" flag"); 6778556Sobrien if (ntohl(bhstr->bhstr_statsn) != conn->conn_statsn + 1) { 6878556Sobrien log_errx(1, "received Text PDU with wrong StatSN: " 6978556Sobrien "is %u, should be %u", ntohl(bhstr->bhstr_statsn), 7078556Sobrien conn->conn_statsn + 1); 7178556Sobrien } 7278556Sobrien conn->conn_statsn = ntohl(bhstr->bhstr_statsn); 7378556Sobrien 7478556Sobrien return (response); 7578556Sobrien} 7678556Sobrien 7778556Sobrienstatic struct pdu * 7878556Sobrientext_new_request(struct connection *conn) 7978556Sobrien{ 8078556Sobrien struct pdu *request; 8178556Sobrien struct iscsi_bhs_text_request *bhstr; 8278556Sobrien 8378556Sobrien request = pdu_new(conn); 8478556Sobrien bhstr = (struct iscsi_bhs_text_request *)request->pdu_bhs; 8578556Sobrien bhstr->bhstr_opcode = ISCSI_BHS_OPCODE_TEXT_REQUEST | 8678556Sobrien ISCSI_BHS_OPCODE_IMMEDIATE; 8778556Sobrien bhstr->bhstr_flags = BHSTR_FLAGS_FINAL; 8878556Sobrien bhstr->bhstr_initiator_task_tag = 0; 8978556Sobrien bhstr->bhstr_target_transfer_tag = 0xffffffff; 9078556Sobrien 9178556Sobrien bhstr->bhstr_initiator_task_tag = 0; /* XXX */ 9278556Sobrien bhstr->bhstr_cmdsn = 0; /* XXX */ 9378556Sobrien bhstr->bhstr_expstatsn = htonl(conn->conn_statsn + 1); 9478556Sobrien 9578556Sobrien return (request); 9678556Sobrien} 9778556Sobrien 9878556Sobrienstatic struct pdu * 9978556Sobrienlogout_receive(struct connection *conn) 10078556Sobrien{ 10178556Sobrien struct pdu *response; 10278556Sobrien struct iscsi_bhs_logout_response *bhslr; 10378556Sobrien 10478556Sobrien response = pdu_new(conn); 10578556Sobrien pdu_receive(response); 10678556Sobrien if (response->pdu_bhs->bhs_opcode != ISCSI_BHS_OPCODE_LOGOUT_RESPONSE) 10778556Sobrien log_errx(1, "protocol error: received invalid opcode 0x%x", 10878556Sobrien response->pdu_bhs->bhs_opcode); 10978556Sobrien bhslr = (struct iscsi_bhs_logout_response *)response->pdu_bhs; 11078556Sobrien if (ntohs(bhslr->bhslr_response) != BHSLR_RESPONSE_CLOSED_SUCCESSFULLY) 11178556Sobrien log_warnx("received Logout Response with reason %d", 11278556Sobrien ntohs(bhslr->bhslr_response)); 11378556Sobrien if (ntohl(bhslr->bhslr_statsn) != conn->conn_statsn + 1) { 11478556Sobrien log_errx(1, "received Logout PDU with wrong StatSN: " 11578556Sobrien "is %u, should be %u", ntohl(bhslr->bhslr_statsn), 11678556Sobrien conn->conn_statsn + 1); 11778556Sobrien } 11878556Sobrien conn->conn_statsn = ntohl(bhslr->bhslr_statsn); 11978556Sobrien 12078556Sobrien return (response); 12178556Sobrien} 12278556Sobrien 12378556Sobrienstatic struct pdu * 12478556Sobrienlogout_new_request(struct connection *conn) 12578556Sobrien{ 12678556Sobrien struct pdu *request; 12778556Sobrien struct iscsi_bhs_logout_request *bhslr; 12878556Sobrien 12978556Sobrien request = pdu_new(conn); 13078556Sobrien bhslr = (struct iscsi_bhs_logout_request *)request->pdu_bhs; 13178556Sobrien bhslr->bhslr_opcode = ISCSI_BHS_OPCODE_LOGOUT_REQUEST | 13278556Sobrien ISCSI_BHS_OPCODE_IMMEDIATE; 13378556Sobrien bhslr->bhslr_reason = BHSLR_REASON_CLOSE_SESSION; 13478556Sobrien bhslr->bhslr_reason |= 0x80; 13578556Sobrien bhslr->bhslr_initiator_task_tag = 0; /* XXX */ 13678556Sobrien bhslr->bhslr_cmdsn = 0; /* XXX */ 13778556Sobrien bhslr->bhslr_expstatsn = htonl(conn->conn_statsn + 1); 13878556Sobrien 13978556Sobrien return (request); 14078556Sobrien} 14178556Sobrien 14278556Sobrienstatic void 14378556Sobrienkernel_add(const struct connection *conn, const char *target) 14478556Sobrien{ 14578556Sobrien struct iscsi_session_add isa; 14678556Sobrien int error; 14778556Sobrien 14878556Sobrien memset(&isa, 0, sizeof(isa)); 14978556Sobrien memcpy(&isa.isa_conf, &conn->conn_conf, sizeof(isa.isa_conf)); 15078556Sobrien strlcpy(isa.isa_conf.isc_target, target, 15178556Sobrien sizeof(isa.isa_conf.isc_target)); 15278556Sobrien isa.isa_conf.isc_discovery = 0; 15378556Sobrien error = ioctl(conn->conn_iscsi_fd, ISCSISADD, &isa); 15478556Sobrien if (error != 0) 15578556Sobrien log_warn("failed to add %s: ISCSISADD", target); 15678556Sobrien} 15778556Sobrien 15878556Sobrienstatic void 15978556Sobrienkernel_remove(const struct connection *conn) 16078556Sobrien{ 16178556Sobrien struct iscsi_session_remove isr; 16278556Sobrien int error; 16378556Sobrien 16478556Sobrien memset(&isr, 0, sizeof(isr)); 16578556Sobrien isr.isr_session_id = conn->conn_session_id; 16678556Sobrien error = ioctl(conn->conn_iscsi_fd, ISCSISREMOVE, &isr); 16778556Sobrien if (error != 0) 16878556Sobrien log_warn("ISCSISREMOVE"); 16978556Sobrien} 17078556Sobrien 17178556Sobrienvoid 17278556Sobriendiscovery(struct connection *conn) 17378556Sobrien{ 17478556Sobrien struct pdu *request, *response; 17578556Sobrien struct keys *request_keys, *response_keys; 17678556Sobrien int i; 17778556Sobrien 17878556Sobrien log_debugx("beginning discovery session"); 17978556Sobrien request = text_new_request(conn); 18078556Sobrien request_keys = keys_new(); 18178556Sobrien keys_add(request_keys, "SendTargets", "All"); 18278556Sobrien keys_save(request_keys, request); 18378556Sobrien keys_delete(request_keys); 18478556Sobrien request_keys = NULL; 18578556Sobrien pdu_send(request); 18678556Sobrien pdu_delete(request); 18778556Sobrien request = NULL; 18878556Sobrien 18978556Sobrien log_debugx("waiting for Text Response"); 19078556Sobrien response = text_receive(conn); 19178556Sobrien response_keys = keys_new(); 19278556Sobrien keys_load(response_keys, response); 19378556Sobrien for (i = 0; i < KEYS_MAX; i++) { 19478556Sobrien if (response_keys->keys_names[i] == NULL) 19578556Sobrien break; 19678556Sobrien 19778556Sobrien if (strcmp(response_keys->keys_names[i], "TargetName") != 0) 19890067Ssobomax continue; 19978556Sobrien 20078556Sobrien log_debugx("adding target %s", response_keys->keys_values[i]); 20190067Ssobomax /* 20278556Sobrien * XXX: Validate the target name? 20378556Sobrien */ 20490067Ssobomax kernel_add(conn, response_keys->keys_values[i]); 20578556Sobrien } 20678556Sobrien keys_delete(response_keys); 20790067Ssobomax pdu_delete(response); 20890067Ssobomax 20990067Ssobomax log_debugx("removing temporary discovery session"); 21078556Sobrien kernel_remove(conn); 21178556Sobrien 21278556Sobrien log_debugx("discovery done; logging out"); 21378556Sobrien request = logout_new_request(conn); 21478556Sobrien pdu_send(request); 21578556Sobrien pdu_delete(request); 21678556Sobrien request = NULL; 21778556Sobrien 21878556Sobrien log_debugx("waiting for Logout Response"); 21978556Sobrien response = logout_receive(conn); 22078556Sobrien pdu_delete(response); 22178556Sobrien 22278556Sobrien log_debugx("discovery session done"); 22378556Sobrien} 22478556Sobrien