/* * kgetipnodebyname * * This function builds a request that will be sent to the iscsi_door. * The iSCSI door after receiving the request calls getipnodebyaddr(). * for more information on the input, output parameter and return value, * consult the man page for getipnodebyname(). * * Before calling the iscsi door this function tries to do the conversion * locally. If a name resolution is needed the iscsi door is called. * * There's some limitations to the information returned by this function. * Only one address of the address list returned by getipnodebyname() is * returned. The other parameters of the structure should be ignored. */ struct hostent * kgetipnodebyname( const char *name, int af, int flags, int *error_num ) { door_arg_t arg; mybuffer_t *buffer; size_t msg_size = ISCSI_DOOR_MAX_DATA_SIZE; size_t hostent_size = ISCSI_DOOR_MAX_DATA_SIZE; size_t buffer_size; getipnodebyname_req_t *req; getipnodebyname_cnf_t *cnf; struct hostent *hptr; buffer_size = msg_size + hostent_size + sizeof (mybuffer_t); buffer = (mybuffer_t *)kmem_zalloc(buffer_size, KM_SLEEP); if (buffer) { /* * The buffer was successfully allocated. * * Buffer * * +--------------------+ <--- buffer * | mybuffer_t | * +--------------------+ <--- hptr * | | * | | * | hostent_size | * | | * | | * | | * +--------------------+ <--- req, cnf * | | * | | * | | * | msg_size | * | | * | | * | | * +--------------------+ */ buffer->signature = ISCSI_DOOR_REQ_SIGNATURE; buffer->size = buffer_size; hptr = (struct hostent *)((char *)buffer + sizeof (mybuffer_t)); req = (getipnodebyname_req_t *)((char *)hptr + hostent_size); cnf = (getipnodebyname_cnf_t *)((char *)hptr + hostent_size); hostent_size -= sizeof (struct hostent); /* * We try first locally. If the conversion cannot be done * by inet_pton the door is called. * The cnf address is used as output buffer. * inet_pton returns '1' if the conversion was successful. */ switch (af) { case AF_INET: hptr->h_length = sizeof (struct in_addr); break; case AF_INET6: hptr->h_length = sizeof (struct in6_addr); break; default: kfreehostent(hptr); *error_num = NO_RECOVERY; return (NULL); } if ((msg_size < hptr->h_length) || (hostent_size < sizeof (char *))) { kfreehostent(hptr); *error_num = NO_RECOVERY; return (NULL); } if (inet_pton(af, (char *)name, cnf) == 1) { /* * inet_pton converted the string successfully. */ hptr->h_addrtype = af; hptr->h_addr_list = (char **)((char *)hptr + sizeof (struct hostent)); *hptr->h_addr_list = (char *)cnf; return (hptr); } /* * The name couldn't ne converted by inet_pton. The door is * called. */ /* Header initialization. */ req->hdr.signature = ISCSI_DOOR_REQ_SIGNATURE; req->hdr.version = ISCSI_DOOR_REQ_VERSION_1; req->hdr.opcode = ISCSI_DOOR_GETIPNODEBYNAME_REQ; /* Body initialization. */ req->name_length = strlen(name); if (req->name_length > (msg_size - sizeof (getipnodebyname_req_t) - 1)) { kfreehostent(hptr); *error_num = NO_RECOVERY; return (NULL); } req->name_offset = sizeof (getipnodebyname_req_t); req->af = af; req->flags = flags; bcopy( name, ((char *)req + req->name_offset), req->name_length); /* Door argument initialization. */ arg.data_ptr = (char *)req; arg.data_size = msg_size; arg.desc_num = 0; arg.desc_ptr = NULL; arg.rbuf = (char *)cnf; arg.rsize = msg_size; if (iscsi_door_upcall(&arg) == B_FALSE) { /* The door call failed */ kfreehostent(hptr); *error_num = NO_RECOVERY; return (NULL); } /* * The door call itself was successful. The value returned * in arg.rbuf should be cnf, but we never know. */ cnf = (getipnodebyname_cnf_t *)arg.rbuf; if ((cnf == NULL) || (arg.rsize < sizeof (getipnodebyname_cnf_t)) || (cnf->hdr.signature != ISCSI_DOOR_REQ_SIGNATURE) || (cnf->hdr.version != ISCSI_DOOR_REQ_VERSION_1) || (cnf->hdr.opcode != ISCSI_DOOR_GETIPNODEBYNAME_CNF) || ((cnf->hdr.status != ISCSI_DOOR_STATUS_SUCCESS) && (cnf->hdr.status != ISCSI_DOOR_STATUS_MORE))) { /* The door didn't like the request */ kfreehostent(hptr); *error_num = NO_RECOVERY; return (NULL); } if (cnf->h_addr_list_length == 0) { kfreehostent(hptr); *error_num = HOST_NOT_FOUND; return (NULL); } hptr->h_addrtype = cnf->h_addrtype; hptr->h_length = cnf->h_addrlen; hptr->h_addr_list = (char **)((char *)hptr + sizeof (struct hostent)); *hptr->h_addr_list = ((char *)cnf + cnf->h_addr_list_offset); return (hptr); } else { *error_num = NO_RECOVERY; return (NULL); } }
/* * iscsi_create_sendtgts_list - Based upon the given data, build a * linked list of SendTarget information. The data passed into this * function is expected to be the data portion(s) of SendTarget text * response. */ static iscsi_status_t iscsi_create_sendtgts_list(iscsi_conn_t *icp, char *data, int data_len, iscsi_sendtgts_list_t *stl) { char *line = NULL; boolean_t targetname_added = B_FALSE; iscsi_sendtgts_entry_t *curr_ste = NULL, *prev_ste = NULL; struct hostent *hptr; int error_num; /* initialize number of targets found */ stl->stl_out_cnt = 0; if (data_len == 0) return (ISCSI_STATUS_SUCCESS); while ((line = iscsi_get_next_text(data, data_len, line)) != NULL) { if (strncmp(TARGETNAME, line, strlen(TARGETNAME)) == 0) { /* check if this is first targetname */ if (prev_ste != NULL) { stl->stl_out_cnt++; } if (stl->stl_out_cnt >= stl->stl_in_cnt) { /* * continue processing the data so that * the total number of targets are known * and the caller can retry with the correct * number of entries in the list */ continue; } curr_ste = &(stl->stl_list[stl->stl_out_cnt]); /* * This entry will use the IP address and port * that was passed into this routine. If the next * line that we receive is a TargetAddress we will * know to modify this entry with the new IP address, * port and portal group tag. If this state flag * is not set we'll just create a new entry using * only the previous entries targetname. */ (void) strncpy((char *)curr_ste->ste_name, line + strlen(TARGETNAME), sizeof (curr_ste->ste_name)); if (icp->conn_base_addr.sin.sa_family == AF_INET) { struct sockaddr_in *addr_in = &icp->conn_base_addr.sin4; curr_ste->ste_ipaddr.a_addr.i_insize = sizeof (struct in_addr); bcopy(&addr_in->sin_addr.s_addr, &curr_ste->ste_ipaddr.a_addr.i_addr, sizeof (struct in_addr)); curr_ste->ste_ipaddr.a_port = htons(addr_in->sin_port); } else { struct sockaddr_in6 *addr_in6 = &icp->conn_base_addr.sin6; curr_ste->ste_ipaddr.a_addr.i_insize = sizeof (struct in6_addr); bcopy(&addr_in6->sin6_addr.s6_addr, &curr_ste->ste_ipaddr.a_addr.i_addr, sizeof (struct in6_addr)); curr_ste->ste_ipaddr.a_port = htons(addr_in6->sin6_port); } curr_ste->ste_tpgt = -1; targetname_added = B_TRUE; } else if (strncmp(TARGETADDRESS, line, strlen(TARGETADDRESS)) == 0) { char *in_str, *tmp_buf, *addr_str, *port_str, *tpgt_str; int type, tmp_buf_len; long result; /* * If TARGETADDRESS is first line a SendTarget response * (i.e. no TARGETNAME lines preceding), treat as * an error. To check this an assumption is made that * at least one sendtarget_entry_t should exist prior * to entering this code. */ if (prev_ste == NULL) { cmn_err(CE_NOTE, "SendTargets protocol error: " "TARGETADDRESS first"); return (ISCSI_STATUS_PROTOCOL_ERROR); } /* * If we can't find an '=' then the sendtargets * response if invalid per spec. Return empty list. */ in_str = strchr(line, '='); if (in_str == NULL) { return (ISCSI_STATUS_PROTOCOL_ERROR); } /* move past the '=' */ in_str++; /* Copy addr, port, and tpgt into temporary buffer */ tmp_buf_len = strlen(in_str) + 1; tmp_buf = kmem_zalloc(tmp_buf_len, KM_SLEEP); (void) strncpy(tmp_buf, in_str, tmp_buf_len); /* * Parse the addr, port, and tpgt from * sendtarget response */ if (parse_addr_port_tpgt(tmp_buf, &addr_str, &type, &port_str, &tpgt_str) == B_FALSE) { /* Unable to extract addr */ kmem_free(tmp_buf, tmp_buf_len); return (ISCSI_STATUS_PROTOCOL_ERROR); } /* Now convert string addr to binary */ hptr = kgetipnodebyname(addr_str, type, AI_ALL, &error_num); if (!hptr) { /* Unable to get valid address */ kmem_free(tmp_buf, tmp_buf_len); return (ISCSI_STATUS_PROTOCOL_ERROR); } /* Check if space for response */ if (targetname_added == B_FALSE) { stl->stl_out_cnt++; if (stl->stl_out_cnt >= stl->stl_in_cnt) { /* * continue processing the data so that * the total number of targets are * known and the caller can retry with * the correct number of entries in * the list */ kfreehostent(hptr); kmem_free(tmp_buf, tmp_buf_len); continue; } curr_ste = &(stl->stl_list[stl->stl_out_cnt]); (void) strcpy((char *)curr_ste->ste_name, (char *)prev_ste->ste_name); } curr_ste->ste_ipaddr.a_addr.i_insize = hptr->h_length; bcopy(*hptr->h_addr_list, &(curr_ste->ste_ipaddr.a_addr.i_addr), curr_ste->ste_ipaddr.a_addr.i_insize); kfreehostent(hptr); if (port_str != NULL) { (void) ddi_strtol(port_str, NULL, 0, &result); curr_ste->ste_ipaddr.a_port = (short)result; } else { curr_ste->ste_ipaddr.a_port = ISCSI_LISTEN_PORT; } if (tpgt_str != NULL) { (void) ddi_strtol(tpgt_str, NULL, 0, &result); curr_ste->ste_tpgt = (short)result; } else { cmn_err(CE_NOTE, "SendTargets protocol error: " "TPGT not specified"); kmem_free(tmp_buf, tmp_buf_len); return (ISCSI_STATUS_PROTOCOL_ERROR); } kmem_free(tmp_buf, tmp_buf_len); targetname_added = B_FALSE; } else if (strlen(line) != 0) { /* * Any other string besides an empty string * is a protocol error */ cmn_err(CE_NOTE, "SendTargets protocol error: " "unexpected response"); return (ISCSI_STATUS_PROTOCOL_ERROR); } prev_ste = curr_ste; } /* * If target found increment out count one more time because * this is the total number of entries in the list not an index * like it was used above */ if (prev_ste != NULL) { stl->stl_out_cnt++; } return (ISCSI_STATUS_SUCCESS); }