iscsit_text.c (7978:4559e57ec313) | iscsit_text.c (9601:e0ed15140e6d) |
---|---|
1/* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE --- 5 unchanged lines hidden (view full) --- 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21/* | 1/* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE --- 5 unchanged lines hidden (view full) --- 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21/* |
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. | 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. |
23 * Use is subject to license terms. 24 */ 25 26#include <sys/cpuvar.h> 27#include <sys/types.h> 28#include <sys/conf.h> 29#include <sys/file.h> 30#include <sys/ddi.h> --- 13 unchanged lines hidden (view full) --- 44#include <sys/idm/idm_text.h> 45#include <sys/idm/idm_so.h> 46#include <iscsit_isns.h> 47#include <iscsit.h> 48 49#define IPADDRSTRLEN INET6_ADDRSTRLEN /* space for ipaddr string */ 50#define PORTALSTRLEN (IPADDRSTRLEN+16) /* add space for :port,tag */ 51 | 23 * Use is subject to license terms. 24 */ 25 26#include <sys/cpuvar.h> 27#include <sys/types.h> 28#include <sys/conf.h> 29#include <sys/file.h> 30#include <sys/ddi.h> --- 13 unchanged lines hidden (view full) --- 44#include <sys/idm/idm_text.h> 45#include <sys/idm/idm_so.h> 46#include <iscsit_isns.h> 47#include <iscsit.h> 48 49#define IPADDRSTRLEN INET6_ADDRSTRLEN /* space for ipaddr string */ 50#define PORTALSTRLEN (IPADDRSTRLEN+16) /* add space for :port,tag */ 51 |
52void 53iscsit_text_cmd_fini(iscsit_conn_t *ict); 54 |
|
52/* 53 * The kernel inet_ntop() function formats ipv4 address fields with 54 * leading zeros which the win2k initiator interprets as octal. 55 */ 56 57static void iscsit_v4_ntop(struct in_addr *in, char a[], int size) 58{ 59 unsigned char *p = (unsigned char *) in; 60 61 (void) snprintf(a, size, "%d.%d.%d.%d", *p, *(p+1), *(p+2), *(p+3)); 62} 63 64static void | 55/* 56 * The kernel inet_ntop() function formats ipv4 address fields with 57 * leading zeros which the win2k initiator interprets as octal. 58 */ 59 60static void iscsit_v4_ntop(struct in_addr *in, char a[], int size) 61{ 62 unsigned char *p = (unsigned char *) in; 63 64 (void) snprintf(a, size, "%d.%d.%d.%d", *p, *(p+1), *(p+2), *(p+3)); 65} 66 67static void |
65iscsit_send_reject(idm_pdu_t *req_pdu, uint8_t reason_code) | 68iscsit_bump_ttt(iscsit_conn_t *ict) |
66{ | 69{ |
67 idm_pdu_t *reject_pdu; 68 iscsi_reject_rsp_hdr_t *rej_hdr; | 70 /* 71 * Set the target task tag. The value will be zero when 72 * the connection is created. Increment it and wrap it 73 * back to one if we hit the reserved value. 74 * 75 * The TTT is fabricated since there is no real task associated 76 * with a text request. The idm task range is reused here since 77 * no real tasks can be started from a discovery session and 78 * thus no conflicts are possible. 79 */ 80 if (++ict->ict_text_rsp_ttt == IDM_TASKIDS_MAX) 81 ict->ict_text_rsp_ttt = 1; 82} |
69 | 83 |
70 reject_pdu = idm_pdu_alloc(sizeof (iscsi_hdr_t), req_pdu->isp_hdrlen); 71 if (reject_pdu == NULL) { 72 /* Just give up.. the initiator will timeout */ 73 idm_pdu_complete(req_pdu, IDM_STATUS_SUCCESS); 74 return; | 84static void 85iscsit_text_resp_complete_cb(idm_pdu_t *pdu, idm_status_t status) 86{ 87 iscsit_conn_t *ict = pdu->isp_private; 88 89 idm_pdu_free(pdu); 90 if (status != IDM_STATUS_SUCCESS) { 91 /* 92 * Could not send the last text response. 93 * Clear any state and bump the TTT so subsequent 94 * requests will not match. 95 */ 96 iscsit_text_cmd_fini(ict); 97 iscsit_bump_ttt(ict); |
75 } | 98 } |
99 iscsit_conn_rele(ict); 100} |
|
76 | 101 |
77 /* Payload contains the header from the bad PDU */ 78 idm_pdu_init(reject_pdu, req_pdu->isp_ic, NULL, NULL); 79 bcopy(req_pdu->isp_hdr, reject_pdu->isp_data, req_pdu->isp_hdrlen); | 102static void 103iscsit_text_reject(idm_pdu_t *req_pdu, uint8_t reason_code) 104{ 105 iscsit_conn_t *ict = req_pdu->isp_ic->ic_handle; |
80 | 106 |
81 rej_hdr = (iscsi_reject_rsp_hdr_t *)reject_pdu->isp_hdr; 82 bzero(rej_hdr, sizeof (*rej_hdr)); 83 rej_hdr->opcode = ISCSI_OP_REJECT_MSG; 84 rej_hdr->flags = ISCSI_FLAG_FINAL; 85 rej_hdr->reason = reason_code; 86 hton24(rej_hdr->dlength, req_pdu->isp_hdrlen); 87 rej_hdr->must_be_ff[0] = 0xff; 88 rej_hdr->must_be_ff[1] = 0xff; 89 rej_hdr->must_be_ff[2] = 0xff; 90 rej_hdr->must_be_ff[3] = 0xff; 91 92 iscsit_pdu_tx(reject_pdu); | 107 /* 108 * A reject means abandoning this text request. 109 * Cleanup any state from the request and increment the TTT 110 * in case the initiator does not get the reject response 111 * and attempts to resume this request. 112 */ 113 iscsit_text_cmd_fini(ict); 114 iscsit_bump_ttt(ict); 115 iscsit_send_reject(ict, req_pdu, reason_code); |
93 idm_pdu_complete(req_pdu, IDM_STATUS_SUCCESS); | 116 idm_pdu_complete(req_pdu, IDM_STATUS_SUCCESS); |
117 |
|
94} 95 | 118} 119 |
120 121/* 122 * Add individual <TargetAddress=ipaddr> tuple to the nvlist 123 */ |
|
96static void | 124static void |
97iscsit_add_target_portals(nvlist_t *nv_resp, iscsit_tgt_t *target) | 125iscsit_add_portal(struct sockaddr_storage *ss, int flip_v6, int tag, 126 nvlist_t *nv_resp) |
98{ | 127{ |
99 iscsit_tpgt_t *tpg_list; 100 iscsit_tpg_t *tpg; 101 idm_addr_list_t *ipaddr_p; 102 idm_addr_t *tip; 103 iscsit_portal_t *portal; 104 int ipsize, i; 105 char *name = "TargetAddress"; 106 char a[IPADDRSTRLEN]; 107 char v[PORTALSTRLEN]; 108 struct sockaddr_storage *ss; | 128 char ipaddr[IPADDRSTRLEN]; /* ip address string */ 129 char ta_value[PORTALSTRLEN]; /* target address value */ |
109 struct sockaddr_in *sin; | 130 struct sockaddr_in *sin; |
110 struct sockaddr_in6 *sin6; | |
111 struct in_addr *in; | 131 struct in_addr *in; |
112 struct in6_addr *in6; 113 int type; | 132 struct sockaddr_in6 *sin6; 133 struct in6_addr *in6, flip_in6; |
114 | 134 |
135 switch (ss->ss_family) { 136 case AF_INET: 137 sin = (struct sockaddr_in *)ss; 138 in = &sin->sin_addr; 139 iscsit_v4_ntop(in, ipaddr, sizeof (ipaddr)); 140 (void) snprintf(ta_value, sizeof (ta_value), "%s:%d,%d", 141 ipaddr, ntohs(sin->sin_port), tag); 142 break; 143 case AF_INET6: 144 sin6 = (struct sockaddr_in6 *)ss; 145 in6 = &sin6->sin6_addr; 146 if (flip_v6) { 147 uint16_t *v6_field_i = (uint16_t *)in6; 148 uint16_t *v6_field_o = (uint16_t *)&flip_in6; 149 int i; |
|
115 | 150 |
116 /* 117 * Look through the portal groups associated with this target. 118 */ 119 mutex_enter(&target->target_mutex); 120 tpg_list = avl_first(&target->target_tpgt_list); 121 while (tpg_list != NULL) { 122 tpg = tpg_list->tpgt_tpg; 123 /* 124 * The default portal group will match any current interface. 125 * A target cannot listen on other portal groups if it 126 * listens on the default portal group. 127 */ 128 if (tpg == iscsit_global.global_default_tpg) { | |
129 /* | 151 /* |
130 * get the list of plumbed interfaces | 152 * Ugh. The iSCSI config data is stored in host 153 * order while the addresses retrieved from the 154 * stack come back in network order. inet_ntop 155 * expects network order. |
131 */ | 156 */ |
132 ipsize = idm_get_ipaddr(&ipaddr_p); 133 if (ipsize == 0) { 134 mutex_exit(&target->target_mutex); 135 return; | 157 for (i = 0; i < 8; i++) 158 *v6_field_o++ = htons(*v6_field_i++); 159 in6 = &flip_in6; 160 } 161 (void) inet_ntop(AF_INET6, in6, ipaddr, sizeof (ipaddr)); 162 (void) snprintf(ta_value, sizeof (ta_value), "[%s]:%d,%d", 163 ipaddr, ntohs(sin6->sin6_port), tag); 164 break; 165 default: 166 ASSERT(0); 167 return; 168 } 169 (void) nvlist_add_string(nv_resp, "TargetAddress", ta_value); 170} 171 172/* 173 * Process the special case of the default portal group. 174 * Network addresses are obtained from the network stack and 175 * require some reformatting. 176 */ 177static void 178iscsit_add_default_portals(iscsit_conn_t *ict, idm_addr_list_t *ipaddr_p, 179 nvlist_t *nv_resp) 180{ 181 int pass, i; 182 idm_addr_t *tip; 183 struct sockaddr_storage ss; 184 struct sockaddr_in *sin; 185 struct sockaddr_in6 *sin6; 186 187 /* 188 * If this request was received on one of the portals, 189 * output that portal first. Most initiators will try to 190 * connect on the first portal in the SendTargets response. 191 * For example, this will avoid the confusing situation of a 192 * discovery coming in on an IB interface and the initiator 193 * then doing the normal login on an ethernet interface. 194 */ 195 sin = (struct sockaddr_in *)&ss; 196 sin6 = (struct sockaddr_in6 *)&ss; 197 for (pass = 1; pass <= 2; pass++) { 198 tip = &ipaddr_p->al_addrs[0]; 199 for (i = 0; i < ipaddr_p->al_out_cnt; i++, tip++) { 200 /* Convert the address into sockaddr_storage format */ 201 switch (tip->a_addr.i_insize) { 202 case sizeof (struct in_addr): 203 sin->sin_family = AF_INET; 204 sin->sin_port = htons(ISCSI_LISTEN_PORT); 205 sin->sin_addr = tip->a_addr.i_addr.in4; 206 break; 207 case sizeof (struct in6_addr): 208 sin6->sin6_family = AF_INET6; 209 sin6->sin6_port = htons(ISCSI_LISTEN_PORT); 210 sin6->sin6_addr = tip->a_addr.i_addr.in6; 211 break; 212 default: 213 ASSERT(0); 214 continue; |
136 } | 215 } |
137 tip = &ipaddr_p->al_addrs[0]; 138 for (i = 0; i < ipaddr_p->al_out_cnt; i++, tip++) { 139 if (tip->a_addr.i_insize == 140 sizeof (struct in_addr)) { 141 type = AF_INET; 142 in = &tip->a_addr.i_addr.in4; 143 iscsit_v4_ntop(in, a, sizeof (a)); 144 (void) snprintf(v, sizeof (v), 145 "%s,1", a); 146 } else if (tip->a_addr.i_insize == 147 sizeof (struct in6_addr)) { 148 type = AF_INET6; 149 in6 = &tip->a_addr.i_addr.in6; 150 (void) inet_ntop(type, in6, a, 151 sizeof (a)); 152 (void) snprintf(v, sizeof (v), 153 "[%s],1", a); 154 } else { 155 break; 156 } | 216 switch (pass) { 217 case 1: |
157 /* | 218 /* |
158 * Add the TargetAddress=<addr> nvpair | 219 * On the first pass, skip portals that 220 * do not match the incoming connection. |
159 */ | 221 */ |
160 (void) nvlist_add_string(nv_resp, name, v); | 222 if (idm_ss_compare(&ss, &ict->ict_ic->ic_laddr, 223 B_TRUE) != 0) 224 continue; 225 break; 226 case 2: 227 /* 228 * On the second pass, process the 229 * remaining portals. 230 */ 231 if (idm_ss_compare(&ss, &ict->ict_ic->ic_laddr, 232 B_TRUE) == 0) 233 continue; 234 break; |
161 } | 235 } |
162 kmem_free(ipaddr_p, ipsize); | |
163 /* | 236 /* |
164 * Cannot listen on other portal groups. | 237 * Add portal to the response list. 238 * Do not byte swap v6 address. 239 * By convention, the default portal group tag == 1 |
165 */ | 240 */ |
166 mutex_exit(&target->target_mutex); 167 return; | 241 iscsit_add_portal(&ss, 0, 1, nv_resp); |
168 } | 242 } |
169 /* 170 * Found a defined portal group - add each portal address. 171 */ 172 portal = avl_first(&tpg->tpg_portal_list); 173 while (portal != NULL) { | 243 } 244} 245 246/* 247 * Process a portal group from the configuration database. 248 */ 249static void 250iscsit_add_portals(iscsit_conn_t *ict, iscsit_tpgt_t *tpg_list, 251 nvlist_t *nv_resp) 252{ 253 int pass; 254 iscsit_portal_t *portal, *next_portal; 255 iscsit_tpg_t *tpg; 256 struct sockaddr_storage *ss; 257 258 /* 259 * As with the default portal group, output the portal used by 260 * the incoming request first. 261 */ 262 tpg = tpg_list->tpgt_tpg; 263 for (pass = 1; pass <= 2; pass++) { 264 for (portal = avl_first(&tpg->tpg_portal_list); 265 portal != NULL; 266 portal = next_portal) { 267 268 next_portal = AVL_NEXT(&tpg->tpg_portal_list, portal); |
174 ss = &portal->portal_addr; | 269 ss = &portal->portal_addr; |
175 type = ss->ss_family; 176 switch (type) { 177 case AF_INET: 178 sin = (struct sockaddr_in *)ss; 179 in = &sin->sin_addr; 180 iscsit_v4_ntop(in, a, sizeof (a)); 181 (void) snprintf(v, sizeof (v), "%s:%d,%d", a, 182 ntohs(sin->sin_port), 183 tpg_list->tpgt_tag); 184 (void) nvlist_add_string(nv_resp, name, v); | 270 switch (pass) { 271 case 1: 272 /* 273 * On the first pass, skip portals that 274 * do not match the incoming connection. 275 */ 276 if (idm_ss_compare(ss, 277 &ict->ict_ic->ic_laddr, B_TRUE) != 0) 278 continue; |
185 break; | 279 break; |
186 case AF_INET6: 187 sin6 = (struct sockaddr_in6 *)ss; 188 in6 = &sin6->sin6_addr; 189 (void) inet_ntop(type, in6, a, sizeof (a)); 190 (void) snprintf(v, sizeof (v), "[%s]:%d,%d", a, 191 sin6->sin6_port, 192 tpg_list->tpgt_tag); 193 (void) nvlist_add_string(nv_resp, name, v); | 280 case 2: 281 /* 282 * On the second pass, process the 283 * remaining portals. 284 */ 285 if (idm_ss_compare(ss, 286 &ict->ict_ic->ic_laddr, B_TRUE) == 0) 287 continue; |
194 break; | 288 break; |
195 default: 196 break; | |
197 } | 289 } |
198 portal = AVL_NEXT(&tpg->tpg_portal_list, portal); | 290 /* 291 * Add portal to the response list. 292 * Need to byte swap v6 address. 293 */ 294 iscsit_add_portal(ss, 1, tpg_list->tpgt_tag, nv_resp); |
199 } | 295 } |
296 } 297} 298 299/* 300 * Process all the portal groups bound to a particular target. 301 */ 302static void 303iscsit_add_tpgs(iscsit_conn_t *ict, iscsit_tgt_t *target, nvlist_t *nv_resp) 304{ 305 iscsit_tpgt_t *tpg_list; 306 idm_addr_list_t *ipaddr_p; 307 int ipsize; 308 309 310 /* 311 * Look through the portal groups associated with this target. 312 */ 313 mutex_enter(&target->target_mutex); 314 tpg_list = avl_first(&target->target_tpgt_list); 315 316 /* check for the default portal group */ 317 if (tpg_list->tpgt_tpg == iscsit_global.global_default_tpg) { 318 /* 319 * The default portal group is a special case and will 320 * return all reasonable interfaces on this node. 321 * 322 * A target cannot be bound to other portal groups 323 * if it is bound to the default portal group. 324 */ 325 ASSERT(AVL_NEXT(&target->target_tpgt_list, tpg_list) == NULL); 326 327 /* 328 * get the list of local interface addresses 329 */ 330 ipsize = idm_get_ipaddr(&ipaddr_p); 331 if (ipsize > 0) { 332 /* convert the ip address list to nvlist format */ 333 iscsit_add_default_portals(ict, ipaddr_p, nv_resp); 334 kmem_free(ipaddr_p, ipsize); 335 } 336 mutex_exit(&target->target_mutex); 337 return; 338 } 339 340 /* 341 * Not the default portal group - process the user defined tpgs 342 */ 343 ASSERT(tpg_list != NULL); 344 while (tpg_list != NULL) { 345 346 ASSERT(tpg_list->tpgt_tpg != iscsit_global.global_default_tpg); 347 348 /* 349 * Found a defined portal group - add each portal address. 350 * As with the default portal group, make 2 passes over 351 * the addresses in order to output the connection 352 * address first. 353 */ 354 iscsit_add_portals(ict, tpg_list, nv_resp); 355 |
|
200 tpg_list = AVL_NEXT(&target->target_tpgt_list, tpg_list); 201 } 202 mutex_exit(&target->target_mutex); 203} 204 | 356 tpg_list = AVL_NEXT(&target->target_tpgt_list, tpg_list); 357 } 358 mutex_exit(&target->target_mutex); 359} 360 |
205void 206iscsit_pdu_op_text_cmd(iscsit_conn_t *ict, idm_pdu_t *rx_pdu) | 361#ifdef DEBUG 362/* 363 * To test with smaller PDUs in order to force multi-PDU responses, 364 * set this value such that: 0 < test_max_len < 8192 365 */ 366uint32_t iscsit_text_max_len = 0; 367#endif 368 369/* 370 * Format a text response PDU from the text buffer and send it. 371 */ 372static void 373iscsit_send_next_text_response(iscsit_conn_t *ict, idm_pdu_t *rx_pdu) |
207{ 208 iscsi_text_hdr_t *th_req = (iscsi_text_hdr_t *)rx_pdu->isp_hdr; 209 iscsi_text_rsp_hdr_t *th_resp; | 374{ 375 iscsi_text_hdr_t *th_req = (iscsi_text_hdr_t *)rx_pdu->isp_hdr; 376 iscsi_text_rsp_hdr_t *th_resp; |
377 idm_pdu_t *resp; 378 uint32_t len, remainder, max_len; 379 char *base; 380 int final; 381 382 max_len = ISCSI_DEFAULT_MAX_RECV_SEG_LEN; 383#ifdef DEBUG 384 if (iscsit_text_max_len > 0 && iscsit_text_max_len < 8192) 385 max_len = iscsit_text_max_len; 386#endif 387 remainder = ict->ict_text_rsp_valid_len - ict->ict_text_rsp_off; 388 if (remainder <= max_len) { 389 len = remainder; 390 final = 1; 391 } else { 392 len = max_len; 393 final = 0; 394 } 395 /* 396 * Allocate a PDU and copy in text response buffer 397 */ 398 resp = idm_pdu_alloc(sizeof (iscsi_hdr_t), len); 399 idm_pdu_init(resp, ict->ict_ic, ict, iscsit_text_resp_complete_cb); 400 base = ict->ict_text_rsp_buf + ict->ict_text_rsp_off; 401 bcopy(base, resp->isp_data, len); 402 /* 403 * Fill in the response header 404 */ 405 th_resp = (iscsi_text_rsp_hdr_t *)resp->isp_hdr; 406 bzero(th_resp, sizeof (*th_resp)); 407 th_resp->opcode = ISCSI_OP_TEXT_RSP; 408 th_resp->itt = th_req->itt; 409 hton24(th_resp->dlength, len); 410 if (final) { 411 th_resp->flags = ISCSI_FLAG_FINAL; 412 th_resp->ttt = ISCSI_RSVD_TASK_TAG; 413 kmem_free(ict->ict_text_rsp_buf, ict->ict_text_rsp_len); 414 ict->ict_text_rsp_buf = NULL; 415 ict->ict_text_rsp_len = 0; 416 ict->ict_text_rsp_valid_len = 0; 417 ict->ict_text_rsp_off = 0; 418 } else { 419 th_resp->flags = ISCSI_FLAG_TEXT_CONTINUE; 420 th_resp->ttt = ict->ict_text_rsp_ttt; 421 ict->ict_text_rsp_off += len; 422 } 423 /* Send the response on its way */ 424 iscsit_conn_hold(ict); 425 iscsit_pdu_tx(resp); 426 /* Free the request pdu */ 427 idm_pdu_complete(rx_pdu, IDM_STATUS_SUCCESS); 428} 429 430/* 431 * Clean-up the text buffer if it exists. 432 */ 433void 434iscsit_text_cmd_fini(iscsit_conn_t *ict) 435{ 436 if (ict->ict_text_rsp_buf != NULL) { 437 ASSERT(ict->ict_text_rsp_len != 0); 438 kmem_free(ict->ict_text_rsp_buf, ict->ict_text_rsp_len); 439 } 440 ict->ict_text_rsp_buf = NULL; 441 ict->ict_text_rsp_len = 0; 442 ict->ict_text_rsp_valid_len = 0; 443 ict->ict_text_rsp_off = 0; 444} 445 446/* 447 * Process an iSCSI text command. 448 * 449 * This code only handles the common case of a text command 450 * containing the single tuple SendTargets=All issued during 451 * a discovery session. The request will always arrive in a 452 * single PDU, but the response may span multiple PDUs if the 453 * configuration is large. I.e. many targets and portals. 454 * 455 * The request is checked for correctness and then the response 456 * is generated from the global target into nvlist format. Then 457 * the nvlist is reformatted into idm textbuf format which reflects 458 * the iSCSI defined <name=value> specification. Finally, the 459 * textbuf is sent to the initiator in one or more text response PDUs 460 */ 461void 462iscsit_pdu_op_text_cmd(iscsit_conn_t *ict, idm_pdu_t *rx_pdu) 463{ 464 iscsi_text_hdr_t *th_req = (iscsi_text_hdr_t *)rx_pdu->isp_hdr; |
|
210 nvlist_t *nv_resp; | 465 nvlist_t *nv_resp; |
211 char *textbuf; 212 char *kv_name, *kv_pair; | 466 char *kv_pair; |
213 int flags; | 467 int flags; |
468 char *textbuf; |
|
214 int textbuflen; | 469 int textbuflen; |
470 int validlen; 471 iscsit_tgt_t *target, *next_target; |
|
215 int rc; | 472 int rc; |
216 idm_pdu_t *resp; | |
217 218 flags = th_req->flags; 219 if ((flags & ISCSI_FLAG_FINAL) != ISCSI_FLAG_FINAL) { | 473 474 flags = th_req->flags; 475 if ((flags & ISCSI_FLAG_FINAL) != ISCSI_FLAG_FINAL) { |
220 /* Cannot handle multi-PDU messages now */ 221 iscsit_send_reject(rx_pdu, ISCSI_REJECT_CMD_NOT_SUPPORTED); | 476 /* Cannot handle multi-PDU requests now */ 477 iscsit_text_reject(rx_pdu, ISCSI_REJECT_CMD_NOT_SUPPORTED); |
222 return; 223 } 224 if (th_req->ttt != ISCSI_RSVD_TASK_TAG) { | 478 return; 479 } 480 if (th_req->ttt != ISCSI_RSVD_TASK_TAG) { |
225 /* Last of a multi-PDU message */ 226 iscsit_send_reject(rx_pdu, ISCSI_REJECT_CMD_NOT_SUPPORTED); | 481 /* 482 * This is the initiator acknowledging our last PDU and 483 * indicating it is ready for the next PDU in the sequence. 484 */ 485 /* 486 * There can only be one outstanding text request on a 487 * connection. Make sure this one PDU has the current TTT. 488 */ 489 /* XXX combine the following 3 checks after testing */ 490 if (th_req->ttt != ict->ict_text_rsp_ttt) { 491 /* Not part of this sequence */ 492 iscsit_text_reject(rx_pdu, 493 ISCSI_REJECT_CMD_NOT_SUPPORTED); 494 return; 495 } 496 /* 497 * ITT should match what was saved from first PDU. 498 */ 499 if (th_req->itt != ict->ict_text_req_itt) { 500 /* Not part of this sequence */ 501 iscsit_text_reject(rx_pdu, 502 ISCSI_REJECT_CMD_NOT_SUPPORTED); 503 return; 504 } 505 /* 506 * Cannot deal with more key/value pairs now. 507 */ 508 if (rx_pdu->isp_datalen != 0) { 509 iscsit_text_reject(rx_pdu, 510 ISCSI_REJECT_CMD_NOT_SUPPORTED); 511 return; 512 } 513 iscsit_send_next_text_response(ict, rx_pdu); |
227 return; 228 } 229 230 /* | 514 return; 515 } 516 517 /* |
231 * At this point we have a single PDU text command | 518 * Initiator has started a new text request. Only 519 * one can be active at a time, so abandon any previous 520 * text request on this connection. |
232 */ | 521 */ |
522 iscsit_text_cmd_fini(ict); |
|
233 | 523 |
524 /* Set the target task tag. */ 525 iscsit_bump_ttt(ict); 526 527 /* Save the initiator task tag */ 528 ict->ict_text_req_itt = th_req->itt; 529 530 /* 531 * Make sure this is a proper SendTargets request 532 */ |
|
234 textbuf = (char *)rx_pdu->isp_data; 235 textbuflen = rx_pdu->isp_datalen; | 533 textbuf = (char *)rx_pdu->isp_data; 534 textbuflen = rx_pdu->isp_datalen; |
236 kv_name = "SendTargets="; | |
237 kv_pair = "SendTargets=All"; | 535 kv_pair = "SendTargets=All"; |
238 if (strncmp(kv_name, textbuf, strlen(kv_name)) != 0) { 239 /* Not a Sendtargets command */ 240 iscsit_send_reject(rx_pdu, ISCSI_REJECT_CMD_NOT_SUPPORTED); 241 return; 242 } 243 if (strcmp(kv_pair, textbuf) == 0 && | 536 if (textbuflen >= strlen(kv_pair) && 537 strcmp(kv_pair, textbuf) == 0 && |
244 ict->ict_op.op_discovery_session == B_TRUE) { | 538 ict->ict_op.op_discovery_session == B_TRUE) { |
245 iscsit_tgt_t *target; 246 int validlen; | |
247 248 /* 249 * Most common case of SendTargets=All during discovery. 250 */ 251 /* 252 * Create an nvlist for response. 253 */ 254 if (nvlist_alloc(&nv_resp, 0, KM_SLEEP) != 0) { | 539 540 /* 541 * Most common case of SendTargets=All during discovery. 542 */ 543 /* 544 * Create an nvlist for response. 545 */ 546 if (nvlist_alloc(&nv_resp, 0, KM_SLEEP) != 0) { |
255 iscsit_send_reject(rx_pdu, | 547 iscsit_text_reject(rx_pdu, |
256 ISCSI_REJECT_CMD_NOT_SUPPORTED); 257 return; 258 } 259 | 548 ISCSI_REJECT_CMD_NOT_SUPPORTED); 549 return; 550 } 551 |
552 /* 553 * Add all the targets to the response list. 554 */ |
|
260 ISCSIT_GLOBAL_LOCK(RW_READER); | 555 ISCSIT_GLOBAL_LOCK(RW_READER); |
261 target = avl_first(&iscsit_global.global_target_list); 262 while (target != NULL) { 263 char *name = "TargetName"; 264 char *val = target->target_name; | 556 for (target = avl_first(&iscsit_global.global_target_list); 557 target != NULL; 558 target = next_target) { 559 char *key, *value; 560 iscsit_tgt_state_t state; |
265 | 561 |
266 (void) nvlist_add_string(nv_resp, name, val); 267 iscsit_add_target_portals(nv_resp, target); 268 target = AVL_NEXT(&iscsit_global.global_target_list, 269 target); | 562 next_target = AVL_NEXT( 563 &iscsit_global.global_target_list, target); 564 565 /* only report online and onlining targets */ 566 state = target->target_state; 567 if (state != TS_ONLINING && state != TS_ONLINE && 568 state != TS_STMF_ONLINE) 569 continue; 570 571 key = "TargetName"; 572 value = target->target_name; 573 if (nvlist_add_string(nv_resp, key, value) == 0) { 574 /* add the portal groups bound to this target */ 575 iscsit_add_tpgs(ict, target, nv_resp); 576 } |
270 } 271 ISCSIT_GLOBAL_UNLOCK(); 272 273 /* | 577 } 578 ISCSIT_GLOBAL_UNLOCK(); 579 580 /* |
274 * Convert the reponse nv list into text buffer. | 581 * Convert the response nvlist into an idm text buffer. |
275 */ 276 textbuf = 0; 277 textbuflen = 0; 278 validlen = 0; 279 rc = idm_nvlist_to_textbuf(nv_resp, &textbuf, 280 &textbuflen, &validlen); 281 nvlist_free(nv_resp); 282 if (rc != 0) { 283 if (textbuf && textbuflen) 284 kmem_free(textbuf, textbuflen); | 582 */ 583 textbuf = 0; 584 textbuflen = 0; 585 validlen = 0; 586 rc = idm_nvlist_to_textbuf(nv_resp, &textbuf, 587 &textbuflen, &validlen); 588 nvlist_free(nv_resp); 589 if (rc != 0) { 590 if (textbuf && textbuflen) 591 kmem_free(textbuf, textbuflen); |
285 iscsit_send_reject(rx_pdu, | 592 iscsit_text_reject(rx_pdu, |
286 ISCSI_REJECT_CMD_NOT_SUPPORTED); 287 return; 288 } | 593 ISCSI_REJECT_CMD_NOT_SUPPORTED); 594 return; 595 } |
289 /* 290 * Allocate a PDU and copy in text response buffer 291 */ 292 resp = idm_pdu_alloc(sizeof (iscsi_hdr_t), validlen); 293 idm_pdu_init(resp, ict->ict_ic, NULL, NULL); 294 bcopy(textbuf, resp->isp_data, validlen); 295 kmem_free(textbuf, textbuflen); 296 /* 297 * Fill in the response header 298 */ 299 th_resp = (iscsi_text_rsp_hdr_t *)resp->isp_hdr; 300 bzero(th_resp, sizeof (*th_resp)); 301 th_resp->opcode = ISCSI_OP_TEXT_RSP; 302 th_resp->flags = ISCSI_FLAG_FINAL; 303 th_resp->ttt = ISCSI_RSVD_TASK_TAG; 304 th_resp->itt = th_req->itt; 305 hton24(th_resp->dlength, validlen); | 596 ict->ict_text_rsp_buf = textbuf; 597 ict->ict_text_rsp_len = textbuflen; 598 ict->ict_text_rsp_valid_len = validlen; 599 ict->ict_text_rsp_off = 0; 600 iscsit_send_next_text_response(ict, rx_pdu); |
306 } else { 307 /* 308 * Other cases to handle 309 * Discovery session: 310 * SendTargets=<target_name> 311 * Normal session | 601 } else { 602 /* 603 * Other cases to handle 604 * Discovery session: 605 * SendTargets=<target_name> 606 * Normal session |
312 * SendTargets=<target_name> - should match session | |
313 * SendTargets=<NULL> - assume target name of session 314 * All others 315 * Error 316 */ | 607 * SendTargets=<NULL> - assume target name of session 608 * All others 609 * Error 610 */ |
317 iscsit_send_reject(rx_pdu, ISCSI_REJECT_CMD_NOT_SUPPORTED); | 611 iscsit_text_reject(rx_pdu, ISCSI_REJECT_CMD_NOT_SUPPORTED); |
318 return; 319 } | 612 return; 613 } |
320 321 /* Send the response on its way */ 322 iscsit_pdu_tx(resp); 323 idm_pdu_complete(rx_pdu, IDM_STATUS_SUCCESS); | |
324} | 614} |