Print this page
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/scsi/adapters/iscsi/isns_client.c
+++ new/usr/src/uts/common/io/scsi/adapters/iscsi/isns_client.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 *
25 25 * iSNS Client
26 26 */
27 27
28 28 #include "iscsi.h" /* For ISCSI_MAX_IOVEC */
29 29 #include "isns_protocol.h"
30 30 #include "isns_client.h"
31 31 #include "persistent.h"
32 32
33 33 #ifdef _KERNEL
34 34 #include <sys/sunddi.h>
35 35 #else
36 36 #include <stdlib.h>
37 37 #endif
38 38 #include <netinet/tcp.h>
39 39 #include <sys/types.h>
40 40
41 41 /* For local use */
42 42 #define ISNS_MAX_IOVEC 5
43 43 #define MAX_XID (2^16)
44 44 #define MAX_RCV_RSP_COUNT 10 /* Maximum number of unmatched xid */
45 45 #define ISNS_RCV_TIMEOUT 5
46 46 #define ISNS_RCV_RETRY_MAX 2
47 47 #define IPV4_RSVD_BYTES 10
48 48
49 49 typedef struct isns_reg_arg {
50 50 iscsi_addr_t *isns_server_addr;
51 51 uint8_t *node_name;
52 52 size_t node_name_len;
53 53 uint8_t *node_alias;
54 54 size_t node_alias_len;
55 55 uint32_t node_type;
56 56 uint8_t *lhba_handle;
57 57 } isns_reg_arg_t;
58 58
59 59 typedef struct isns_async_thread_arg {
60 60 uint8_t *lhba_handle;
61 61 void *listening_so;
62 62 } isns_async_thread_arg_t;
63 63
64 64 /* One global queue to serve all LHBA instances. */
65 65 static ddi_taskq_t *reg_query_taskq;
66 66 static kmutex_t reg_query_taskq_mutex;
67 67
68 68 /* One global queue to serve all LHBA instances. */
69 69 static ddi_taskq_t *scn_taskq;
70 70 static kmutex_t scn_taskq_mutex;
71 71
72 72 /* One globally maintained transaction ID. */
73 73 static uint16_t xid = 0;
74 74
75 75 /*
76 76 * One SCN callback registration per LHBA instance. For now, since we
77 77 * support only one instance, we create one place holder for the
78 78 * callback.
79 79 */
80 80 void (*scn_callback_p)(void *);
81 81
82 82 /*
83 83 * One thread, port, local address, and listening socket per LHBA instance.
84 84 * For now, since we support only one instance, we create one set of place
85 85 * holder for these data.
86 86 */
87 87 static boolean_t esi_scn_thr_to_shutdown = B_FALSE;
88 88 static iscsi_thread_t *esi_scn_thr_id = NULL;
89 89 static void *instance_listening_so = NULL;
90 90 /*
91 91 * This mutex protects all the per LHBA instance variables, i.e.,
92 92 * esi_scn_thr_to_shutdown, esi_scn_thr_id, and instance_listening_so.
93 93 */
94 94 static kmutex_t esi_scn_thr_mutex;
95 95
96 96 /* iSNS related helpers */
97 97 /* Return status */
98 98 #define ISNS_OK 0
99 99 #define ISNS_BAD_SVR_ADDR 1
100 100 #define ISNS_INTERNAL_ERR 2
101 101 #define ISNS_CANNOT_FIND_LOCAL_ADDR 3
102 102 static int discover_isns_server(uint8_t *lhba_handle,
103 103 iscsi_addr_list_t **isns_server_addrs);
104 104 static int create_esi_scn_thr(uint8_t *lhba_handle,
105 105 iscsi_addr_t *isns_server_addr);
106 106 static void esi_scn_thr_cleanup(void);
107 107 static void register_isns_client(void *arg);
108 108 static isns_status_t do_isns_dev_attr_reg(iscsi_addr_t *isns_server_addr,
109 109 uint8_t *node_name, uint8_t *node_alias, uint32_t node_type);
110 110 static isns_status_t do_isns_dev_dereg(iscsi_addr_t *isns_server_addr,
111 111 uint8_t *node_name);
112 112
113 113 /*
114 114 * Make query to all iSNS servers visible to the specified LHBA.
115 115 * The query could be made for all target nodes or for a specific target
116 116 * node.
117 117 */
118 118 static isns_status_t do_isns_query(boolean_t is_query_all_nodes_b,
119 119 uint8_t *lhba_handle, uint8_t *target_node_name,
120 120 uint8_t *source_node_name, uint8_t *source_node_alias,
121 121 uint32_t source_node_type, isns_portal_group_list_t **pg_list);
122 122
123 123 /*
124 124 * Create DevAttrQuery message requesting portal group information for all
125 125 * target nodes. Send it to the specified iSNS server. Parse the
126 126 * DevAttrQueryRsp PDU and translate the results into a portal group list
127 127 * object.
128 128 */
129 129 static isns_status_t do_isns_dev_attr_query_all_nodes(
130 130 iscsi_addr_t *isns_server_addr, uint8_t *node_name,
131 131 uint8_t *node_alias, isns_portal_group_list_t **pg_list);
132 132
133 133 /*
134 134 * Create DevAttrQuery message requesting portal group information for the
135 135 * specified target node. Send it to the specified iSNS server. Parse the
136 136 * DevAttrQueryRsp PDU and translate the results into a portal group list
137 137 * object.
138 138 */
139 139 static isns_status_t do_isns_dev_attr_query_one_node(
140 140 iscsi_addr_t *isns_server_addr, uint8_t *target_node_name,
141 141 uint8_t *source_node_name, uint8_t *source_node_alias,
142 142 uint32_t source_node_type, isns_portal_group_list_t **pg_list);
143 143
144 144 static void isns_service_esi_scn(iscsi_thread_t *thread, void* arg);
145 145 static void (*scn_callback_lookup(uint8_t *lhba_handle))(void *);
146 146
147 147 /* Transport related helpers */
148 148 static void *isns_open(iscsi_addr_t *isns_server_addr);
149 149 static ssize_t isns_send_pdu(void *socket, isns_pdu_t *pdu);
150 150 static size_t isns_rcv_pdu(void *so, isns_pdu_t **pdu, size_t *pdu_size);
151 151 static boolean_t find_listening_addr(iscsi_addr_t *local_addr,
152 152 void *listening_so);
153 153 static boolean_t find_local_portal(iscsi_addr_t *isns_server_addr,
154 154 iscsi_addr_t **local_addr, void **listening_so);
155 155
156 156 /* iSNS protocol related helpers */
157 157 static size_t isns_create_pdu_header(uint16_t func_id,
158 158 uint16_t flags, isns_pdu_t **pdu);
159 159 static int isns_add_attr(isns_pdu_t *pdu,
160 160 size_t max_pdu_size, uint32_t attr_id, uint32_t attr_len,
161 161 void *attr_data, uint32_t attr_numeric_data);
162 162 static uint16_t create_xid(void);
163 163 static size_t isns_create_dev_attr_reg_pdu(
164 164 uint8_t *node_name, uint8_t *node_alias, uint32_t node_type,
165 165 uint16_t *xid, isns_pdu_t **out_pdu);
166 166 static size_t isns_create_dev_dereg_pdu(uint8_t *node_name,
167 167 uint16_t *xid_p, isns_pdu_t **out_pdu);
168 168 static size_t isns_create_dev_attr_qry_target_nodes_pdu(
169 169 uint8_t *node_name, uint8_t *node_alias, uint16_t *xid,
170 170 isns_pdu_t **out_pdu);
171 171 static size_t isns_create_dev_attr_qry_one_pg_pdu(
172 172 uint8_t *target_node_name, uint8_t *source_node_name,
173 173 uint16_t *xid, isns_pdu_t **out_pdu);
174 174 static size_t isns_create_esi_rsp_pdu(uint32_t rsp_status_code,
175 175 isns_pdu_t *pdu, uint16_t *xid, isns_pdu_t **out_pdu);
176 176 static size_t isns_create_scn_reg_pdu(uint8_t *node_name,
177 177 uint8_t *node_alias, uint16_t *xid, isns_pdu_t **out_pdu);
178 178 static size_t isns_create_scn_dereg_pdu(uint8_t *node_name,
179 179 uint16_t *xid_p, isns_pdu_t **out_pdu);
180 180 static size_t isns_create_scn_rsp_pdu(uint32_t rsp_status_code,
181 181 isns_pdu_t *pdu, uint16_t *xid, isns_pdu_t **out_pdu);
182 182 static uint32_t isns_process_dev_attr_reg_rsp(isns_pdu_t *resp_pdu_p);
183 183 static uint32_t isns_process_dev_attr_dereg_rsp(isns_pdu_t *resp_pdu_p);
184 184
185 185 /*
186 186 * Process and parse a DevAttrQryRsp message. The routine creates a list
187 187 * of Portal Group objects if the message is parasable without any issue.
188 188 * If the parsing is not successful, the pg_list will be set to NULL.
189 189 */
190 190 static uint32_t isns_process_dev_attr_qry_target_nodes_pdu(
191 191 iscsi_addr_t *isns_server_addr, uint16_t payload_funcId,
192 192 isns_resp_t *resp_p, size_t resp_len,
193 193 isns_portal_group_list_t **pg_list);
194 194 static uint32_t isns_process_scn_reg_rsp(isns_pdu_t *resp_pdu_p);
195 195 static uint32_t isns_process_scn_dereg_rsp(isns_pdu_t *resp_pdu_p);
196 196 static uint32_t isns_process_esi(isns_pdu_t *esi_pdu_p);
197 197 static uint32_t isns_process_scn(isns_pdu_t *scn_pdu_p, uint8_t *lhba_handle);
198 198
199 199 void
200 200 isns_client_init()
201 201 {
202 202 mutex_init(®_query_taskq_mutex, NULL, MUTEX_DRIVER, NULL);
203 203 mutex_enter(®_query_taskq_mutex);
204 204 reg_query_taskq = ddi_taskq_create(NULL, "isns_reg_query_taskq",
205 205 1, TASKQ_DEFAULTPRI, 0);
206 206 mutex_exit(®_query_taskq_mutex);
207 207
208 208 mutex_init(&scn_taskq_mutex, NULL, MUTEX_DRIVER, NULL);
209 209 mutex_enter(&scn_taskq_mutex);
210 210 scn_taskq = ddi_taskq_create(NULL, "isns_scn_taskq",
211 211 1, TASKQ_DEFAULTPRI, 0);
212 212 mutex_exit(&scn_taskq_mutex);
213 213
214 214 mutex_init(&esi_scn_thr_mutex, NULL, MUTEX_DRIVER, NULL);
215 215
216 216 /* MISC initializations. */
217 217 scn_callback_p = NULL;
218 218 esi_scn_thr_id = NULL;
219 219 instance_listening_so = NULL;
220 220 esi_scn_thr_to_shutdown = B_FALSE;
221 221 xid = 0;
222 222 }
223 223
224 224 void
225 225 isns_client_cleanup()
226 226 {
227 227 ddi_taskq_t *tmp_taskq_p;
228 228
229 229 mutex_enter(&scn_taskq_mutex);
230 230 tmp_taskq_p = scn_taskq;
231 231 scn_taskq = NULL;
232 232 mutex_exit(&scn_taskq_mutex);
233 233 ddi_taskq_destroy(tmp_taskq_p);
234 234
235 235 mutex_enter(®_query_taskq_mutex);
236 236 tmp_taskq_p = reg_query_taskq;
237 237 reg_query_taskq = NULL;
238 238 mutex_exit(®_query_taskq_mutex);
239 239 ddi_taskq_destroy(tmp_taskq_p);
240 240
241 241 mutex_destroy(®_query_taskq_mutex);
242 242 mutex_destroy(&scn_taskq_mutex);
243 243
244 244 esi_scn_thr_cleanup();
245 245
246 246 mutex_destroy(&esi_scn_thr_mutex);
247 247 }
248 248
249 249 isns_status_t
250 250 isns_reg(uint8_t *lhba_handle,
251 251 uint8_t *node_name,
252 252 size_t node_name_len,
253 253 uint8_t *node_alias,
254 254 size_t node_alias_len,
255 255 uint32_t node_type,
256 256 void (*scn_callback)(void *))
257 257 {
258 258 int i;
259 259 int list_space;
260 260 iscsi_addr_list_t *isns_server_addr_list;
261 261 isns_reg_arg_t *reg_args_p;
262 262
263 263 /* Look up the iSNS Server address(es) based on the specified ISID */
264 264 if (discover_isns_server(lhba_handle, &isns_server_addr_list) !=
265 265 ISNS_OK) {
266 266 return (isns_no_svr_found);
267 267 }
268 268
269 269 /* No iSNS server discovered - no registration needed. */
270 270 if (isns_server_addr_list->al_out_cnt == 0) {
271 271 list_space = sizeof (iscsi_addr_list_t);
272 272 kmem_free(isns_server_addr_list, list_space);
273 273 isns_server_addr_list = NULL;
274 274 return (isns_no_svr_found);
275 275 }
276 276
277 277 /* Check and create ESI/SCN threads and populate local address */
278 278 for (i = 0; i < isns_server_addr_list->al_out_cnt; i++) {
279 279 if (create_esi_scn_thr(lhba_handle,
280 280 &(isns_server_addr_list->al_addrs[i])) == ISNS_OK) {
281 281 break;
282 282 }
283 283 }
284 284 if (i == isns_server_addr_list->al_out_cnt) {
285 285 /*
286 286 * Problem creating ESI/SCN thread
287 287 * Free the server list
288 288 */
289 289 list_space = sizeof (iscsi_addr_list_t);
290 290 if (isns_server_addr_list->al_out_cnt > 0) {
291 291 list_space += (sizeof (iscsi_addr_t) *
292 292 (isns_server_addr_list->al_out_cnt - 1));
293 293 }
294 294 kmem_free(isns_server_addr_list, list_space);
295 295 isns_server_addr_list = NULL;
296 296 return (isns_internal_err);
297 297 }
298 298
299 299 /* Register against all iSNS servers discovered. */
300 300 for (i = 0; i < isns_server_addr_list->al_out_cnt; i++) {
301 301 reg_args_p = kmem_zalloc(sizeof (isns_reg_arg_t), KM_SLEEP);
302 302 reg_args_p->isns_server_addr =
303 303 kmem_zalloc(sizeof (iscsi_addr_t), KM_SLEEP);
304 304 bcopy(&isns_server_addr_list->al_addrs[i],
305 305 reg_args_p->isns_server_addr, sizeof (iscsi_addr_t));
306 306 reg_args_p->node_name = kmem_zalloc(node_name_len, KM_SLEEP);
307 307 bcopy(node_name, reg_args_p->node_name, node_name_len);
308 308 reg_args_p->node_name_len = node_name_len;
309 309 reg_args_p->node_alias = kmem_zalloc(node_alias_len, KM_SLEEP);
310 310 bcopy(node_alias, reg_args_p->node_alias, node_alias_len);
311 311 reg_args_p->node_alias_len = node_alias_len;
312 312 reg_args_p->node_type = node_type;
313 313
314 314 /* Dispatch the registration request */
315 315 register_isns_client(reg_args_p);
316 316 }
317 317
318 318 /* Free the server list */
319 319 list_space = sizeof (iscsi_addr_list_t);
320 320 if (isns_server_addr_list->al_out_cnt > 0) {
321 321 list_space += (sizeof (iscsi_addr_t) *
322 322 (isns_server_addr_list->al_out_cnt - 1));
323 323 }
324 324 kmem_free(isns_server_addr_list, list_space);
325 325 isns_server_addr_list = NULL;
326 326
327 327 /* Register the scn_callback. */
328 328 scn_callback_p = scn_callback;
329 329
330 330 return (isns_ok);
331 331 }
332 332
333 333 isns_status_t
334 334 isns_reg_one_server(entry_t *isns_server,
335 335 uint8_t *lhba_handle,
336 336 uint8_t *node_name,
337 337 size_t node_name_len,
338 338 uint8_t *node_alias,
339 339 size_t node_alias_len,
340 340 uint32_t node_type,
341 341 void (*scn_callback)(void *))
342 342 {
343 343 int status;
344 344 iscsi_addr_t *ap;
345 345 isns_reg_arg_t *reg_args_p;
346 346
347 347 ap = (iscsi_addr_t *)kmem_zalloc(sizeof (iscsi_addr_t), KM_SLEEP);
348 348 ap->a_port = isns_server->e_port;
349 349 ap->a_addr.i_insize = isns_server->e_insize;
350 350 if (isns_server->e_insize == sizeof (struct in_addr)) {
351 351 ap->a_addr.i_addr.in4.s_addr = (isns_server->e_u.u_in4.s_addr);
352 352 } else if (isns_server->e_insize == sizeof (struct in6_addr)) {
353 353 bcopy(&(isns_server->e_u.u_in6.s6_addr),
354 354 ap->a_addr.i_addr.in6.s6_addr,
355 355 sizeof (struct in6_addr));
356 356 } else {
357 357 kmem_free(ap, sizeof (iscsi_addr_t));
358 358 return (isns_op_failed);
359 359 }
360 360
361 361 /* Check and create ESI/SCN threads and populate local address */
362 362 if ((status = create_esi_scn_thr(lhba_handle, ap))
363 363 != ISNS_OK) {
364 364 /* Problem creating ESI/SCN thread */
365 365 DTRACE_PROBE1(isns_reg_one_server_create_esi_scn_thr,
366 366 int, status);
367 367 kmem_free(ap, sizeof (iscsi_addr_t));
368 368 return (isns_internal_err);
369 369 }
370 370
371 371 reg_args_p = kmem_zalloc(sizeof (isns_reg_arg_t), KM_SLEEP);
372 372 reg_args_p->isns_server_addr =
373 373 kmem_zalloc(sizeof (iscsi_addr_t), KM_SLEEP);
374 374 bcopy(ap, reg_args_p->isns_server_addr, sizeof (iscsi_addr_t));
375 375 reg_args_p->node_name = kmem_zalloc(node_name_len, KM_SLEEP);
376 376 bcopy(node_name, reg_args_p->node_name, node_name_len);
377 377 reg_args_p->node_name_len = node_name_len;
378 378 reg_args_p->node_alias = kmem_zalloc(node_alias_len, KM_SLEEP);
379 379 bcopy(node_alias, reg_args_p->node_alias, node_alias_len);
380 380 reg_args_p->node_alias_len = node_alias_len;
381 381 reg_args_p->node_type = node_type;
382 382
383 383 /* Dispatch the registration request */
384 384 register_isns_client(reg_args_p);
385 385
386 386 /* Register the scn_callback. */
387 387 scn_callback_p = scn_callback;
388 388
389 389 kmem_free(ap, sizeof (iscsi_addr_t));
390 390 return (isns_ok);
391 391 }
392 392
393 393 isns_status_t
394 394 isns_dereg(uint8_t *lhba_handle,
395 395 uint8_t *node_name)
396 396 {
397 397 int i;
398 398 int isns_svr_lst_sz;
399 399 int list_space;
400 400 iscsi_addr_list_t *isns_server_addr_list = NULL;
401 401 isns_status_t dereg_stat, combined_dereg_stat;
402 402
403 403 /* Look up the iSNS Server address(es) based on the specified ISID */
404 404 if (discover_isns_server(lhba_handle, &isns_server_addr_list) !=
405 405 ISNS_OK) {
406 406 return (isns_no_svr_found);
407 407 }
408 408 ASSERT(isns_server_addr_list != NULL);
409 409 if (isns_server_addr_list->al_out_cnt == 0) {
410 410 isns_svr_lst_sz = sizeof (iscsi_addr_list_t);
411 411 kmem_free(isns_server_addr_list, isns_svr_lst_sz);
412 412 isns_server_addr_list = NULL;
413 413 return (isns_no_svr_found);
414 414 }
415 415
416 416 combined_dereg_stat = isns_ok;
417 417 for (i = 0; i < isns_server_addr_list->al_out_cnt; i++) {
418 418 dereg_stat = do_isns_dev_dereg(
419 419 &isns_server_addr_list->al_addrs[i],
420 420 node_name);
421 421 if (dereg_stat == isns_ok) {
422 422 if (combined_dereg_stat != isns_ok) {
423 423 combined_dereg_stat = isns_op_partially_failed;
424 424 }
425 425 } else {
426 426 if (combined_dereg_stat == isns_ok) {
427 427 combined_dereg_stat = isns_op_partially_failed;
428 428 }
429 429 }
430 430 }
431 431
432 432 /* Free the server list. */
433 433 list_space = sizeof (iscsi_addr_list_t);
434 434 if (isns_server_addr_list->al_out_cnt > 0) {
435 435 list_space += (sizeof (iscsi_addr_t) *
436 436 (isns_server_addr_list->al_out_cnt - 1));
437 437 }
438 438 kmem_free(isns_server_addr_list, list_space);
439 439 isns_server_addr_list = NULL;
440 440
441 441 /* Cleanup ESI/SCN thread. */
442 442 esi_scn_thr_cleanup();
443 443
444 444 return (combined_dereg_stat);
445 445 }
446 446
447 447 isns_status_t
448 448 isns_dereg_one_server(entry_t *isns_server,
449 449 uint8_t *node_name,
450 450 boolean_t is_last_isns_server_b)
451 451 {
452 452 iscsi_addr_t *ap;
453 453 isns_status_t dereg_stat;
454 454
455 455 ap = (iscsi_addr_t *)kmem_zalloc(sizeof (iscsi_addr_t), KM_SLEEP);
456 456 ap->a_port = isns_server->e_port;
457 457 ap->a_addr.i_insize = isns_server->e_insize;
458 458 if (isns_server->e_insize == sizeof (struct in_addr)) {
459 459 ap->a_addr.i_addr.in4.s_addr = (isns_server->e_u.u_in4.s_addr);
460 460 } else if (isns_server->e_insize == sizeof (struct in6_addr)) {
461 461 bcopy(&(isns_server->e_u.u_in6.s6_addr),
462 462 ap->a_addr.i_addr.in6.s6_addr,
463 463 sizeof (struct in6_addr));
464 464 } else {
465 465 kmem_free(ap, sizeof (iscsi_addr_t));
466 466 return (isns_op_failed);
467 467 }
468 468
469 469 dereg_stat = do_isns_dev_dereg(ap, node_name);
470 470
471 471 kmem_free(ap, sizeof (iscsi_addr_t));
472 472
473 473 if (is_last_isns_server_b == B_TRUE) {
474 474 /*
475 475 * Clean up ESI/SCN thread resource if it is the
476 476 * last known iSNS server.
477 477 */
478 478 esi_scn_thr_cleanup();
479 479 }
480 480
481 481 return (dereg_stat);
482 482 }
483 483
484 484 isns_status_t
485 485 isns_query(uint8_t *lhba_handle,
486 486 uint8_t *node_name,
487 487 uint8_t *node_alias,
488 488 uint32_t node_type,
489 489 isns_portal_group_list_t **pg_list)
490 490 {
491 491 return (do_isns_query(B_TRUE,
492 492 lhba_handle,
493 493 (uint8_t *)"",
494 494 node_name,
495 495 node_alias,
496 496 node_type,
497 497 pg_list));
498 498 }
499 499
500 500 /* ARGSUSED */
501 501 isns_status_t
502 502 isns_query_one_server(iscsi_addr_t *isns_server_addr,
503 503 uint8_t *lhba_handle,
504 504 uint8_t *node_name,
505 505 uint8_t *node_alias,
506 506 uint32_t node_type,
507 507 isns_portal_group_list_t **pg_list)
508 508 {
509 509 return (do_isns_dev_attr_query_all_nodes(isns_server_addr,
510 510 node_name,
511 511 node_alias,
512 512 pg_list));
513 513 }
514 514
515 515 isns_status_t
516 516 isns_query_one_node(uint8_t *target_node_name,
517 517 uint8_t *lhba_handle,
518 518 uint8_t *source_node_name,
519 519 uint8_t *source_node_alias,
520 520 uint32_t source_node_type,
521 521 isns_portal_group_list_t **pg_list)
522 522 {
523 523 return (do_isns_query(B_FALSE,
524 524 lhba_handle,
525 525 target_node_name,
526 526 source_node_name,
527 527 source_node_alias,
528 528 source_node_type,
529 529 pg_list));
530 530 }
531 531
532 532 /* ARGSUSED */
533 533 isns_status_t
534 534 isns_query_one_server_one_node(iscsi_addr_t *isns_server_addr,
535 535 uint8_t *target_node_name,
536 536 uint8_t *lhba_handle,
537 537 uint8_t *source_node_name,
538 538 uint8_t *source_node_alias,
539 539 uint32_t source_node_type,
540 540 isns_portal_group_list_t **pg_list) {
541 541 /* Not supported yet. */
542 542 *pg_list = NULL;
543 543 return (isns_op_failed);
544 544 }
545 545
546 546 /* ARGSUSED */
547 547 static
548 548 int
549 549 discover_isns_server(uint8_t *lhba_handle,
550 550 iscsi_addr_list_t **isns_server_addrs)
551 551 {
552 552 entry_t e;
553 553 int i;
554 554 int isns_server_count = 1;
555 555 int list_space;
556 556 void *void_p;
557 557
558 558 /*
559 559 * Use supported iSNS server discovery method to find out all the
560 560 * iSNS servers. For now, only static configuration method is
561 561 * supported.
562 562 */
563 563 isns_server_count = 0;
564 564 void_p = NULL;
565 565 persistent_isns_addr_lock();
566 566 while (persistent_isns_addr_next(&void_p, &e) == B_TRUE) {
567 567 isns_server_count++;
568 568 }
569 569 persistent_isns_addr_unlock();
570 570
571 571 list_space = sizeof (iscsi_addr_list_t);
572 572 if (isns_server_count > 0) {
573 573 list_space += (sizeof (iscsi_addr_t) * (isns_server_count - 1));
574 574 }
575 575 *isns_server_addrs = (iscsi_addr_list_t *)kmem_zalloc(list_space,
576 576 KM_SLEEP);
577 577 (*isns_server_addrs)->al_out_cnt = isns_server_count;
578 578
579 579 persistent_isns_addr_lock();
580 580 i = 0;
581 581 void_p = NULL;
582 582 while (persistent_isns_addr_next(&void_p, &e) == B_TRUE) {
583 583 iscsi_addr_t *ap;
584 584
585 585 ap = &((*isns_server_addrs)->al_addrs[i]);
586 586 ap->a_port = e.e_port;
587 587 ap->a_addr.i_insize = e.e_insize;
588 588 if (e.e_insize == sizeof (struct in_addr)) {
589 589 ap->a_addr.i_addr.in4.s_addr = (e.e_u.u_in4.s_addr);
590 590 } else if (e.e_insize == sizeof (struct in6_addr)) {
591 591 bcopy(&e.e_u.u_in6.s6_addr,
592 592 ap->a_addr.i_addr.in6.s6_addr,
593 593 sizeof (struct in6_addr));
594 594 } else {
595 595 kmem_free(*isns_server_addrs, list_space);
596 596 *isns_server_addrs = NULL;
597 597 return (ISNS_BAD_SVR_ADDR);
598 598 }
599 599 i++;
600 600 }
601 601 persistent_isns_addr_unlock();
602 602
603 603 return (ISNS_OK);
604 604 }
605 605
606 606 static
607 607 int
608 608 create_esi_scn_thr(uint8_t *lhba_handle, iscsi_addr_t *isns_server_address)
609 609 {
610 610 void *listening_so = NULL;
611 611 boolean_t found = B_FALSE;
612 612
613 613 ASSERT(lhba_handle != NULL);
614 614 ASSERT(isns_server_address != NULL);
615 615
616 616 /*
617 617 * Bringing up of the thread should happen regardless of the
618 618 * subsequent registration status. That means, do not destroy the
619 619 * ESI/SCN thread already created.
620 620 */
621 621 /* Check and create ESI/SCN thread. */
622 622 mutex_enter(&esi_scn_thr_mutex);
623 623
624 624 /* Determine local port and address. */
625 625 found = find_local_portal(isns_server_address,
626 626 NULL, &listening_so);
627 627 if (found == B_FALSE) {
628 628 if (listening_so != NULL) {
629 629 iscsi_net->close(listening_so);
630 630 }
631 631 mutex_exit(&esi_scn_thr_mutex);
632 632 return (ISNS_CANNOT_FIND_LOCAL_ADDR);
633 633 }
634 634
635 635 if (esi_scn_thr_id == NULL) {
636 636 char thr_name[ISCSI_TH_MAX_NAME_LEN];
637 637 int rval;
638 638 isns_async_thread_arg_t *larg;
639 639
640 640 /* Assume the LHBA handle has a length of 4 */
641 641 if (snprintf(thr_name, sizeof (thr_name) - 1,
642 642 "isns_client_esi_%x%x%x%x",
643 643 lhba_handle[0],
644 644 lhba_handle[1],
645 645 lhba_handle[2],
646 646 lhba_handle[3]) >=
647 647 sizeof (thr_name)) {
648 648 esi_scn_thr_id = NULL;
649 649 if (listening_so != NULL) {
650 650 iscsi_net->close(listening_so);
651 651 listening_so = NULL;
652 652 }
653 653 mutex_exit(&esi_scn_thr_mutex);
654 654 return (ISNS_INTERNAL_ERR);
655 655 }
656 656
657 657 larg = kmem_zalloc(sizeof (isns_async_thread_arg_t), KM_SLEEP);
658 658 larg->lhba_handle = lhba_handle;
659 659 larg->listening_so = listening_so;
660 660 instance_listening_so = listening_so;
661 661 esi_scn_thr_to_shutdown = B_FALSE;
662 662 esi_scn_thr_id = iscsi_thread_create(NULL,
663 663 thr_name, isns_service_esi_scn, (void *)larg);
664 664 if (esi_scn_thr_id == NULL) {
665 665 if (listening_so != NULL) {
666 666 iscsi_net->close(listening_so);
667 667 listening_so = NULL;
668 668 instance_listening_so = NULL;
669 669 }
670 670 mutex_exit(&esi_scn_thr_mutex);
671 671 return (ISNS_INTERNAL_ERR);
672 672 }
673 673
674 674 rval = iscsi_thread_start(esi_scn_thr_id);
675 675 if (rval == B_FALSE) {
676 676 iscsi_thread_destroy(esi_scn_thr_id);
677 677 esi_scn_thr_id = NULL;
678 678 if (listening_so != NULL) {
679 679 iscsi_net->close(listening_so);
680 680 listening_so = NULL;
681 681 instance_listening_so = NULL;
682 682 }
683 683 mutex_exit(&esi_scn_thr_mutex);
684 684 return (ISNS_INTERNAL_ERR);
685 685 }
686 686 (void) iscsi_thread_send_wakeup(esi_scn_thr_id);
687 687 }
688 688 mutex_exit(&esi_scn_thr_mutex);
689 689
690 690 return (ISNS_OK);
691 691 }
692 692
693 693 static
694 694 void
695 695 register_isns_client(void *arg)
696 696 {
697 697 isns_reg_arg_t *reg_args;
698 698 isns_status_t status;
699 699
700 700 reg_args = (isns_reg_arg_t *)arg;
701 701
702 702 /* Deregister stale registration (if any). */
703 703 status = do_isns_dev_dereg(reg_args->isns_server_addr,
704 704 reg_args->node_name);
705 705
706 706 if (status == isns_open_conn_err) {
707 707 /* Cannot open connection to the server. Stop proceeding. */
708 708 kmem_free(reg_args->isns_server_addr, sizeof (iscsi_addr_t));
709 709 reg_args->isns_server_addr = NULL;
710 710 kmem_free(reg_args->node_name, reg_args->node_name_len);
711 711 reg_args->node_name = NULL;
712 712 kmem_free(reg_args->node_alias, reg_args->node_alias_len);
713 713 reg_args->node_alias = NULL;
714 714 kmem_free(reg_args, sizeof (isns_reg_arg_t));
715 715 return;
716 716 }
717 717
718 718 DTRACE_PROBE1(register_isns_client_dereg, isns_status_t, status);
719 719
720 720 /* New registration. */
721 721 status = do_isns_dev_attr_reg(reg_args->isns_server_addr,
722 722 reg_args->node_name, reg_args->node_alias, reg_args->node_type);
723 723
724 724 DTRACE_PROBE1(register_isns_client_reg, isns_status_t, status);
725 725
726 726 /* Cleanup */
727 727 kmem_free(reg_args->isns_server_addr, sizeof (iscsi_addr_t));
728 728 reg_args->isns_server_addr = NULL;
729 729 kmem_free(reg_args->node_name, reg_args->node_name_len);
730 730 reg_args->node_name = NULL;
731 731 kmem_free(reg_args->node_alias, reg_args->node_alias_len);
732 732 reg_args->node_alias = NULL;
733 733 kmem_free(reg_args, sizeof (isns_reg_arg_t));
734 734 }
735 735
736 736 static
737 737 isns_status_t
738 738 do_isns_dev_attr_reg(iscsi_addr_t *isns_server_addr,
739 739 uint8_t *node_name, uint8_t *node_alias, uint32_t node_type)
740 740 {
741 741 int rcv_rsp_cnt = 0;
742 742 int rsp_status;
743 743 isns_pdu_t *in_pdu, *out_pdu;
744 744 isns_status_t rval;
745 745 size_t bytes_received, in_pdu_size = 0, out_pdu_size = 0;
746 746 uint16_t xid;
747 747 void *so = NULL;
748 748
749 749 out_pdu_size = isns_create_dev_attr_reg_pdu(
750 750 node_name,
751 751 node_alias,
752 752 node_type,
753 753 &xid, &out_pdu);
754 754 if (out_pdu_size == 0) {
755 755 return (isns_create_msg_err);
756 756 }
757 757
758 758 ASSERT(out_pdu != NULL);
759 759 ASSERT(out_pdu_size > 0);
760 760
761 761 so = isns_open(isns_server_addr);
762 762 if (so == NULL) {
763 763 /* Log a message and return */
764 764 kmem_free(out_pdu, out_pdu_size);
765 765 out_pdu = NULL;
766 766 return (isns_open_conn_err);
767 767 }
768 768
769 769 if (isns_send_pdu(so, out_pdu) != 0) {
770 770 iscsi_net->close(so);
771 771 kmem_free(out_pdu, out_pdu_size);
772 772 out_pdu = NULL;
773 773 return (isns_send_msg_err);
774 774 }
775 775
776 776 /* Done with the out PDU - free it */
777 777 kmem_free(out_pdu, out_pdu_size);
778 778 out_pdu = NULL;
779 779
780 780 rcv_rsp_cnt = 0;
781 781 rval = isns_ok;
782 782 for (;;) {
783 783 bytes_received = isns_rcv_pdu(so, &in_pdu, &in_pdu_size);
784 784 ASSERT(bytes_received >= (size_t)0);
785 785 if (bytes_received == 0) {
786 786 ASSERT(in_pdu == NULL);
787 787 ASSERT(in_pdu_size == 0);
788 788 rval = isns_rcv_msg_err;
789 789 break;
790 790 }
791 791
792 792 ASSERT(in_pdu != NULL);
793 793 ASSERT(in_pdu_size > 0);
794 794
795 795 if (ntohs(in_pdu->xid) != xid) {
796 796 rcv_rsp_cnt++;
797 797 if (rcv_rsp_cnt < MAX_RCV_RSP_COUNT) {
798 798 continue;
799 799 } else {
800 800 /* Exceed maximum receive count. */
801 801 kmem_free(in_pdu, in_pdu_size);
802 802 in_pdu = NULL;
803 803 rval = isns_no_rsp_rcvd;
804 804 break;
805 805 }
806 806 }
807 807
808 808 rsp_status = isns_process_dev_attr_reg_rsp(in_pdu);
809 809 if (rsp_status != ISNS_RSP_SUCCESSFUL) {
810 810 if (rsp_status == ISNS_RSP_SRC_UNAUTHORIZED) {
811 811 rval = isns_op_partially_failed;
812 812 } else {
813 813 rval = isns_op_failed;
814 814 }
815 815 }
816 816 kmem_free(in_pdu, in_pdu_size);
817 817 in_pdu = NULL;
818 818 break;
819 819 }
820 820
821 821 if (rval != isns_ok) {
822 822 iscsi_net->close(so);
823 823 return (rval);
824 824 }
825 825
826 826 /* Always register SCN */
827 827 out_pdu_size = isns_create_scn_reg_pdu(
828 828 node_name, node_alias,
829 829 &xid, &out_pdu);
830 830 if (out_pdu_size == 0) {
831 831 iscsi_net->close(so);
832 832 return (isns_create_msg_err);
833 833 }
834 834
835 835 ASSERT(out_pdu != NULL);
836 836 ASSERT(out_pdu_size > 0);
837 837
838 838 if (isns_send_pdu(so, out_pdu) != 0) {
839 839 iscsi_net->close(so);
840 840 kmem_free(out_pdu, out_pdu_size);
841 841 out_pdu = NULL;
842 842 return (isns_send_msg_err);
843 843 }
844 844
845 845 /* Done with the out PDU - free it */
846 846 kmem_free(out_pdu, out_pdu_size);
847 847 out_pdu = NULL;
848 848
849 849 rcv_rsp_cnt = 0;
850 850 for (;;) {
851 851 bytes_received = isns_rcv_pdu(so, &in_pdu, &in_pdu_size);
852 852 ASSERT(bytes_received >= (size_t)0);
853 853 if (bytes_received == 0) {
854 854 ASSERT(in_pdu == NULL);
855 855 ASSERT(in_pdu_size == 0);
856 856 rval = isns_rcv_msg_err;
857 857 break;
858 858 }
859 859
860 860 ASSERT(in_pdu != NULL);
861 861 ASSERT(in_pdu_size > 0);
862 862
863 863 if (ntohs(in_pdu->xid) != xid) {
864 864 rcv_rsp_cnt++;
865 865 if (rcv_rsp_cnt < MAX_RCV_RSP_COUNT) {
866 866 continue;
867 867 } else {
868 868 /* Exceed maximum receive count. */
869 869 kmem_free(in_pdu, in_pdu_size);
870 870 in_pdu = NULL;
871 871 rval = isns_no_rsp_rcvd;
872 872 break;
873 873 }
874 874 }
875 875
876 876 rsp_status = isns_process_scn_reg_rsp(in_pdu);
877 877 if (rsp_status != ISNS_RSP_SUCCESSFUL) {
878 878 rval = isns_op_failed;
879 879 }
880 880 kmem_free(in_pdu, in_pdu_size);
881 881 in_pdu = NULL;
882 882 break;
883 883 }
884 884
885 885 iscsi_net->close(so);
886 886
887 887 return (rval);
888 888 }
889 889
890 890 static
891 891 isns_status_t
892 892 do_isns_dev_dereg(iscsi_addr_t *isns_server_addr,
893 893 uint8_t *node_name)
894 894 {
895 895 int rcv_rsp_cnt = 0;
896 896 int rsp_status;
897 897 isns_pdu_t *in_pdu, *out_pdu;
898 898 isns_status_t rval;
899 899 size_t bytes_received, in_pdu_size = 0, out_pdu_size = 0;
900 900 uint16_t xid;
901 901 void *so = NULL;
902 902
903 903 out_pdu_size = isns_create_dev_dereg_pdu(
904 904 node_name,
905 905 &xid, &out_pdu);
906 906 if (out_pdu_size == 0) {
907 907 return (isns_create_msg_err);
908 908 }
909 909
910 910 ASSERT(out_pdu != NULL);
911 911 ASSERT(out_pdu_size > 0);
912 912
913 913 so = isns_open(isns_server_addr);
914 914 if (so == NULL) {
915 915 /* Log a message and return */
916 916 kmem_free(out_pdu, out_pdu_size);
917 917 out_pdu = NULL;
918 918 return (isns_open_conn_err);
919 919 }
920 920
921 921 if (isns_send_pdu(so, out_pdu) != 0) {
922 922 iscsi_net->close(so);
923 923 kmem_free(out_pdu, out_pdu_size);
924 924 out_pdu = NULL;
925 925 return (isns_send_msg_err);
926 926 }
927 927
928 928 /* Done with the out PDU - free it */
929 929 kmem_free(out_pdu, out_pdu_size);
930 930 out_pdu = NULL;
931 931
932 932 rcv_rsp_cnt = 0;
933 933 rval = isns_ok;
934 934 for (;;) {
935 935 bytes_received = isns_rcv_pdu(so, &in_pdu, &in_pdu_size);
936 936 ASSERT(bytes_received >= (size_t)0);
937 937 if (bytes_received == 0) {
938 938 ASSERT(in_pdu == NULL);
939 939 ASSERT(in_pdu_size == 0);
940 940 rval = isns_rcv_msg_err;
941 941 break;
942 942 }
943 943
944 944 ASSERT(in_pdu != NULL);
945 945 ASSERT(in_pdu_size > 0);
946 946
947 947 if (ntohs(in_pdu->xid) != xid) {
948 948 rcv_rsp_cnt++;
949 949 if (rcv_rsp_cnt < MAX_RCV_RSP_COUNT) {
950 950 continue;
951 951 } else {
952 952 /* Exceed maximum receive count. */
953 953 kmem_free(in_pdu, in_pdu_size);
954 954 in_pdu = NULL;
955 955 rval = isns_no_rsp_rcvd;
956 956 break;
957 957 }
958 958 }
959 959
960 960 rsp_status = isns_process_dev_attr_dereg_rsp(in_pdu);
961 961 if (rsp_status != ISNS_RSP_SUCCESSFUL) {
962 962 rval = isns_op_failed;
963 963 }
964 964 kmem_free(in_pdu, in_pdu_size);
965 965 in_pdu = NULL;
966 966 break;
967 967 }
968 968
969 969 if (rval != isns_ok) {
970 970 iscsi_net->close(so);
971 971 return (rval);
972 972 }
973 973
974 974 /* Always deregister SCN */
975 975 out_pdu_size = isns_create_scn_dereg_pdu(
976 976 node_name,
977 977 &xid, &out_pdu);
978 978 if (out_pdu_size == 0) {
979 979 iscsi_net->close(so);
980 980 return (isns_create_msg_err);
981 981 }
982 982
983 983 ASSERT(out_pdu != NULL);
984 984 ASSERT(out_pdu_size > 0);
985 985
986 986 if (isns_send_pdu(so, out_pdu) != 0) {
987 987 iscsi_net->close(so);
988 988 kmem_free(out_pdu, out_pdu_size);
989 989 out_pdu = NULL;
990 990 return (isns_send_msg_err);
991 991 }
992 992
993 993 /* Done with the out PDU - free it */
994 994 kmem_free(out_pdu, out_pdu_size);
995 995 out_pdu = NULL;
996 996
997 997 rcv_rsp_cnt = 0;
998 998 for (;;) {
999 999 bytes_received = isns_rcv_pdu(so, &in_pdu, &in_pdu_size);
1000 1000 ASSERT(bytes_received >= (size_t)0);
1001 1001 if (bytes_received == 0) {
1002 1002 ASSERT(in_pdu == NULL);
1003 1003 ASSERT(in_pdu_size == 0);
1004 1004 rval = isns_rcv_msg_err;
1005 1005 break;
1006 1006 }
1007 1007
1008 1008 ASSERT(in_pdu != NULL);
1009 1009 ASSERT(in_pdu_size > 0);
1010 1010
1011 1011 if (ntohs(in_pdu->xid) != xid) {
1012 1012 rcv_rsp_cnt++;
1013 1013 if (rcv_rsp_cnt < MAX_RCV_RSP_COUNT) {
1014 1014 continue;
1015 1015 } else {
1016 1016 /* Exceed maximum receive count. */
1017 1017 kmem_free(in_pdu, in_pdu_size);
1018 1018 in_pdu = NULL;
1019 1019 rval = isns_no_rsp_rcvd;
1020 1020 break;
1021 1021 }
1022 1022 }
1023 1023
1024 1024 rsp_status = isns_process_scn_dereg_rsp(in_pdu);
1025 1025 if (rsp_status != ISNS_RSP_SUCCESSFUL) {
1026 1026 rval = isns_op_failed;
1027 1027 }
1028 1028 kmem_free(in_pdu, in_pdu_size);
1029 1029 in_pdu = NULL;
1030 1030 break;
1031 1031 }
1032 1032
1033 1033 iscsi_net->close(so);
1034 1034
1035 1035 return (rval);
1036 1036 }
1037 1037
1038 1038 static
1039 1039 isns_status_t
1040 1040 do_isns_query(boolean_t is_query_all_nodes_b,
1041 1041 uint8_t *lhba_handle,
1042 1042 uint8_t *target_node_name,
1043 1043 uint8_t *source_node_name,
1044 1044 uint8_t *source_node_alias,
1045 1045 uint32_t source_node_type,
1046 1046 isns_portal_group_list_t **pg_list)
1047 1047 {
1048 1048 int i, j, k;
1049 1049 int combined_num_of_pgs, combined_pg_lst_sz,
1050 1050 isns_svr_lst_sz,
1051 1051 tmp_pg_list_sz,
1052 1052 tmp_pg_lists_sz;
1053 1053 iscsi_addr_list_t *isns_server_addr_list = NULL;
1054 1054 isns_portal_group_t *pg;
1055 1055 isns_portal_group_list_t *combined_pg_list,
1056 1056 *tmp_pg_list, **tmp_pg_lists;
1057 1057 isns_status_t qry_stat, combined_qry_stat;
1058 1058
1059 1059 /* Look up the iSNS Server address(es) based on the specified ISID */
1060 1060 if (discover_isns_server(lhba_handle, &isns_server_addr_list) !=
1061 1061 ISNS_OK) {
1062 1062 *pg_list = NULL;
1063 1063 return (isns_no_svr_found);
1064 1064 }
1065 1065 if (isns_server_addr_list->al_out_cnt == 0) {
1066 1066 isns_svr_lst_sz = sizeof (iscsi_addr_list_t);
1067 1067 kmem_free(isns_server_addr_list, isns_svr_lst_sz);
1068 1068 isns_server_addr_list = NULL;
1069 1069 *pg_list = NULL;
1070 1070 return (isns_no_svr_found);
1071 1071 }
1072 1072
1073 1073 /*
1074 1074 * isns_server_addr_list->al_out_cnt should not be zero by the
1075 1075 * time it comes to this point.
1076 1076 */
1077 1077 tmp_pg_lists_sz = isns_server_addr_list->al_out_cnt *
1078 1078 sizeof (isns_portal_group_list_t *);
1079 1079 tmp_pg_lists = (isns_portal_group_list_t **)kmem_zalloc(
1080 1080 tmp_pg_lists_sz, KM_SLEEP);
1081 1081 combined_num_of_pgs = 0;
1082 1082 combined_qry_stat = isns_ok;
1083 1083 for (i = 0; i < isns_server_addr_list->al_out_cnt; i++) {
1084 1084 if (is_query_all_nodes_b) {
1085 1085 qry_stat = do_isns_dev_attr_query_all_nodes(
1086 1086 &isns_server_addr_list->al_addrs[i],
1087 1087 source_node_name,
1088 1088 source_node_alias,
1089 1089 &tmp_pg_list);
1090 1090 } else {
1091 1091 qry_stat = do_isns_dev_attr_query_one_node(
1092 1092 &isns_server_addr_list->al_addrs[i],
1093 1093 target_node_name,
1094 1094 source_node_name,
1095 1095 source_node_alias,
1096 1096 source_node_type,
1097 1097 &tmp_pg_list);
1098 1098 }
1099 1099
1100 1100 /* Record the portal group list retrieved from this server. */
1101 1101 tmp_pg_lists[i] = tmp_pg_list;
1102 1102 if (tmp_pg_list != NULL) {
1103 1103 combined_num_of_pgs += tmp_pg_list->pg_out_cnt;
1104 1104 }
1105 1105
1106 1106 if (qry_stat == isns_ok) {
1107 1107 if (combined_qry_stat != isns_ok) {
1108 1108 combined_qry_stat = isns_op_partially_failed;
1109 1109 }
1110 1110 } else {
1111 1111 if (combined_qry_stat != isns_op_partially_failed) {
1112 1112 if (combined_qry_stat == isns_ok && i > 0) {
1113 1113 combined_qry_stat =
1114 1114 isns_op_partially_failed;
1115 1115 } else {
1116 1116 combined_qry_stat = qry_stat;
1117 1117 }
1118 1118 }
1119 1119 }
1120 1120
1121 1121 if (is_query_all_nodes_b == B_FALSE) {
1122 1122 if (qry_stat == isns_ok) {
1123 1123 /*
1124 1124 * Break out of the loop if we already got
1125 1125 * the node information for one node.
1126 1126 */
1127 1127 break;
1128 1128 }
1129 1129 }
1130 1130 }
1131 1131
1132 1132 /* Merge the retrieved portal lists */
1133 1133 combined_pg_lst_sz = sizeof (isns_portal_group_list_t);
1134 1134 if (combined_num_of_pgs > 0) {
1135 1135 combined_pg_lst_sz += (combined_num_of_pgs - 1) *
1136 1136 sizeof (isns_portal_group_t);
1137 1137 }
1138 1138 combined_pg_list = (isns_portal_group_list_t *)kmem_zalloc(
1139 1139 combined_pg_lst_sz, KM_SLEEP);
1140 1140
1141 1141 combined_pg_list->pg_out_cnt = combined_num_of_pgs;
1142 1142 k = 0;
1143 1143 for (i = 0; i < isns_server_addr_list->al_out_cnt; i++) {
1144 1144 if (tmp_pg_lists[i] == NULL) {
1145 1145 continue;
1146 1146 }
1147 1147 for (j = 0; j < tmp_pg_lists[i]->pg_out_cnt; j++) {
1148 1148 pg = &(combined_pg_list->pg_list[k]);
1149 1149 bcopy(&(tmp_pg_lists[i]->pg_list[j]),
1150 1150 pg, sizeof (isns_portal_group_t));
1151 1151 k++;
1152 1152 }
1153 1153 tmp_pg_list_sz = sizeof (isns_portal_group_list_t);
1154 1154 if (tmp_pg_lists[i]->pg_out_cnt > 0) {
1155 1155 tmp_pg_list_sz += (tmp_pg_lists[i]->pg_out_cnt - 1) *
1156 1156 sizeof (isns_portal_group_t);
1157 1157 }
1158 1158 kmem_free(tmp_pg_lists[i], tmp_pg_list_sz);
1159 1159 tmp_pg_lists[i] = NULL;
1160 1160 }
1161 1161 kmem_free(tmp_pg_lists, tmp_pg_lists_sz);
1162 1162 tmp_pg_lists = NULL;
1163 1163
1164 1164 isns_svr_lst_sz = sizeof (iscsi_addr_list_t);
1165 1165 if (isns_server_addr_list->al_out_cnt > 0) {
1166 1166 isns_svr_lst_sz += (sizeof (iscsi_addr_t) *
1167 1167 (isns_server_addr_list->al_out_cnt - 1));
1168 1168 }
1169 1169 kmem_free(isns_server_addr_list, isns_svr_lst_sz);
1170 1170 isns_server_addr_list = NULL;
1171 1171
1172 1172 DTRACE_PROBE1(list, isns_portal_group_list_t *, combined_pg_list);
1173 1173
1174 1174 *pg_list = combined_pg_list;
1175 1175 return (combined_qry_stat);
1176 1176 }
1177 1177
1178 1178 static
1179 1179 isns_status_t
1180 1180 do_isns_dev_attr_query_all_nodes(iscsi_addr_t *isns_server_addr,
1181 1181 uint8_t *node_name,
1182 1182 uint8_t *node_alias,
1183 1183 isns_portal_group_list_t **pg_list)
1184 1184 {
1185 1185 int bytes_received;
1186 1186 int rcv_rsp_cnt = 0;
1187 1187 int rsp_status;
1188 1188 uint16_t xid, seq_id = 0, func_id;
1189 1189 isns_pdu_t *in_pdu, *out_pdu;
1190 1190 isns_pdu_mult_payload_t *combined_pdu = NULL, *old_combined_pdu = NULL;
1191 1191 isns_status_t qry_stat;
1192 1192 size_t out_pdu_size = 0, in_pdu_size = 0;
1193 1193 size_t old_combined_pdu_size = 0, combined_pdu_size = 0;
1194 1194 void *so = NULL;
1195 1195 uint8_t *payload_ptr;
1196 1196
1197 1197 /* Initialize */
1198 1198 *pg_list = NULL;
1199 1199
1200 1200 so = isns_open(isns_server_addr);
1201 1201 if (so == NULL) {
1202 1202 /* Log a message and return */
1203 1203 return (isns_open_conn_err);
1204 1204 }
1205 1205
1206 1206 /*
1207 1207 * Then, ask for all PG attributes. Filter the non-target nodes.
1208 1208 */
1209 1209 out_pdu_size = isns_create_dev_attr_qry_target_nodes_pdu(
1210 1210 node_name, node_alias, &xid, &out_pdu);
1211 1211 if (out_pdu_size == 0) {
1212 1212 iscsi_net->close(so);
1213 1213 return (isns_create_msg_err);
1214 1214 }
1215 1215
1216 1216 ASSERT(out_pdu != NULL);
1217 1217 ASSERT(out_pdu_size > 0);
1218 1218
1219 1219 if (isns_send_pdu(so, out_pdu) != 0) {
1220 1220 iscsi_net->close(so);
1221 1221 kmem_free(out_pdu, out_pdu_size);
1222 1222 out_pdu = NULL;
1223 1223 return (isns_send_msg_err);
1224 1224 }
1225 1225
1226 1226 /* Done with the out PDU - free it */
1227 1227 kmem_free(out_pdu, out_pdu_size);
1228 1228 out_pdu = NULL;
1229 1229
1230 1230 rcv_rsp_cnt = 0;
1231 1231 qry_stat = isns_ok;
1232 1232 for (;;) {
1233 1233 uint16_t flags;
1234 1234
1235 1235 bytes_received = isns_rcv_pdu(so, &in_pdu, &in_pdu_size);
1236 1236 ASSERT(bytes_received >= 0);
1237 1237 if (bytes_received == 0) {
1238 1238 ASSERT(in_pdu == NULL);
1239 1239 ASSERT(in_pdu_size == 0);
1240 1240 qry_stat = isns_rcv_msg_err;
1241 1241 break;
1242 1242 }
1243 1243
1244 1244 ASSERT(in_pdu != NULL);
1245 1245 ASSERT(in_pdu_size > 0);
1246 1246
1247 1247 /*
1248 1248 * make sure we are processing the right transaction id
1249 1249 */
1250 1250 if (ntohs(in_pdu->xid) != xid) {
1251 1251 rcv_rsp_cnt++;
1252 1252 if (rcv_rsp_cnt < MAX_RCV_RSP_COUNT) {
1253 1253 kmem_free(in_pdu, in_pdu_size);
1254 1254 in_pdu = NULL;
1255 1255 continue;
1256 1256 } else {
1257 1257 /* Exceed maximum receive count. */
1258 1258 kmem_free(in_pdu, in_pdu_size);
1259 1259 in_pdu = NULL;
1260 1260 qry_stat = isns_no_rsp_rcvd;
1261 1261 break;
1262 1262 }
1263 1263 }
1264 1264
1265 1265 /*
1266 1266 * check to see if FIRST and LAST PDU flag is set
1267 1267 * if they are both set, then this response only has one
1268 1268 * pdu and we can process the pdu
1269 1269 */
1270 1270 flags = in_pdu->flags;
1271 1271 if (((flags & ISNS_FLAG_FIRST_PDU) == ISNS_FLAG_FIRST_PDU) &&
1272 1272 ((flags & ISNS_FLAG_LAST_PDU) == ISNS_FLAG_LAST_PDU)) {
1273 1273 rsp_status =
1274 1274 isns_process_dev_attr_qry_target_nodes_pdu(
1275 1275 isns_server_addr,
1276 1276 in_pdu->func_id,
1277 1277 (isns_resp_t *)in_pdu->payload,
1278 1278 (size_t)in_pdu->payload_len,
1279 1279 pg_list);
1280 1280 kmem_free(in_pdu, in_pdu_size);
1281 1281 in_pdu = NULL;
1282 1282 break;
1283 1283 }
1284 1284 /*
1285 1285 * this pdu is part of a multi-pdu response. save off the
1286 1286 * the payload of this pdu and continue processing
1287 1287 */
1288 1288 if ((flags & ISNS_FLAG_FIRST_PDU) == ISNS_FLAG_FIRST_PDU) {
1289 1289 /* This is the first pdu, make sure sequence ID is 0 */
1290 1290 if (in_pdu->seq != 0) {
1291 1291 cmn_err(CE_NOTE, "isns query response invalid: "
1292 1292 "first pdu is not sequence ID 0");
1293 1293 kmem_free(in_pdu, in_pdu_size);
1294 1294 in_pdu = NULL;
1295 1295 return (isns_op_failed);
1296 1296 }
1297 1297 seq_id = 0;
1298 1298
1299 1299 /* create new pdu and copy in data from old pdu */
1300 1300 combined_pdu_size = ISNSP_MULT_PAYLOAD_HEADER_SIZE +
1301 1301 in_pdu->payload_len;
1302 1302 combined_pdu = (isns_pdu_mult_payload_t *)kmem_zalloc(
1303 1303 combined_pdu_size, KM_SLEEP);
1304 1304 func_id = in_pdu->func_id;
1305 1305 combined_pdu->payload_len = in_pdu->payload_len;
1306 1306 bcopy(in_pdu->payload, combined_pdu->payload,
1307 1307 in_pdu->payload_len);
1308 1308
1309 1309 /* done with in_pdu, free it */
1310 1310 kmem_free(in_pdu, in_pdu_size);
1311 1311 in_pdu = NULL;
1312 1312 } else {
1313 1313 seq_id++;
1314 1314 if (in_pdu->seq != seq_id) {
1315 1315 cmn_err(CE_NOTE, "isns query response invalid: "
1316 1316 "Missing sequence ID %d from isns query "
1317 1317 "response.", seq_id);
1318 1318 kmem_free(in_pdu, in_pdu_size);
1319 1319 in_pdu = NULL;
1320 1320 if (combined_pdu != NULL) {
1321 1321 kmem_free(combined_pdu,
1322 1322 combined_pdu_size);
1323 1323 combined_pdu = NULL;
1324 1324 }
1325 1325 return (isns_op_failed);
1326 1326 }
1327 1327 /*
1328 1328 * if conbined_pdu_size is still zero, then we never
1329 1329 * processed the first pdu
1330 1330 */
1331 1331 if (combined_pdu_size == 0) {
1332 1332 cmn_err(CE_NOTE, "isns query response invalid: "
1333 1333 "Did not receive first pdu.\n");
1334 1334 kmem_free(in_pdu, in_pdu_size);
1335 1335 in_pdu = NULL;
1336 1336 return (isns_op_failed);
1337 1337 }
1338 1338 /* save off the old combined pdu */
1339 1339 old_combined_pdu_size = combined_pdu_size;
1340 1340 old_combined_pdu = combined_pdu;
1341 1341
1342 1342 /*
1343 1343 * alloc a new pdu big enough to also hold the new
1344 1344 * pdu payload
1345 1345 */
1346 1346 combined_pdu_size += in_pdu->payload_len;
1347 1347 combined_pdu = (isns_pdu_mult_payload_t *)kmem_zalloc(
1348 1348 combined_pdu_size, KM_SLEEP);
1349 1349
1350 1350 /*
1351 1351 * copy the old pdu into the new allocated pdu buffer
1352 1352 * and append on the new pdu payload that we just
1353 1353 * received
1354 1354 */
1355 1355 bcopy(old_combined_pdu, combined_pdu,
1356 1356 old_combined_pdu_size);
1357 1357
1358 1358 payload_ptr = combined_pdu->payload +
1359 1359 combined_pdu->payload_len;
1360 1360 combined_pdu->payload_len += in_pdu->payload_len;
1361 1361 bcopy(in_pdu->payload, payload_ptr,
1362 1362 in_pdu->payload_len);
1363 1363
1364 1364 /* free in_pdu and old_combined_pdu */
1365 1365 kmem_free(in_pdu, in_pdu_size);
1366 1366 kmem_free(old_combined_pdu, old_combined_pdu_size);
1367 1367 in_pdu = NULL;
1368 1368 old_combined_pdu = NULL;
1369 1369 }
1370 1370 /*
1371 1371 * check to see if this is the LAST pdu.
1372 1372 * if it is, we can process it and move on
1373 1373 * otherwise continue to wait for the next pdu
1374 1374 */
1375 1375 if ((flags & ISNS_FLAG_LAST_PDU) == ISNS_FLAG_LAST_PDU) {
1376 1376 rsp_status =
1377 1377 isns_process_dev_attr_qry_target_nodes_pdu(
1378 1378 isns_server_addr,
1379 1379 func_id,
1380 1380 (isns_resp_t *)combined_pdu->payload,
1381 1381 combined_pdu->payload_len,
1382 1382 pg_list);
1383 1383 kmem_free(combined_pdu, combined_pdu_size);
1384 1384 combined_pdu = NULL;
1385 1385 break;
1386 1386 }
1387 1387 }
1388 1388 if (rsp_status != ISNS_RSP_SUCCESSFUL) {
1389 1389 qry_stat = isns_op_failed;
1390 1390 }
1391 1391
1392 1392 iscsi_net->close(so);
1393 1393
1394 1394 return (qry_stat);
1395 1395 }
1396 1396
1397 1397 /* ARGSUSED */
1398 1398 static
1399 1399 isns_status_t
1400 1400 do_isns_dev_attr_query_one_node(iscsi_addr_t *isns_server_addr,
1401 1401 uint8_t *target_node_name,
1402 1402 uint8_t *source_node_name,
1403 1403 uint8_t *source_node_alias,
1404 1404 uint32_t source_node_type,
1405 1405 isns_portal_group_list_t **pg_list)
1406 1406 {
1407 1407 int bytes_received;
1408 1408 int rcv_rsp_cnt;
1409 1409 int rsp_status;
1410 1410 isns_pdu_t *in_pdu, *out_pdu;
1411 1411 isns_status_t rval;
1412 1412 size_t out_pdu_size = 0, in_pdu_size = 0;
1413 1413 uint16_t xid;
1414 1414 void *so = NULL;
1415 1415
1416 1416 /* Obtain the list of target type storage nodes first */
1417 1417 out_pdu_size = isns_create_dev_attr_qry_one_pg_pdu(
1418 1418 target_node_name, source_node_name, &xid, &out_pdu);
1419 1419 if (out_pdu_size == 0) {
1420 1420 return (isns_create_msg_err);
1421 1421 }
1422 1422
1423 1423 ASSERT(out_pdu != NULL);
1424 1424 ASSERT(out_pdu_size > 0);
1425 1425
1426 1426 so = isns_open(isns_server_addr);
1427 1427 if (so == NULL) {
1428 1428 /* Log a message and return */
1429 1429 kmem_free(out_pdu, out_pdu_size);
1430 1430 out_pdu = NULL;
1431 1431 return (isns_open_conn_err);
1432 1432 }
1433 1433
1434 1434 if (isns_send_pdu(so, out_pdu) != 0) {
1435 1435 iscsi_net->close(so);
1436 1436 kmem_free(out_pdu, out_pdu_size);
1437 1437 out_pdu = NULL;
1438 1438 return (isns_send_msg_err);
1439 1439 }
1440 1440
1441 1441 /* Done with the out PDU - free it */
1442 1442 kmem_free(out_pdu, out_pdu_size);
1443 1443 out_pdu = NULL;
1444 1444
1445 1445 rcv_rsp_cnt = 0;
1446 1446 rval = isns_ok;
1447 1447 for (;;) {
1448 1448 bytes_received = isns_rcv_pdu(so, &in_pdu, &in_pdu_size);
1449 1449 ASSERT(bytes_received >= 0);
1450 1450 if (bytes_received == 0) {
1451 1451 ASSERT(in_pdu == NULL);
1452 1452 ASSERT(in_pdu_size == 0);
1453 1453 rval = isns_rcv_msg_err;
1454 1454 break;
1455 1455 }
1456 1456
1457 1457 ASSERT(in_pdu != NULL);
1458 1458 ASSERT(in_pdu_size > 0);
1459 1459
1460 1460 if (ntohs(in_pdu->xid) != xid) {
1461 1461 rcv_rsp_cnt++;
1462 1462 if (rcv_rsp_cnt < MAX_RCV_RSP_COUNT) {
1463 1463 continue;
1464 1464 } else {
1465 1465 /* Exceed maximum receive count. */
1466 1466 kmem_free(in_pdu, in_pdu_size);
1467 1467 in_pdu = NULL;
1468 1468 rval = isns_no_rsp_rcvd;
1469 1469 break;
1470 1470 }
1471 1471 }
1472 1472
1473 1473 rsp_status = isns_process_dev_attr_qry_target_nodes_pdu(
1474 1474 isns_server_addr, in_pdu->func_id,
1475 1475 (isns_resp_t *)in_pdu->payload, (size_t)in_pdu->payload_len,
1476 1476 pg_list);
1477 1477 if (rsp_status != ISNS_RSP_SUCCESSFUL) {
1478 1478 rval = isns_op_failed;
1479 1479 }
1480 1480 kmem_free(in_pdu, in_pdu_size);
1481 1481 in_pdu = NULL;
1482 1482 break;
1483 1483 }
1484 1484
1485 1485 iscsi_net->close(so);
1486 1486
1487 1487 return (rval);
1488 1488 }
↓ open down ↓ |
1488 lines elided |
↑ open up ↑ |
1489 1489
1490 1490 static
1491 1491 void
1492 1492 *isns_open(iscsi_addr_t *isns_server_addr)
1493 1493 {
1494 1494 int rval = 0;
1495 1495 union {
1496 1496 struct sockaddr sin;
1497 1497 struct sockaddr_in s_in4;
1498 1498 struct sockaddr_in6 s_in6;
1499 - } sa_rsvr = { 0 };
1499 + } sa_rsvr = {{0}};
1500 1500 void *so;
1501 1501 struct sockaddr_in6 t_addr;
1502 1502 socklen_t t_addrlen;
1503 1503
1504 1504 bzero(&t_addr, sizeof (struct sockaddr_in6));
1505 1505 t_addrlen = sizeof (struct sockaddr_in6);
1506 1506 if (isns_server_addr->a_addr.i_insize == sizeof (struct in_addr)) {
1507 1507 /* IPv4 */
1508 1508 sa_rsvr.s_in4.sin_family = AF_INET;
1509 1509 sa_rsvr.s_in4.sin_port = htons(isns_server_addr->a_port);
1510 1510 sa_rsvr.s_in4.sin_addr.s_addr =
1511 1511 isns_server_addr->a_addr.i_addr.in4.s_addr;
1512 1512
1513 1513 /* Create socket */
1514 1514 so = iscsi_net->socket(AF_INET, SOCK_STREAM, 0);
1515 1515 } else {
1516 1516 /* IPv6 */
1517 1517 sa_rsvr.s_in6.sin6_family = AF_INET6;
1518 1518 bcopy(&(isns_server_addr->a_addr.i_addr.in6),
1519 1519 sa_rsvr.s_in6.sin6_addr.s6_addr,
1520 1520 sizeof (struct in6_addr));
1521 1521 sa_rsvr.s_in6.sin6_port = htons(isns_server_addr->a_port);
1522 1522 /* Create socket */
1523 1523 so = iscsi_net->socket(AF_INET6, SOCK_STREAM, 0);
1524 1524 }
1525 1525
1526 1526 if (so == NULL) {
1527 1527 return (NULL);
1528 1528 }
1529 1529
1530 1530 rval = iscsi_net->connect(so, &sa_rsvr.sin,
1531 1531 (isns_server_addr->a_addr.i_insize == sizeof (struct in_addr)) ?
1532 1532 sizeof (struct sockaddr_in) :
1533 1533 sizeof (struct sockaddr_in6), 0, 0);
1534 1534
1535 1535 if (rval != 0) {
1536 1536 /* Flag value 2 indicates both cantsend and cantrecv */
1537 1537 iscsi_net->shutdown(so, 2);
1538 1538 iscsi_net->close(so);
1539 1539 return (NULL);
1540 1540 }
1541 1541
1542 1542 (void) iscsi_net->getsockname(so, (struct sockaddr *)&t_addr,
1543 1543 &t_addrlen);
1544 1544
1545 1545 return (so);
1546 1546 }
1547 1547
1548 1548 static ssize_t
1549 1549 isns_send_pdu(void *socket, isns_pdu_t *pdu)
1550 1550 {
1551 1551 int iovlen = 0;
1552 1552 iovec_t iovec[ISNS_MAX_IOVEC];
1553 1553 struct msghdr msg;
1554 1554 size_t send_len;
1555 1555 size_t total_len = 0;
1556 1556
1557 1557 ASSERT(iovlen < ISNS_MAX_IOVEC);
1558 1558 iovec[iovlen].iov_base = (void *)pdu;
1559 1559 iovec[iovlen].iov_len = (ISNSP_HEADER_SIZE);
1560 1560 total_len += (ISNSP_HEADER_SIZE);
1561 1561 iovlen++;
1562 1562
1563 1563 ASSERT(iovlen < ISNS_MAX_IOVEC);
1564 1564 iovec[iovlen].iov_base = (void *)pdu->payload;
1565 1565 iovec[iovlen].iov_len = ntohs(pdu->payload_len);
1566 1566 total_len += ntohs(pdu->payload_len);
1567 1567 iovlen++;
1568 1568
1569 1569 /* Initialization of the message header. */
1570 1570 bzero(&msg, sizeof (msg));
1571 1571 msg.msg_iov = &iovec[0];
1572 1572 msg.msg_flags = MSG_WAITALL;
1573 1573 msg.msg_iovlen = iovlen;
1574 1574
1575 1575 send_len = iscsi_net->sendmsg(socket, &msg);
1576 1576 return (send_len == total_len ? 0 : -1);
1577 1577 }
1578 1578
1579 1579 static
1580 1580 size_t
1581 1581 isns_rcv_pdu(void *socket, isns_pdu_t **pdu, size_t *pdu_size)
1582 1582 {
1583 1583 int poll_cnt;
1584 1584 iovec_t iovec[ISNS_MAX_IOVEC];
1585 1585 isns_pdu_t *tmp_pdu_hdr;
1586 1586 size_t bytes_received, total_bytes_received = 0, payload_len = 0;
1587 1587 struct msghdr msg;
1588 1588 uint8_t *tmp_pdu_data;
1589 1589
1590 1590 /* Receive the header first */
1591 1591 tmp_pdu_hdr = (isns_pdu_t *)kmem_zalloc(ISNSP_HEADER_SIZE, KM_SLEEP);
1592 1592 (void) memset((char *)&iovec[0], 0, sizeof (iovec_t));
1593 1593 iovec[0].iov_base = (void *)tmp_pdu_hdr;
1594 1594 iovec[0].iov_len = ISNSP_HEADER_SIZE;
1595 1595
1596 1596 /* Initialization of the message header. */
1597 1597 bzero(&msg, sizeof (msg));
1598 1598 msg.msg_iov = &iovec[0];
1599 1599 msg.msg_flags = MSG_WAITALL;
1600 1600 msg.msg_iovlen = 1;
1601 1601
1602 1602 /* Poll and receive the packets. */
1603 1603 poll_cnt = 0;
1604 1604 do {
1605 1605 bytes_received = iscsi_net->recvmsg(socket, &msg,
1606 1606 ISNS_RCV_TIMEOUT);
1607 1607 if (bytes_received == 0) {
1608 1608 /* Not yet. Increase poll count and try again. */
1609 1609 poll_cnt++;
1610 1610 continue;
1611 1611 } else {
1612 1612 /* OK data received. */
1613 1613 break;
1614 1614 }
1615 1615 } while (poll_cnt < ISNS_RCV_RETRY_MAX);
1616 1616
1617 1617 DTRACE_PROBE2(isns_rcv_pdu_hdr_summary,
1618 1618 int, poll_cnt, int, bytes_received);
1619 1619 if (poll_cnt >= ISNS_RCV_RETRY_MAX) {
1620 1620 kmem_free(tmp_pdu_hdr, ISNSP_HEADER_SIZE);
1621 1621 *pdu = NULL;
1622 1622 *pdu_size = 0;
1623 1623 return (0);
1624 1624 }
1625 1625 if (bytes_received == 0 || bytes_received != ISNSP_HEADER_SIZE) {
1626 1626 kmem_free(tmp_pdu_hdr, ISNSP_HEADER_SIZE);
1627 1627 *pdu = NULL;
1628 1628 *pdu_size = 0;
1629 1629 return (0);
1630 1630 }
1631 1631 total_bytes_received += bytes_received;
1632 1632
1633 1633 payload_len = ntohs(tmp_pdu_hdr->payload_len);
1634 1634 DTRACE_PROBE1(isns_rcv_pdu_probe1, int, payload_len);
1635 1635 /* Verify the received payload len is within limit */
1636 1636 if (payload_len > ISNSP_MAX_PAYLOAD_SIZE) {
1637 1637 kmem_free(tmp_pdu_hdr, ISNSP_HEADER_SIZE);
1638 1638 *pdu = NULL;
1639 1639 *pdu_size = 0;
1640 1640 return (0);
1641 1641 }
1642 1642
1643 1643 /* Proceed to receive additional data. */
1644 1644 tmp_pdu_data = kmem_zalloc(payload_len, KM_SLEEP);
1645 1645 (void) memset((char *)&iovec[0], 0, sizeof (iovec_t));
1646 1646 iovec[0].iov_base = (void *)tmp_pdu_data;
1647 1647 iovec[0].iov_len = payload_len;
1648 1648
1649 1649 /* Initialization of the message header. */
1650 1650 bzero(&msg, sizeof (msg));
1651 1651 msg.msg_iov = &iovec[0];
1652 1652 msg.msg_flags = MSG_WAITALL;
1653 1653 msg.msg_iovlen = 1;
1654 1654
1655 1655 /* Poll and receive the rest of the PDU. */
1656 1656 poll_cnt = 0;
1657 1657 do {
1658 1658 bytes_received = iscsi_net->recvmsg(socket, &msg,
1659 1659 ISNS_RCV_TIMEOUT);
1660 1660 if (bytes_received == 0) {
1661 1661 /* Not yet. Increase poll count and try again. */
1662 1662 poll_cnt++;
1663 1663 continue;
1664 1664 } else {
1665 1665 /* OK data received. */
1666 1666 break;
1667 1667 }
1668 1668 } while (poll_cnt < ISNS_RCV_RETRY_MAX);
1669 1669
1670 1670 DTRACE_PROBE2(isns_rcv_pdu_data_summary,
1671 1671 int, poll_cnt, int, bytes_received);
1672 1672
1673 1673 if (poll_cnt >= ISNS_RCV_RETRY_MAX) {
1674 1674 kmem_free(tmp_pdu_data, payload_len);
1675 1675 kmem_free(tmp_pdu_hdr, ISNSP_HEADER_SIZE);
1676 1676 *pdu = NULL;
1677 1677 *pdu_size = 0;
1678 1678 return (0);
1679 1679 }
1680 1680 if (bytes_received == 0 || bytes_received != payload_len) {
1681 1681 kmem_free(tmp_pdu_data, payload_len);
1682 1682 kmem_free(tmp_pdu_hdr, ISNSP_HEADER_SIZE);
1683 1683 *pdu = NULL;
1684 1684 *pdu_size = 0;
1685 1685 return (0);
1686 1686 }
1687 1687 total_bytes_received += bytes_received;
1688 1688
1689 1689 *pdu_size = ISNSP_HEADER_SIZE + payload_len;
1690 1690 (*pdu) = (isns_pdu_t *)kmem_zalloc((*pdu_size), KM_SLEEP);
1691 1691 (*pdu)->version = ntohs(tmp_pdu_hdr->version);
1692 1692 (*pdu)->func_id = ntohs(tmp_pdu_hdr->func_id);
1693 1693 (*pdu)->payload_len = payload_len;
1694 1694 (*pdu)->flags = ntohs(tmp_pdu_hdr->flags);
1695 1695 (*pdu)->xid = ntohs(tmp_pdu_hdr->xid);
1696 1696 (*pdu)->seq = ntohs(tmp_pdu_hdr->seq);
1697 1697 bcopy(tmp_pdu_data, &((*pdu)->payload), payload_len);
1698 1698
1699 1699 kmem_free(tmp_pdu_data, payload_len);
1700 1700 tmp_pdu_data = NULL;
1701 1701 kmem_free(tmp_pdu_hdr, ISNSP_HEADER_SIZE);
1702 1702 tmp_pdu_hdr = NULL;
1703 1703
1704 1704 return (total_bytes_received);
1705 1705 }
1706 1706
1707 1707
1708 1708 /*
1709 1709 * isns_create_dev_attr_reg_pdu - isns client registration pdu
1710 1710 */
1711 1711 static size_t
1712 1712 isns_create_dev_attr_reg_pdu(
1713 1713 uint8_t *node_name,
1714 1714 uint8_t *node_alias,
1715 1715 uint32_t node_type,
1716 1716 uint16_t *xid_p,
1717 1717 isns_pdu_t **out_pdu)
1718 1718 {
1719 1719 in_port_t local_port;
1720 1720 isns_pdu_t *pdu;
1721 1721 size_t pdu_size, node_name_len, node_alias_len;
1722 1722 uint16_t flags;
1723 1723 boolean_t rval = B_FALSE;
1724 1724 iscsi_addr_t local_addr;
1725 1725
1726 1726 ASSERT(node_name != NULL);
1727 1727 ASSERT(node_alias != NULL);
1728 1728
1729 1729 /* RFC 4171 section 6.1 - NULLs included in the length. */
1730 1730 node_name_len = strlen((char *)node_name) + 1;
1731 1731 node_alias_len = strlen((char *)node_alias) + 1;
1732 1732
1733 1733 if (node_name_len == 1) {
1734 1734 *out_pdu = NULL;
1735 1735 return (0);
1736 1736 }
1737 1737
1738 1738 /*
1739 1739 * Create DevAttrReg Message
1740 1740 *
1741 1741 * Enable the replace bit so that we can update
1742 1742 * existing registration
1743 1743 */
1744 1744 flags = ISNS_FLAG_FIRST_PDU |
1745 1745 ISNS_FLAG_LAST_PDU |
1746 1746 ISNS_FLAG_REPLACE_REG;
1747 1747 pdu_size = isns_create_pdu_header(ISNS_DEV_ATTR_REG, flags, &pdu);
1748 1748 *xid_p = pdu->xid;
1749 1749
1750 1750 /* Source attribute */
1751 1751 if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID,
1752 1752 node_name_len, node_name, 0) != 0) {
1753 1753 kmem_free(pdu, pdu_size);
1754 1754 *out_pdu = NULL;
1755 1755 return (0);
1756 1756 }
1757 1757
1758 1758 /*
1759 1759 * Message Key Attributes
1760 1760 *
1761 1761 * EID attribute - Section 6.2.1
1762 1762 * This is required for re-registrations or Replace
1763 1763 * Bit is ignored - Section 5.6.5.1
1764 1764 */
1765 1765 if (isns_add_attr(pdu, pdu_size, ISNS_EID_ATTR_ID,
1766 1766 node_name_len, node_name, 0) != 0) {
1767 1767 kmem_free(pdu, pdu_size);
1768 1768 *out_pdu = NULL;
1769 1769 return (0);
1770 1770 }
1771 1771
1772 1772 /* Delimiter */
1773 1773 if (isns_add_attr(pdu, pdu_size, ISNS_DELIMITER_ATTR_ID, 0, 0, 0)
1774 1774 != 0) {
1775 1775 kmem_free(pdu, pdu_size);
1776 1776 *out_pdu = NULL;
1777 1777 return (0);
1778 1778 }
1779 1779
1780 1780 /* EID attribute - Section 6.2.1 */
1781 1781 if (isns_add_attr(pdu, pdu_size, ISNS_EID_ATTR_ID,
1782 1782 node_name_len, node_name, 0) != 0) {
1783 1783 kmem_free(pdu, pdu_size);
1784 1784 *out_pdu = NULL;
1785 1785 return (0);
1786 1786 }
1787 1787
1788 1788 /* ENTITY Protocol - Section 6.2.2 */
1789 1789 if (isns_add_attr(pdu, pdu_size, ISNS_ENTITY_PROTOCOL_ATTR_ID, 4,
1790 1790 0, ISNS_ENTITY_PROTOCOL_ISCSI) != 0) {
1791 1791 kmem_free(pdu, pdu_size);
1792 1792 *out_pdu = NULL;
1793 1793 return (0);
1794 1794 }
1795 1795
1796 1796 /* iSCSI Name - Section 6.4.1 */
1797 1797 if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID,
1798 1798 node_name_len, node_name, 0) != 0) {
1799 1799 kmem_free(pdu, pdu_size);
1800 1800 *out_pdu = NULL;
1801 1801 return (0);
1802 1802 }
1803 1803
1804 1804 /* iSCSI Alias - Section 6.4.3 Optional */
1805 1805 if (node_alias_len > 1) {
1806 1806 if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_ALIAS_ATTR_ID,
1807 1807 node_alias_len, node_alias, 0) != 0) {
1808 1808 kmem_free(pdu, pdu_size);
1809 1809 *out_pdu = NULL;
1810 1810 return (0);
1811 1811 }
1812 1812 }
1813 1813
1814 1814 /* iSCSI Node Type - Section 6.4.2 */
1815 1815 if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_NODE_TYPE_ATTR_ID, 4,
1816 1816 0, node_type) != 0) {
1817 1817 kmem_free(pdu, pdu_size);
1818 1818 *out_pdu = NULL;
1819 1819 return (0);
1820 1820 }
1821 1821
1822 1822 mutex_enter(&esi_scn_thr_mutex);
1823 1823 if (instance_listening_so != NULL) {
1824 1824 rval = find_listening_addr(&local_addr, instance_listening_so);
1825 1825 if (rval == B_FALSE) {
1826 1826 kmem_free(pdu, pdu_size);
1827 1827 *out_pdu = NULL;
1828 1828 mutex_exit(&esi_scn_thr_mutex);
1829 1829 return (0);
1830 1830 }
1831 1831 } else {
1832 1832 kmem_free(pdu, pdu_size);
1833 1833 *out_pdu = NULL;
1834 1834 mutex_exit(&esi_scn_thr_mutex);
1835 1835 return (0);
1836 1836 }
1837 1837 local_port = local_addr.a_port;
1838 1838 /* Portal IP Address - Section 6.5.2 */
1839 1839 if (isns_add_attr(pdu, pdu_size, ISNS_PORTAL_IP_ADDR_ATTR_ID, 16,
1840 1840 &(local_addr.a_addr.i_addr.in4),
1841 1841 local_addr.a_addr.i_insize) != 0) {
1842 1842 kmem_free(pdu, pdu_size);
1843 1843 *out_pdu = NULL;
1844 1844 mutex_exit(&esi_scn_thr_mutex);
1845 1845 return (0);
1846 1846 }
1847 1847 mutex_exit(&esi_scn_thr_mutex);
1848 1848
1849 1849 /* Portal Port - Section 6.5.3 */
1850 1850 if (isns_add_attr(pdu, pdu_size, ISNS_PORTAL_PORT_ATTR_ID, 4, 0,
1851 1851 local_port) != 0) {
1852 1852 kmem_free(pdu, pdu_size);
1853 1853 *out_pdu = NULL;
1854 1854 return (0);
1855 1855 }
1856 1856
1857 1857 /* SCN Port - Section 6.3.7 */
1858 1858 if (isns_add_attr(pdu, pdu_size, ISNS_SCN_PORT_ATTR_ID, 4, 0,
1859 1859 local_port) != 0) {
1860 1860 kmem_free(pdu, pdu_size);
1861 1861 *out_pdu = NULL;
1862 1862 return (0);
1863 1863 }
1864 1864
1865 1865 /* ESI Port - Section 6.3.5 */
1866 1866 if (isns_add_attr(pdu, pdu_size, ISNS_ESI_PORT_ATTR_ID, 4, 0,
1867 1867 local_port) != 0) {
1868 1868 kmem_free(pdu, pdu_size);
1869 1869 *out_pdu = NULL;
1870 1870 return (0);
1871 1871 }
1872 1872
1873 1873 *out_pdu = pdu;
1874 1874 return (pdu_size);
1875 1875 }
1876 1876
1877 1877 /*
1878 1878 * isns_create_dev_dereg_pdu - Create an iSNS PDU for deregistration.
1879 1879 */
1880 1880 static size_t
1881 1881 isns_create_dev_dereg_pdu(
1882 1882 uint8_t *node_name,
1883 1883 uint16_t *xid_p,
1884 1884 isns_pdu_t **out_pdu)
1885 1885 {
1886 1886 isns_pdu_t *pdu;
1887 1887 size_t pdu_size, node_name_len;
1888 1888 uint16_t flags;
1889 1889
1890 1890 ASSERT(node_name != NULL);
1891 1891
1892 1892 /* RFC 4171 section 6.1 - NULLs included in the length. */
1893 1893 node_name_len = strlen((char *)node_name) + 1;
1894 1894
1895 1895 if (node_name_len == 1) {
1896 1896 *out_pdu = NULL;
1897 1897 return (0);
1898 1898 }
1899 1899
1900 1900 /*
1901 1901 * Create DevDeReg Message
1902 1902 */
1903 1903 flags = ISNS_FLAG_FIRST_PDU |
1904 1904 ISNS_FLAG_LAST_PDU;
1905 1905 pdu_size = isns_create_pdu_header(ISNS_DEV_DEREG, flags, &pdu);
1906 1906 *xid_p = pdu->xid;
1907 1907
1908 1908 /* Source attribute */
1909 1909 if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID,
1910 1910 node_name_len, node_name, 0) != 0) {
1911 1911 kmem_free(pdu, pdu_size);
1912 1912 *out_pdu = NULL;
1913 1913 return (0);
1914 1914 }
1915 1915
1916 1916 /* Delimiter */
1917 1917 if (isns_add_attr(pdu, pdu_size, ISNS_DELIMITER_ATTR_ID, 0, 0, 0)
1918 1918 != 0) {
1919 1919 kmem_free(pdu, pdu_size);
1920 1920 *out_pdu = NULL;
1921 1921 return (0);
1922 1922 }
1923 1923
1924 1924 /* Entity Identifier */
1925 1925 if (isns_add_attr(pdu, pdu_size, ISNS_EID_ATTR_ID,
1926 1926 node_name_len, node_name, 0) != 0) {
1927 1927 kmem_free(pdu, pdu_size);
1928 1928 *out_pdu = NULL;
1929 1929 return (0);
1930 1930 }
1931 1931
1932 1932 *out_pdu = pdu;
1933 1933 return (pdu_size);
1934 1934 }
1935 1935
1936 1936 /*
1937 1937 * isns_create_dev_attr_target_nodes_pdu - get all accessible targets
1938 1938 *
1939 1939 * Querys for a list of all accessible target nodes for this
1940 1940 * initiator. Requests all required login information (name,
1941 1941 * ip, port, tpgt).
1942 1942 */
1943 1943 static size_t
1944 1944 isns_create_dev_attr_qry_target_nodes_pdu(
1945 1945 uint8_t *node_name,
1946 1946 uint8_t *node_alias,
1947 1947 uint16_t *xid_p, isns_pdu_t **out_pdu)
1948 1948 {
1949 1949 isns_pdu_t *pdu_p;
1950 1950 uint16_t flags;
1951 1951 size_t pdu_size, node_name_len;
1952 1952
1953 1953 ASSERT(node_name != NULL);
1954 1954 ASSERT(node_alias != NULL);
1955 1955
1956 1956 /* RFC 4171 section 6.1 - NULLs included in the length. */
1957 1957 node_name_len = strlen((char *)node_name) + 1;
1958 1958
1959 1959 if (node_name_len == 1) {
1960 1960 *out_pdu = NULL;
1961 1961 return (0);
1962 1962 }
1963 1963
1964 1964 /* Create DevAttrQry Message */
1965 1965 flags = ISNS_FLAG_FIRST_PDU |
1966 1966 ISNS_FLAG_LAST_PDU;
1967 1967 pdu_size = isns_create_pdu_header(ISNS_DEV_ATTR_QRY, flags, &pdu_p);
1968 1968 *xid_p = pdu_p->xid;
1969 1969
1970 1970 /* Source attribute */
1971 1971 if (isns_add_attr(pdu_p, pdu_size, ISNS_ISCSI_NAME_ATTR_ID,
1972 1972 node_name_len, node_name, 0) != 0) {
1973 1973 kmem_free(pdu_p, pdu_size);
1974 1974 *out_pdu = NULL;
1975 1975 return (0);
1976 1976 }
1977 1977
1978 1978 /*
1979 1979 * Message Key Attribute
1980 1980 *
1981 1981 * iSCSI Node Type
1982 1982 * Query target nodes only
1983 1983 */
1984 1984 if (isns_add_attr(pdu_p, pdu_size, ISNS_ISCSI_NODE_TYPE_ATTR_ID,
1985 1985 4, 0, ISNS_TARGET_NODE_TYPE) != 0) {
1986 1986 kmem_free(pdu_p, pdu_size);
1987 1987 *out_pdu = NULL;
1988 1988 return (0);
1989 1989 }
1990 1990
1991 1991 /* Delimiter */
1992 1992 if (isns_add_attr(pdu_p, pdu_size,
1993 1993 ISNS_DELIMITER_ATTR_ID, 0, 0, 0) != 0) {
1994 1994 kmem_free(pdu_p, pdu_size);
1995 1995 *out_pdu = NULL;
1996 1996 return (0);
1997 1997 }
1998 1998
1999 1999 /* PG iSCSI Name - Zero length TLV */
2000 2000 if (isns_add_attr(pdu_p, pdu_size, ISNS_PG_ISCSI_NAME_ATTR_ID,
2001 2001 0, 0, 0) != 0) {
2002 2002 kmem_free(pdu_p, pdu_size);
2003 2003 *out_pdu = NULL;
2004 2004 return (0);
2005 2005 }
2006 2006
2007 2007 /* PG Portal IP Address - Zero length TLV */
2008 2008 if (isns_add_attr(pdu_p, pdu_size, ISNS_PG_PORTAL_IP_ADDR_ATTR_ID,
2009 2009 0, 0, 0) != 0) {
2010 2010 kmem_free(pdu_p, pdu_size);
2011 2011 *out_pdu = NULL;
2012 2012 return (0);
2013 2013 }
2014 2014
2015 2015 /* PG Portal Port - Zero length TLV */
2016 2016 if (isns_add_attr(pdu_p, pdu_size, ISNS_PG_PORTAL_PORT_ATTR_ID,
2017 2017 0, 0, 0) != 0) {
2018 2018 kmem_free(pdu_p, pdu_size);
2019 2019 *out_pdu = NULL;
2020 2020 return (0);
2021 2021 }
2022 2022
2023 2023 /* PG Portal Group Tag - Zero length TLV */
2024 2024 if (isns_add_attr(pdu_p, pdu_size,
2025 2025 ISNS_PG_TAG_ATTR_ID, 0, 0, 0) != 0) {
2026 2026 kmem_free(pdu_p, pdu_size);
2027 2027 *out_pdu = NULL;
2028 2028 return (0);
2029 2029 }
2030 2030
2031 2031 *out_pdu = pdu_p;
2032 2032 return (pdu_size);
2033 2033 }
2034 2034
2035 2035 static
2036 2036 size_t
2037 2037 isns_create_dev_attr_qry_one_pg_pdu(
2038 2038 uint8_t *target_node_name,
2039 2039 uint8_t *source_node_name,
2040 2040 uint16_t *xid_p,
2041 2041 isns_pdu_t **out_pdu)
2042 2042 {
2043 2043 isns_pdu_t *pdu_p;
2044 2044 uint16_t flags;
2045 2045 size_t pdu_size, source_node_name_len, target_node_name_len;
2046 2046
2047 2047 ASSERT(target_node_name != NULL);
2048 2048 ASSERT(source_node_name != NULL);
2049 2049
2050 2050 /* RFC 4171 section 6.1 - NULLs included in the length. */
2051 2051 source_node_name_len = strlen((char *)source_node_name) + 1;
2052 2052 target_node_name_len = strlen((char *)target_node_name) + 1;
2053 2053
2054 2054 if (source_node_name_len == 1) {
2055 2055 *out_pdu = NULL;
2056 2056 return (0);
2057 2057 }
2058 2058
2059 2059 /* Create DevAttrQry message scoped to target_node_name */
2060 2060 flags = ISNS_FLAG_FIRST_PDU |
2061 2061 ISNS_FLAG_LAST_PDU;
2062 2062 pdu_size = isns_create_pdu_header(ISNS_DEV_ATTR_QRY, flags, &pdu_p);
2063 2063 *xid_p = pdu_p->xid;
2064 2064
2065 2065 /* Source attribute */
2066 2066 if (isns_add_attr(pdu_p, pdu_size, ISNS_ISCSI_NAME_ATTR_ID,
2067 2067 source_node_name_len, source_node_name, 0) != 0) {
2068 2068 kmem_free(pdu_p, pdu_size);
2069 2069 *out_pdu = NULL;
2070 2070 return (0);
2071 2071 }
2072 2072
2073 2073 /* Message key attribute */
2074 2074 /* iSCSI Node Name */
2075 2075 if (isns_add_attr(pdu_p, pdu_size, ISNS_ISCSI_NAME_ATTR_ID,
2076 2076 target_node_name_len,
2077 2077 target_node_name, 0) != 0) {
2078 2078 kmem_free(pdu_p, pdu_size);
2079 2079 *out_pdu = NULL;
2080 2080 return (0);
2081 2081 }
2082 2082
2083 2083 /* Delimiter */
2084 2084 if (isns_add_attr(pdu_p, pdu_size,
2085 2085 ISNS_DELIMITER_ATTR_ID, 0, 0, 0) != 0) {
2086 2086 kmem_free(pdu_p, pdu_size);
2087 2087 *out_pdu = NULL;
2088 2088 return (0);
2089 2089 }
2090 2090
2091 2091 /* PG iSCSI Name - Zero length TLV */
2092 2092 if (isns_add_attr(pdu_p, pdu_size, ISNS_PG_ISCSI_NAME_ATTR_ID,
2093 2093 0, 0, 0) != 0) {
2094 2094 kmem_free(pdu_p, pdu_size);
2095 2095 *out_pdu = NULL;
2096 2096 return (0);
2097 2097 }
2098 2098
2099 2099 /* PG Portal IP Address - Zero length TLV */
2100 2100 if (isns_add_attr(pdu_p, pdu_size, ISNS_PG_PORTAL_IP_ADDR_ATTR_ID,
2101 2101 0, 0, 0) != 0) {
2102 2102 kmem_free(pdu_p, pdu_size);
2103 2103 *out_pdu = NULL;
2104 2104 return (0);
2105 2105 }
2106 2106
2107 2107 /* PG Portal Port - Zero length TLV */
2108 2108 if (isns_add_attr(pdu_p, pdu_size, ISNS_PG_PORTAL_PORT_ATTR_ID,
2109 2109 0, 0, 0) != 0) {
2110 2110 kmem_free(pdu_p, pdu_size);
2111 2111 *out_pdu = NULL;
2112 2112 return (0);
2113 2113 }
2114 2114
2115 2115 /* PG Portal Group Tag - Zero length TLV */
2116 2116 if (isns_add_attr(pdu_p, pdu_size,
2117 2117 ISNS_PG_TAG_ATTR_ID, 0, 0, 0) != 0) {
2118 2118 kmem_free(pdu_p, pdu_size);
2119 2119 *out_pdu = NULL;
2120 2120 return (0);
2121 2121 }
2122 2122
2123 2123 *out_pdu = pdu_p;
2124 2124 return (pdu_size);
2125 2125 }
2126 2126
2127 2127 static
2128 2128 size_t
2129 2129 isns_create_scn_reg_pdu(
2130 2130 uint8_t *node_name,
2131 2131 uint8_t *node_alias,
2132 2132 uint16_t *xid_p,
2133 2133 isns_pdu_t **out_pdu)
2134 2134 {
2135 2135 isns_pdu_t *pdu;
2136 2136 size_t pdu_size, node_name_len;
2137 2137 uint16_t flags;
2138 2138
2139 2139 ASSERT(node_name != NULL);
2140 2140 ASSERT(node_alias != NULL);
2141 2141
2142 2142 /* RFC 4171 section 6.1 - NULLs included in the length. */
2143 2143 node_name_len = strlen((char *)node_name) + 1;
2144 2144
2145 2145 if (node_name_len == 1) {
2146 2146 *out_pdu = NULL;
2147 2147 return (0);
2148 2148 }
2149 2149
2150 2150 /* Create SCNReg Message */
2151 2151 flags = ISNS_FLAG_FIRST_PDU |
2152 2152 ISNS_FLAG_LAST_PDU;
2153 2153 pdu_size = isns_create_pdu_header(ISNS_SCN_REG, flags, &pdu);
2154 2154 *xid_p = pdu->xid;
2155 2155
2156 2156 /* Source attribute */
2157 2157 if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID,
2158 2158 node_name_len, node_name, 0) != 0) {
2159 2159 kmem_free(pdu, pdu_size);
2160 2160 *out_pdu = NULL;
2161 2161 return (0);
2162 2162 }
2163 2163
2164 2164 /* Message attribute */
2165 2165 if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID,
2166 2166 node_name_len, node_name, 0) != 0) {
2167 2167 kmem_free(pdu, pdu_size);
2168 2168 *out_pdu = NULL;
2169 2169 return (0);
2170 2170 }
2171 2171
2172 2172 /* Delimiter */
2173 2173 if (isns_add_attr(pdu, pdu_size, ISNS_DELIMITER_ATTR_ID, 0, 0, 0)
2174 2174 != 0) {
2175 2175 kmem_free(pdu, pdu_size);
2176 2176 *out_pdu = NULL;
2177 2177 return (0);
2178 2178 }
2179 2179
2180 2180 /* Operating attribute */
2181 2181 if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_SCN_BITMAP_ATTR_ID,
2182 2182 4,
2183 2183 0,
2184 2184 /*
2185 2185 * Microsoft seems to not differentiate between init and
2186 2186 * target. Hence, it makes no difference to turn on/off
2187 2187 * the initiator/target bit.
2188 2188 */
2189 2189 ISNS_TARGET_SELF_INFO_ONLY |
2190 2190 ISNS_OBJ_REMOVED |
2191 2191 ISNS_OBJ_ADDED |
2192 2192 ISNS_OBJ_UPDATED) != 0) {
2193 2193 kmem_free(pdu, pdu_size);
2194 2194 *out_pdu = NULL;
2195 2195 return (0);
2196 2196 }
2197 2197
2198 2198 *out_pdu = pdu;
2199 2199 return (pdu_size);
2200 2200 }
2201 2201
2202 2202 static
2203 2203 size_t
2204 2204 isns_create_scn_dereg_pdu(
2205 2205 uint8_t *node_name,
2206 2206 uint16_t *xid_p,
2207 2207 isns_pdu_t **out_pdu)
2208 2208 {
2209 2209 isns_pdu_t *pdu;
2210 2210 size_t pdu_size, node_name_len;
2211 2211 uint16_t flags;
2212 2212
2213 2213 ASSERT(node_name != NULL);
2214 2214
2215 2215 /* RFC 4171 section 6.1 - NULLs included in the length. */
2216 2216 node_name_len = strlen((char *)node_name) + 1;
2217 2217
2218 2218 if (node_name_len == 1) {
2219 2219 *out_pdu = NULL;
2220 2220 return (0);
2221 2221 }
2222 2222
2223 2223 /* Create SCNReg Message */
2224 2224 flags = ISNS_FLAG_FIRST_PDU |
2225 2225 ISNS_FLAG_LAST_PDU;
2226 2226 pdu_size = isns_create_pdu_header(ISNS_SCN_DEREG, flags, &pdu);
2227 2227 *xid_p = pdu->xid;
2228 2228
2229 2229 /* Source attribute */
2230 2230 if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID,
2231 2231 node_name_len, node_name, 0) != 0) {
2232 2232 kmem_free(pdu, pdu_size);
2233 2233 *out_pdu = NULL;
2234 2234 return (0);
2235 2235 }
2236 2236
2237 2237 /* Message attribute */
2238 2238 if (isns_add_attr(pdu, pdu_size, ISNS_ISCSI_NAME_ATTR_ID,
2239 2239 node_name_len, node_name, 0) != 0) {
2240 2240 kmem_free(pdu, pdu_size);
2241 2241 *out_pdu = NULL;
2242 2242 return (0);
2243 2243 }
2244 2244
2245 2245 /* Delimiter */
2246 2246 if (isns_add_attr(pdu, pdu_size, ISNS_DELIMITER_ATTR_ID, 0, 0, 0)
2247 2247 != 0) {
2248 2248 kmem_free(pdu, pdu_size);
2249 2249 *out_pdu = NULL;
2250 2250 return (0);
2251 2251 }
2252 2252
2253 2253 /* No operating attribute */
2254 2254
2255 2255 *out_pdu = pdu;
2256 2256 return (pdu_size);
2257 2257 }
2258 2258
2259 2259 static
2260 2260 size_t
2261 2261 isns_create_esi_rsp_pdu(uint32_t rsp_status_code,
2262 2262 isns_pdu_t *esi_pdu,
2263 2263 uint16_t *xid_p,
2264 2264 isns_pdu_t **out_pdu)
2265 2265 {
2266 2266 isns_pdu_t *pdu_p;
2267 2267 uint16_t flags;
2268 2268 uint8_t *payload_ptr;
2269 2269 uint32_t swapped_status_code = htonl(rsp_status_code);
2270 2270 size_t pdu_size, payload_len = 0;
2271 2271
2272 2272 /* Create ESIRsp Message */
2273 2273 flags = ISNS_FLAG_FIRST_PDU |
2274 2274 ISNS_FLAG_LAST_PDU;
2275 2275 pdu_size = isns_create_pdu_header(ISNS_ESI_RSP, flags, &pdu_p);
2276 2276 *xid_p = pdu_p->xid;
2277 2277
2278 2278 payload_len = ntohs(pdu_p->payload_len);
2279 2279
2280 2280 /* Status Code */
2281 2281 payload_ptr = pdu_p->payload + payload_len;
2282 2282 bcopy(&swapped_status_code, payload_ptr, 4);
2283 2283 payload_len += 4;
2284 2284
2285 2285 payload_ptr = pdu_p->payload + payload_len;
2286 2286 if ((esi_pdu->payload_len) < ISNSP_MAX_PAYLOAD_SIZE) {
2287 2287 bcopy(esi_pdu->payload, payload_ptr,
2288 2288 (esi_pdu->payload_len));
2289 2289 payload_len += (esi_pdu->payload_len);
2290 2290 } else {
2291 2291 bcopy(esi_pdu->payload, payload_ptr, ISNSP_MAX_PAYLOAD_SIZE);
2292 2292 payload_len += ISNSP_MAX_PAYLOAD_SIZE;
2293 2293 }
2294 2294 pdu_p->payload_len = htons(payload_len);
2295 2295
2296 2296 /* Delimiter */
2297 2297 if (isns_add_attr(pdu_p, pdu_size, ISNS_DELIMITER_ATTR_ID, 0, 0, 0)
2298 2298 != 0) {
2299 2299 kmem_free(pdu_p, pdu_size);
2300 2300 *out_pdu = NULL;
2301 2301 return (0);
2302 2302 }
2303 2303
2304 2304 *out_pdu = pdu_p;
2305 2305 return (pdu_size);
2306 2306 }
2307 2307
2308 2308 static
2309 2309 size_t
2310 2310 isns_create_scn_rsp_pdu(uint32_t rsp_status_code,
2311 2311 isns_pdu_t *scn_pdu,
2312 2312 uint16_t *xid_p,
2313 2313 isns_pdu_t **out_pdu)
2314 2314 {
2315 2315 isns_pdu_t *pdu_p;
2316 2316 uint16_t flags;
2317 2317 uint8_t *payload_ptr;
2318 2318 uint32_t swapped_status_code = htonl(rsp_status_code);
2319 2319 size_t pdu_size, payload_len = 0;
2320 2320
2321 2321 /* Create SCNRsp Message */
2322 2322 flags = ISNS_FLAG_FIRST_PDU |
2323 2323 ISNS_FLAG_LAST_PDU;
2324 2324 pdu_size = isns_create_pdu_header(ISNS_SCN_RSP, flags, &pdu_p);
2325 2325 *xid_p = pdu_p->xid;
2326 2326
2327 2327 payload_len = ntohs(pdu_p->payload_len);
2328 2328
2329 2329 /* Status Code */
2330 2330 payload_ptr = pdu_p->payload + payload_len;
2331 2331 bcopy(&swapped_status_code, payload_ptr, 4);
2332 2332 payload_len += 4;
2333 2333
2334 2334 payload_ptr = pdu_p->payload + payload_len;
2335 2335 if ((scn_pdu->payload_len) < ISNSP_MAX_PAYLOAD_SIZE) {
2336 2336 bcopy(scn_pdu->payload, payload_ptr,
2337 2337 (scn_pdu->payload_len));
2338 2338 payload_len += (scn_pdu->payload_len);
2339 2339 } else {
2340 2340 bcopy(scn_pdu->payload, payload_ptr, ISNSP_MAX_PAYLOAD_SIZE);
2341 2341 payload_len += ISNSP_MAX_PAYLOAD_SIZE;
2342 2342 }
2343 2343 pdu_p->payload_len = htons(payload_len);
2344 2344
2345 2345 /* Delimiter */
2346 2346 if (isns_add_attr(pdu_p, pdu_size, ISNS_DELIMITER_ATTR_ID, 0, 0, 0)
2347 2347 != 0) {
2348 2348 kmem_free(pdu_p, pdu_size);
2349 2349 *out_pdu = NULL;
2350 2350 return (0);
2351 2351 }
2352 2352
2353 2353 *out_pdu = pdu_p;
2354 2354 return (pdu_size);
2355 2355 }
2356 2356
2357 2357 static
2358 2358 uint32_t
2359 2359 isns_process_dev_attr_reg_rsp(isns_pdu_t *resp_pdu_p)
2360 2360 {
2361 2361 isns_resp_t *resp_p;
2362 2362
2363 2363 if (resp_pdu_p->func_id != ISNS_DEV_ATTR_REG_RSP) {
2364 2364 /* If this happens the iSNS server may have a problem. */
2365 2365 return (ISNS_RSP_MSG_FORMAT_ERROR);
2366 2366 }
2367 2367
2368 2368 /* Check response's status code */
2369 2369 resp_p = (isns_resp_t *)resp_pdu_p->payload;
2370 2370 if (ntohl(resp_p->status) != ISNS_RSP_SUCCESSFUL) {
2371 2371 return (ntohl(resp_p->status));
2372 2372 }
2373 2373
2374 2374 return (ISNS_RSP_SUCCESSFUL);
2375 2375 }
2376 2376
2377 2377 static
2378 2378 uint32_t
2379 2379 isns_process_dev_attr_dereg_rsp(isns_pdu_t *resp_pdu_p)
2380 2380 {
2381 2381 isns_resp_t *resp_p;
2382 2382
2383 2383 if (resp_pdu_p->func_id != ISNS_DEV_DEREG_RSP) {
2384 2384 /* If this happens the iSNS server may have a problem. */
2385 2385 return (ISNS_RSP_MSG_FORMAT_ERROR);
2386 2386 }
2387 2387
2388 2388 /* Check response's status code */
2389 2389 resp_p = (isns_resp_t *)resp_pdu_p->payload;
2390 2390 if (ntohl(resp_p->status) != ISNS_RSP_SUCCESSFUL) {
2391 2391 return (ntohl(resp_p->status));
2392 2392 }
2393 2393
2394 2394 return (ISNS_RSP_SUCCESSFUL);
2395 2395 }
2396 2396
2397 2397 static
2398 2398 uint32_t
2399 2399 isns_process_scn_reg_rsp(isns_pdu_t *resp_pdu_p)
2400 2400 {
2401 2401 isns_resp_t *resp_p;
2402 2402
2403 2403 ASSERT(resp_pdu_p != NULL);
2404 2404 if (resp_pdu_p->func_id != ISNS_SCN_REG_RSP) {
2405 2405 /* If this happens the iSNS server may have a problem. */
2406 2406 return (ISNS_RSP_MSG_FORMAT_ERROR);
2407 2407 }
2408 2408
2409 2409 /* Check response's status code */
2410 2410 resp_p = (isns_resp_t *)resp_pdu_p->payload;
2411 2411 if (ntohl(resp_p->status) != ISNS_RSP_SUCCESSFUL) {
2412 2412 return (ntohl(resp_p->status));
2413 2413 }
2414 2414 return (ISNS_RSP_SUCCESSFUL);
2415 2415 }
2416 2416
2417 2417 static
2418 2418 uint32_t
2419 2419 isns_process_scn_dereg_rsp(isns_pdu_t *resp_pdu_p)
2420 2420 {
2421 2421 isns_resp_t *resp_p;
2422 2422
2423 2423 ASSERT(resp_pdu_p != NULL);
2424 2424 if (resp_pdu_p->func_id != ISNS_SCN_DEREG_RSP) {
2425 2425 /* If this happens the iSNS server may have a problem. */
2426 2426 return (ISNS_RSP_MSG_FORMAT_ERROR);
2427 2427 }
2428 2428
2429 2429 /* Check response's status code */
2430 2430 resp_p = (isns_resp_t *)resp_pdu_p->payload;
2431 2431 if (ntohl(resp_p->status) != ISNS_RSP_SUCCESSFUL) {
2432 2432 return (ntohl(resp_p->status));
2433 2433 }
2434 2434 return (ISNS_RSP_SUCCESSFUL);
2435 2435 }
2436 2436
2437 2437 static
2438 2438 uint32_t
2439 2439 isns_process_dev_attr_qry_target_nodes_pdu(
2440 2440 iscsi_addr_t *isns_server_addr, uint16_t payload_funcId,
2441 2441 isns_resp_t *resp_p, size_t resp_len,
2442 2442 isns_portal_group_list_t **pg_list)
2443 2443 {
2444 2444 boolean_t done_b, found_delimiter_b, target_node_type_b;
2445 2445 int num_of_pgs = 0, pg_sz, idx;
2446 2446 isns_tlv_t *attr_tlv_p;
2447 2447 uint8_t *data_p;
2448 2448 uint32_t len, total_payload_len = 0;
2449 2449 isns_portal_group_t *pg;
2450 2450 uint8_t junk[IPV4_RSVD_BYTES];
2451 2451
2452 2452 *pg_list = NULL;
2453 2453 bzero(junk, IPV4_RSVD_BYTES);
2454 2454
2455 2455 if (payload_funcId != ISNS_DEV_ATTR_QRY_RSP) {
2456 2456 /* If this happens the iSNS server may have a problem. */
2457 2457 return (ISNS_RSP_MSG_FORMAT_ERROR);
2458 2458 }
2459 2459
2460 2460 if (ntohl(resp_p->status) != ISNS_RSP_SUCCESSFUL) {
2461 2461 return (ntohl(resp_p->status));
2462 2462 }
2463 2463
2464 2464 /*
2465 2465 * If payload is smaller than the length of even 1 attribute
2466 2466 * there is something wrong with the PDU.
2467 2467 */
2468 2468 if (resp_len < (ISNS_TLV_ATTR_ID_LEN +
2469 2469 ISNS_TLV_ATTR_LEN_LEN)) {
2470 2470 return (ISNS_RSP_MSG_FORMAT_ERROR);
2471 2471 }
2472 2472
2473 2473 /*
2474 2474 * Expected DevAttrQryRsp message format:
2475 2475 *
2476 2476 * Status Code
2477 2477 * iSCSI Node Type
2478 2478 * Delimiter
2479 2479 * PG iSCSI Name [Optional]
2480 2480 * PG Portal IP Address [Optional]
2481 2481 * PG Portal Port [Optional]
2482 2482 * PG Tag [Optional]
2483 2483 * PG iSCSI Name [Optional]
2484 2484 * PG Portal IP Address [Optional]
2485 2485 * PG Portal Port [Optional]
2486 2486 * PG Tag [Optional]
2487 2487 * .
2488 2488 * .
2489 2489 * .
2490 2490 */
2491 2491 data_p = resp_p->data;
2492 2492 done_b = B_FALSE;
2493 2493 found_delimiter_b = B_FALSE;
2494 2494 num_of_pgs = 0;
2495 2495 total_payload_len = sizeof (resp_p->status);
2496 2496 /* Find out the number of entries retrieved */
2497 2497 while (!done_b) {
2498 2498 attr_tlv_p = (isns_tlv_t *)data_p;
2499 2499 if (ntohl(attr_tlv_p->attr_id) == ISNS_DELIMITER_ATTR_ID) {
2500 2500 if (found_delimiter_b) {
2501 2501 done_b = B_TRUE;
2502 2502 } else {
2503 2503 found_delimiter_b = B_TRUE;
2504 2504 }
2505 2505 } else if (ntohl(attr_tlv_p->attr_id) ==
2506 2506 ISNS_PG_TAG_ATTR_ID) {
2507 2507 if (ntohl(attr_tlv_p->attr_len) > 0) {
2508 2508 /*
2509 2509 * Count only those iSCSI node that have a
2510 2510 * non-NULL PGT value as valid Entity.
2511 2511 * Per rfc4171 section 3.4 - If the PGT value
2512 2512 * registered for a specified Portal and iSCSI
2513 2513 * Node is NULL, or if no PGT value is
2514 2514 * registered, then the Portal does not provide
2515 2515 * access to that iSCSI Node in the Entity.
2516 2516 */
2517 2517 num_of_pgs++;
2518 2518 }
2519 2519 }
2520 2520 len = ntohl(attr_tlv_p->attr_len);
2521 2521
2522 2522 total_payload_len += (ISNS_TLV_ATTR_ID_LEN +
2523 2523 ISNS_TLV_ATTR_LEN_LEN + len);
2524 2524 if (total_payload_len >= resp_len) {
2525 2525 done_b = B_TRUE;
2526 2526 } else {
2527 2527 data_p += (ISNS_TLV_ATTR_ID_LEN +
2528 2528 ISNS_TLV_ATTR_LEN_LEN + len);
2529 2529 }
2530 2530 }
2531 2531
2532 2532 pg_sz = sizeof (isns_portal_group_list_t);
2533 2533 if (num_of_pgs > 0) {
2534 2534 pg_sz += (num_of_pgs - 1) * sizeof (isns_portal_group_t);
2535 2535 }
2536 2536 DTRACE_PROBE1(isns_process_dev_attr_qry_target_nodes_pdu_pg_size,
2537 2537 int, pg_sz);
2538 2538 /*
2539 2539 * Once we passed this point, if for any reason we need to return
2540 2540 * because of a failure, we need to free the memory allocated for
2541 2541 * the pg_list and nullify it.
2542 2542 */
2543 2543 *pg_list = (isns_portal_group_list_t *)kmem_zalloc(pg_sz, KM_SLEEP);
2544 2544 (*pg_list)->pg_out_cnt = 0;
2545 2545
2546 2546 /* Assign the isns_server information to all portal groups */
2547 2547 for (idx = 0; idx < num_of_pgs; idx++) {
2548 2548 pg = &((*pg_list)->pg_list[idx]);
2549 2549 bcopy(&isns_server_addr->a_addr, &pg->isns_server_ip,
2550 2550 sizeof (iscsi_ipaddr_t));
2551 2551 pg->isns_server_port = isns_server_addr->a_port;
2552 2552 }
2553 2553
2554 2554 data_p = resp_p->data;
2555 2555 done_b = B_FALSE;
2556 2556 found_delimiter_b = B_FALSE;
2557 2557 total_payload_len = sizeof (resp_p->status);
2558 2558 while (!done_b) {
2559 2559 attr_tlv_p = (isns_tlv_t *)data_p;
2560 2560 pg = &((*pg_list)->pg_list[(*pg_list)->pg_out_cnt]);
2561 2561 switch (ntohl(attr_tlv_p->attr_id)) {
2562 2562 case ISNS_DELIMITER_ATTR_ID:
2563 2563 if (found_delimiter_b) {
2564 2564 done_b = B_TRUE;
2565 2565 } else {
2566 2566 found_delimiter_b = B_TRUE;
2567 2567 }
2568 2568 break;
2569 2569
2570 2570 case ISNS_PG_ISCSI_NAME_ATTR_ID:
2571 2571 target_node_type_b = B_TRUE;
2572 2572 bcopy(attr_tlv_p->attr_value,
2573 2573 (char *)pg->pg_iscsi_name,
2574 2574 ntohl(attr_tlv_p->attr_len) <
2575 2575 ISCSI_MAX_NAME_LEN ?
2576 2576 ntohl(attr_tlv_p->attr_len) :
2577 2577 ISCSI_MAX_NAME_LEN);
2578 2578
2579 2579 DTRACE_PROBE1(isns_dev_attr_qry_process1,
2580 2580 char *, (char *)pg->pg_iscsi_name);
2581 2581 break;
2582 2582
2583 2583 case ISNS_PG_PORTAL_IP_ADDR_ATTR_ID:
2584 2584 if (target_node_type_b) {
2585 2585 /*
2586 2586 * Section 6.3.1 - The Portal IP Address
2587 2587 * is a 16-byte field that may contain
2588 2588 * an IPv4 or IPv6 address. When this
2589 2589 * field contains an IPv4 address, it
2590 2590 * is stored as an IPv4-mapped IPv6
2591 2591 * address
2592 2592 */
2593 2593 if (ntohl(attr_tlv_p->attr_len) != 16) {
2594 2594 #define STRING_AALR "address attribute length received "
2595 2595 #define STRING_FISE16 "from iSNS server, Expected = 16, "
2596 2596 cmn_err(CE_NOTE, "Wrong IP "
2597 2597 STRING_AALR
2598 2598 STRING_FISE16
2599 2599 "Received = %d",
2600 2600 ntohl(
2601 2601 attr_tlv_p->attr_len));
2602 2602 return (
2603 2603 ISNS_RSP_MSG_FORMAT_ERROR);
2604 2604 #undef STRING_AALR
2605 2605 #undef STRING_FISE16
2606 2606 }
2607 2607
2608 2608 /*
2609 2609 * Section 6.3.1 and RFC 2373 state
2610 2610 * that an IPv4 address will be denoted
2611 2611 * by the 10 top bytes as all zero
2612 2612 * followed by either 2 bytes of
2613 2613 * 0x0000 or 0xFFFF The 0x0000 states
2614 2614 * that the address is is IPv6 capable
2615 2615 * and 0xFFFF states its not capable.
2616 2616 */
2617 2617 if ((bcmp(attr_tlv_p->attr_value, junk,
2618 2618 IPV4_RSVD_BYTES) == 0) &&
2619 2619 (((attr_tlv_p->attr_value[10] ==
2620 2620 0x00) &&
2621 2621 (attr_tlv_p->attr_value[11] ==
2622 2622 0x00)) ||
2623 2623 ((attr_tlv_p->attr_value[10] ==
2624 2624 0xFF) &&
2625 2625 (attr_tlv_p->attr_value[11] ==
2626 2626 0xFF)))) {
2627 2627
2628 2628 /* IPv4 */
2629 2629 bcopy(attr_tlv_p->attr_value +
2630 2630 12, &pg->pg_ip_addr.u_ip4,
2631 2631 sizeof (struct in_addr));
2632 2632 pg->insize =
2633 2633 sizeof (struct in_addr);
2634 2634 } else {
2635 2635 /* IPv6 */
2636 2636 bcopy(attr_tlv_p->attr_value,
2637 2637 &pg->pg_ip_addr.u_ip6,
2638 2638 sizeof (struct in6_addr));
2639 2639 pg->insize =
2640 2640 sizeof (struct in6_addr);
2641 2641 }
2642 2642 }
2643 2643 break;
2644 2644
2645 2645 case ISNS_PG_PORTAL_PORT_ATTR_ID:
2646 2646 if (target_node_type_b) {
2647 2647 pg->pg_port =
2648 2648 ntohl(*(uint32_t *)
2649 2649 (*attr_tlv_p).
2650 2650 attr_value);
2651 2651 }
2652 2652
2653 2653 break;
2654 2654
2655 2655 case ISNS_PG_TAG_ATTR_ID:
2656 2656 if (target_node_type_b) {
2657 2657 pg->pg_tag =
2658 2658 ntohl(*(uint32_t *)
2659 2659 (*attr_tlv_p).
2660 2660 attr_value);
2661 2661 }
2662 2662 target_node_type_b = B_FALSE;
2663 2663 if (ntohl(attr_tlv_p->attr_len) > 0) {
2664 2664 /*
2665 2665 * Only the iSCSI node that has a
2666 2666 * non-NULL PGT value is an valid
2667 2667 * Entity.
2668 2668 */
2669 2669 (*pg_list)->pg_out_cnt++;
2670 2670 }
2671 2671 break;
2672 2672
2673 2673 default:
2674 2674 break;
2675 2675 }
2676 2676
2677 2677 len = ntohl(attr_tlv_p->attr_len);
2678 2678 total_payload_len += (ISNS_TLV_ATTR_ID_LEN +
2679 2679 ISNS_TLV_ATTR_LEN_LEN + len);
2680 2680 if ((total_payload_len >= resp_len) ||
2681 2681 ((*pg_list)->pg_out_cnt == num_of_pgs)) {
2682 2682 done_b = B_TRUE;
2683 2683 } else {
2684 2684 data_p += (ISNS_TLV_ATTR_ID_LEN +
2685 2685 ISNS_TLV_ATTR_LEN_LEN + len);
2686 2686 }
2687 2687 }
2688 2688
2689 2689 return (ISNS_RSP_SUCCESSFUL);
2690 2690 }
2691 2691
2692 2692 /* ARGSUSED */
2693 2693 static
2694 2694 uint32_t
2695 2695 isns_process_esi(isns_pdu_t *esi_pdu_p)
2696 2696 {
2697 2697 /* There's nothing particular to process for ESI. */
2698 2698 return (ISNS_RSP_SUCCESSFUL);
2699 2699 }
2700 2700
2701 2701 static
2702 2702 uint32_t
2703 2703 isns_process_scn(isns_pdu_t *scn_pdu_p, uint8_t *lhba_handle)
2704 2704 {
2705 2705 boolean_t dest_attr_found_b;
2706 2706 boolean_t done_b;
2707 2707 boolean_t scn_type_found_b;
2708 2708 isns_scn_callback_arg_t *scn_args_p;
2709 2709 isns_tlv_t *attr_tlv_p;
2710 2710 uint8_t *data_p;
2711 2711 uint8_t *src_attr;
2712 2712 uint32_t attr_eff_len, normalized_attr_len;
2713 2713 uint32_t scn_type;
2714 2714 uint32_t total_payload_len;
2715 2715 void (*scn_callback_to_use)(void *);
2716 2716
2717 2717 /* get the lhba_handle to use for the call back */
2718 2718 scn_callback_to_use = scn_callback_lookup(lhba_handle);
2719 2719 if (scn_callback_to_use == NULL) {
2720 2720 return (ISNS_RSP_INTERNAL_ERROR);
2721 2721 }
2722 2722
2723 2723 dest_attr_found_b = B_FALSE;
2724 2724 scn_type = 0;
2725 2725 scn_type_found_b = B_FALSE;
2726 2726 data_p = scn_pdu_p->payload;
2727 2727 done_b = B_FALSE;
2728 2728 total_payload_len = 0;
2729 2729 src_attr = (uint8_t *)kmem_zalloc(ISCSI_MAX_NAME_LEN, KM_SLEEP);
2730 2730 /*
2731 2731 * Section 5.6.5.8 states an SCN can have more than one
2732 2732 * source attribute. Process all attributes until we
2733 2733 * each process all the data or encounter the delimiter.
2734 2734 */
2735 2735 while (!done_b) {
2736 2736 attr_tlv_p = (isns_tlv_t *)data_p;
2737 2737
2738 2738 switch (ntohl(attr_tlv_p->attr_id)) {
2739 2739 /* ISNS_ISCSI_NAME_ATTR_ID - attribute name */
2740 2740 case ISNS_ISCSI_NAME_ATTR_ID:
2741 2741 attr_eff_len = strlen(
2742 2742 (char *)attr_tlv_p->attr_value) + 1;
2743 2743 /*
2744 2744 * The attribute length must be 4-byte aligned.
2745 2745 * Section 5.1.3, RFC 4171.
2746 2746 */
2747 2747 normalized_attr_len = (attr_eff_len % 4) == 0 ?
2748 2748 (attr_eff_len) :
2749 2749 (attr_eff_len + (4 - (attr_eff_len % 4)));
2750 2750 if (normalized_attr_len !=
2751 2751 ntohl(attr_tlv_p->attr_len)) {
2752 2752 /* This SCN is bad. */
2753 2753 kmem_free(src_attr, ISCSI_MAX_NAME_LEN);
2754 2754 return (ISNS_RSP_MSG_FORMAT_ERROR);
2755 2755 }
2756 2756
2757 2757 /* Check if this was the Destination Attribute */
2758 2758 if ((dest_attr_found_b == B_TRUE) &&
2759 2759 (scn_type_found_b == B_TRUE)) {
2760 2760 bzero(src_attr, ISCSI_MAX_NAME_LEN);
2761 2761 bcopy(attr_tlv_p->attr_value,
2762 2762 (char *)src_attr,
2763 2763 ntohl(attr_tlv_p->attr_len) <
2764 2764 ISCSI_MAX_NAME_LEN ?
2765 2765 ntohl(attr_tlv_p->attr_len) :
2766 2766 ISCSI_MAX_NAME_LEN);
2767 2767
2768 2768 /* allocate new callback structure */
2769 2769 scn_args_p =
2770 2770 (isns_scn_callback_arg_t *)kmem_zalloc(
2771 2771 sizeof (isns_scn_callback_arg_t),
2772 2772 KM_SLEEP);
2773 2773 scn_args_p->scn_type = ntohl(scn_type);
2774 2774 bcopy(src_attr, scn_args_p->source_key_attr,
2775 2775 sizeof (scn_args_p->source_key_attr));
2776 2776
2777 2777 /* Dispatch the callback to process the SCN */
2778 2778 mutex_enter(&scn_taskq_mutex);
2779 2779 if (scn_taskq != NULL) {
2780 2780 (void) ddi_taskq_dispatch(scn_taskq,
2781 2781 scn_callback_to_use,
2782 2782 scn_args_p, DDI_SLEEP);
2783 2783 }
2784 2784 mutex_exit(&scn_taskq_mutex);
2785 2785 } else {
2786 2786 /* Skip Destination Attribute */
2787 2787 dest_attr_found_b = B_TRUE;
2788 2788 }
2789 2789 break;
2790 2790
2791 2791 /* ISNS_ISCSI_SCN_BITMAP_ATTR_ID - change type */
2792 2792 case ISNS_ISCSI_SCN_BITMAP_ATTR_ID:
2793 2793 /*
2794 2794 * Determine the type of action to take for this SCN.
2795 2795 */
2796 2796 scn_type_found_b = B_TRUE;
2797 2797 bcopy(&(attr_tlv_p->attr_value), &scn_type, 4);
2798 2798 break;
2799 2799
2800 2800 /* ISNS_DELIMITER_ATTR_ID - end of the payload of a message */
2801 2801 case ISNS_DELIMITER_ATTR_ID:
2802 2802 done_b = B_TRUE;
2803 2803 break;
2804 2804 }
2805 2805
2806 2806 if (done_b == B_FALSE) {
2807 2807 total_payload_len += ntohl(attr_tlv_p->attr_len) +
2808 2808 ISNS_TLV_ATTR_ID_LEN + ISNS_TLV_ATTR_LEN_LEN;
2809 2809 if ((total_payload_len >= scn_pdu_p->payload_len) ||
2810 2810 (total_payload_len > ISNSP_MAX_PAYLOAD_SIZE)) {
2811 2811 /* No more Attributes to process */
2812 2812 done_b = B_TRUE;
2813 2813 } else {
2814 2814 if (scn_pdu_p->payload_len -
2815 2815 total_payload_len <=
2816 2816 ISNS_TLV_ATTR_ID_LEN +
2817 2817 ISNS_TLV_ATTR_LEN_LEN) {
2818 2818 /*
2819 2819 * The rest of the data in the PDU
2820 2820 * is less than the size of a valid
2821 2821 * iSNS TLV. This next attribute
2822 2822 * probably spans across the PDU
2823 2823 * boundary. For now, do not
2824 2824 * process it further.
2825 2825 */
2826 2826 done_b = B_TRUE;
2827 2827 } else {
2828 2828 /* Advance to the next Attribute */
2829 2829 data_p += (ISNS_TLV_ATTR_ID_LEN +
2830 2830 ISNS_TLV_ATTR_LEN_LEN +
2831 2831 ntohl(attr_tlv_p->attr_len));
2832 2832 }
2833 2833 }
2834 2834 }
2835 2835 }
2836 2836
2837 2837 kmem_free(src_attr, ISCSI_MAX_NAME_LEN);
2838 2838 return (ISNS_RSP_SUCCESSFUL);
2839 2839 }
2840 2840
2841 2841 static
2842 2842 size_t
2843 2843 isns_create_pdu_header(uint16_t func_id, uint16_t flags, isns_pdu_t **pdu)
2844 2844 {
2845 2845 /*
2846 2846 * It should be ok to assume ISNSP_MAX_PDU_SIZE is large enough
2847 2847 * since we are creating our own PDU which is fully under our control.
2848 2848 */
2849 2849 size_t pdu_size = ISNSP_MAX_PDU_SIZE;
2850 2850
2851 2851 *pdu = (isns_pdu_t *)kmem_zalloc(pdu_size, KM_SLEEP);
2852 2852 (void) memset((*pdu), 0, pdu_size);
2853 2853 (*pdu)->version = htons((uint16_t)ISNSP_VERSION);
2854 2854 (*pdu)->func_id = htons((uint16_t)func_id);
2855 2855 (*pdu)->payload_len = htons(0);
2856 2856 (*pdu)->flags = htons((uint16_t)(flags | ISNS_FLAG_CLIENT));
2857 2857 (*pdu)->xid = htons(create_xid());
2858 2858 (*pdu)->seq = htons(0);
2859 2859
2860 2860 return (pdu_size);
2861 2861 }
2862 2862
2863 2863 static
2864 2864 int
2865 2865 isns_add_attr(isns_pdu_t *pdu,
2866 2866 size_t max_pdu_size,
2867 2867 uint32_t attr_id,
2868 2868 uint32_t attr_len,
2869 2869 void *attr_data,
2870 2870 uint32_t attr_numeric_data)
2871 2871 {
2872 2872 isns_tlv_t *attr_tlv;
2873 2873 uint8_t *payload_ptr;
2874 2874 uint16_t payload_len;
2875 2875 uint32_t normalized_attr_len;
2876 2876 uint64_t attr_tlv_len;
2877 2877
2878 2878 /* The attribute length must be 4-byte aligned. Section 5.1.3. */
2879 2879 normalized_attr_len = (attr_len % 4) == 0 ? (attr_len) :
2880 2880 (attr_len + (4 - (attr_len % 4)));
2881 2881 attr_tlv_len = ISNS_TLV_ATTR_ID_LEN
2882 2882 + ISNS_TLV_ATTR_LEN_LEN
2883 2883 + normalized_attr_len;
2884 2884 /* Check if we are going to exceed the maximum PDU length. */
2885 2885 payload_len = ntohs(pdu->payload_len);
2886 2886 if ((payload_len + attr_tlv_len) > max_pdu_size) {
2887 2887 return (1);
2888 2888 }
2889 2889
2890 2890 attr_tlv = (isns_tlv_t *)kmem_zalloc(attr_tlv_len, KM_SLEEP);
2891 2891
2892 2892 attr_tlv->attr_id = htonl(attr_id);
2893 2893
2894 2894 switch (attr_id) {
2895 2895 case ISNS_DELIMITER_ATTR_ID:
2896 2896 break;
2897 2897
2898 2898 case ISNS_PORTAL_IP_ADDR_ATTR_ID:
2899 2899 case ISNS_PG_PORTAL_IP_ADDR_ATTR_ID:
2900 2900 if (attr_numeric_data == sizeof (in_addr_t)) {
2901 2901 /* IPv4 */
2902 2902 attr_tlv->attr_value[10] = 0xFF;
2903 2903 attr_tlv->attr_value[11] = 0xFF;
2904 2904 bcopy(attr_data, ((attr_tlv->attr_value) + 12),
2905 2905 sizeof (in_addr_t));
2906 2906 } else if (attr_numeric_data == sizeof (in6_addr_t)) {
2907 2907 /* IPv6 */
2908 2908 bcopy(attr_data, attr_tlv->attr_value,
2909 2909 sizeof (in6_addr_t));
2910 2910 } else if (attr_numeric_data == 0) {
2911 2911 /* EMPTY */
2912 2912 /* Do nothing */
2913 2913 } else {
2914 2914 kmem_free(attr_tlv, attr_tlv_len);
2915 2915 attr_tlv = NULL;
2916 2916 return (1);
2917 2917 }
2918 2918 break;
2919 2919
2920 2920 case ISNS_EID_ATTR_ID:
2921 2921 case ISNS_ISCSI_NAME_ATTR_ID:
2922 2922 case ISNS_ISCSI_ALIAS_ATTR_ID:
2923 2923 case ISNS_PG_ISCSI_NAME_ATTR_ID:
2924 2924 bcopy((char *)attr_data,
2925 2925 attr_tlv->attr_value,
2926 2926 attr_len);
2927 2927 break;
2928 2928
2929 2929 default:
2930 2930 switch (normalized_attr_len) {
2931 2931 case 0:
2932 2932 break;
2933 2933
2934 2934 case 4:
2935 2935 *(uint32_t *)attr_tlv->attr_value =
2936 2936 htonl(attr_numeric_data);
2937 2937 break;
2938 2938
2939 2939 case 8:
2940 2940 *(uint64_t *)attr_tlv->attr_value =
2941 2941 BE_64((uint64_t)
2942 2942 attr_numeric_data);
2943 2943 break;
2944 2944 }
2945 2945 }
2946 2946
2947 2947 attr_tlv->attr_len = htonl(normalized_attr_len);
2948 2948 /*
2949 2949 * Convert the network byte ordered payload length to host byte
2950 2950 * ordered for local address calculation.
2951 2951 */
2952 2952 payload_len = ntohs(pdu->payload_len);
2953 2953 payload_ptr = pdu->payload + payload_len;
2954 2954 bcopy(attr_tlv, payload_ptr, attr_tlv_len);
2955 2955 payload_len += attr_tlv_len;
2956 2956
2957 2957 /*
2958 2958 * Convert the host byte ordered payload length back to network
2959 2959 * byte ordered - it's now ready to be sent on the wire.
2960 2960 */
2961 2961 pdu->payload_len = htons(payload_len);
2962 2962
2963 2963 kmem_free(attr_tlv, attr_tlv_len);
2964 2964 attr_tlv = NULL;
2965 2965
2966 2966 return (0);
2967 2967 }
2968 2968
2969 2969 /* ARGSUSED */
2970 2970 static
2971 2971 void
2972 2972 isns_service_esi_scn(iscsi_thread_t *thread, void *arg)
2973 2973 {
2974 2974 int clnt_len;
↓ open down ↓ |
1465 lines elided |
↑ open up ↑ |
2975 2975 isns_async_thread_arg_t *larg;
2976 2976 isns_pdu_t *in_pdu;
2977 2977 size_t bytes_received, in_pdu_size = 0;
2978 2978 uint8_t *lhba_handle;
2979 2979 struct sockaddr_in6 t_addr;
2980 2980 socklen_t t_addrlen;
2981 2981 union {
2982 2982 struct sockaddr sin;
2983 2983 struct sockaddr_in s_in4;
2984 2984 struct sockaddr_in6 s_in6;
2985 - } clnt_addr = { 0 };
2985 + } clnt_addr = {{0}};
2986 2986 union {
2987 2987 struct sockaddr_in soa4;
2988 2988 struct sockaddr_in6 soa6;
2989 2989 } local_conn_prop;
2990 2990 void *listening_so, *connecting_so;
2991 2991
2992 2992 larg = (isns_async_thread_arg_t *)arg;
2993 2993 listening_so = larg->listening_so;
2994 2994 lhba_handle = larg->lhba_handle;
2995 2995
2996 2996 /* Done using the argument - free it */
2997 2997 kmem_free(larg, sizeof (*larg));
2998 2998 bzero(&t_addr, sizeof (struct sockaddr_in6));
2999 2999 t_addrlen = sizeof (struct sockaddr_in6);
3000 3000
3001 3001 (void) iscsi_net->getsockname(listening_so,
3002 3002 (struct sockaddr *)&t_addr, &t_addrlen);
3003 3003 if (t_addrlen <= sizeof (local_conn_prop)) {
3004 3004 bcopy(&t_addr, &local_conn_prop, t_addrlen);
3005 3005 }
3006 3006
3007 3007 if (iscsi_net->listen(listening_so, 5) < 0) {
3008 3008 iscsi_net->close(listening_so);
3009 3009 }
3010 3010
3011 3011 for (;;) {
3012 3012 int rval;
3013 3013 isns_pdu_t *out_pdu;
3014 3014 size_t out_pdu_size;
3015 3015
3016 3016 clnt_len = sizeof (clnt_addr);
3017 3017
3018 3018 /* Blocking call */
3019 3019 connecting_so = iscsi_net->accept(
3020 3020 listening_so, &clnt_addr.sin, &clnt_len);
3021 3021
3022 3022 mutex_enter(&esi_scn_thr_mutex);
3023 3023 if (esi_scn_thr_to_shutdown == B_TRUE) {
3024 3024 /* Terminate the thread if instructed to do so. */
3025 3025 mutex_exit(&esi_scn_thr_mutex);
3026 3026 return;
3027 3027 }
3028 3028 mutex_exit(&esi_scn_thr_mutex);
3029 3029
3030 3030 if (connecting_so == NULL) {
3031 3031 iscsi_net->close(listening_so);
3032 3032 continue;
3033 3033 }
3034 3034
3035 3035 bytes_received = isns_rcv_pdu(connecting_so, &in_pdu,
3036 3036 &in_pdu_size);
3037 3037 if (in_pdu == NULL) {
3038 3038 continue;
3039 3039 }
3040 3040 if (bytes_received == 0) {
3041 3041 continue;
3042 3042 }
3043 3043
3044 3044 switch (in_pdu->func_id) {
3045 3045 case ISNS_ESI:
3046 3046 case ISNS_SCN:
3047 3047 if (in_pdu->func_id == ISNS_ESI) {
3048 3048 rval = isns_process_esi(in_pdu);
3049 3049 out_pdu_size = isns_create_esi_rsp_pdu(
3050 3050 rval,
3051 3051 in_pdu,
3052 3052 &xid,
3053 3053 &out_pdu);
3054 3054 } else if (in_pdu->func_id == ISNS_SCN) {
3055 3055 rval = isns_process_scn(in_pdu,
3056 3056 lhba_handle);
3057 3057 out_pdu_size = isns_create_scn_rsp_pdu(
3058 3058 rval,
3059 3059 in_pdu,
3060 3060 &xid,
3061 3061 &out_pdu);
3062 3062 } else {
3063 3063 /*
3064 3064 * Ignore all traffics other than
3065 3065 * ESI and SCN.
3066 3066 */
3067 3067 kmem_free(in_pdu, in_pdu_size);
3068 3068 in_pdu = NULL;
3069 3069 continue;
3070 3070 }
3071 3071
3072 3072 if (out_pdu_size == 0) {
3073 3073 kmem_free(in_pdu, in_pdu_size);
3074 3074 in_pdu = NULL;
3075 3075 continue;
3076 3076 }
3077 3077
3078 3078 (void) isns_send_pdu(connecting_so, out_pdu);
3079 3079
3080 3080 kmem_free(out_pdu, out_pdu_size);
3081 3081 out_pdu = NULL;
3082 3082 kmem_free(in_pdu, in_pdu_size);
3083 3083 in_pdu = NULL;
3084 3084
3085 3085 iscsi_net->close(connecting_so);
3086 3086 break;
3087 3087
3088 3088 default:
3089 3089 kmem_free(in_pdu, in_pdu_size);
3090 3090 in_pdu = NULL;
3091 3091 continue;
3092 3092 }
↓ open down ↓ |
97 lines elided |
↑ open up ↑ |
3093 3093 }
3094 3094 }
3095 3095
3096 3096 static
3097 3097 boolean_t
3098 3098 find_listening_addr(iscsi_addr_t *local_addr, void *listening_so)
3099 3099 {
3100 3100 union {
3101 3101 struct sockaddr_in soa4;
3102 3102 struct sockaddr_in6 soa6;
3103 - } local_conn_prop = { 0 };
3103 + } local_conn_prop = {{0}};
3104 3104
3105 3105 struct sockaddr_in6 t_addr;
3106 3106 socklen_t t_addrlen;
3107 3107
3108 3108 if (local_addr == NULL || listening_so == NULL) {
3109 3109 return (B_FALSE);
3110 3110 }
3111 3111
3112 3112 bzero(&t_addr, sizeof (struct sockaddr_in6));
3113 3113 t_addrlen = sizeof (struct sockaddr_in6);
3114 3114
3115 3115 (void) iscsi_net->getsockname(listening_so, (struct sockaddr *)&t_addr,
3116 3116 &t_addrlen);
3117 3117 if (t_addrlen > sizeof (local_conn_prop)) {
3118 3118 return (B_FALSE);
3119 3119 }
3120 3120 bcopy(&t_addr, &local_conn_prop, t_addrlen);
3121 3121 if (local_conn_prop.soa4.sin_family == AF_INET) {
3122 3122 local_addr->a_addr.i_addr.in4.s_addr =
3123 3123 local_conn_prop.soa4.sin_addr.s_addr;
3124 3124 local_addr->a_addr.i_insize = sizeof (in_addr_t);
3125 3125 } else if (local_conn_prop.soa4.sin_family == AF_INET6) {
3126 3126 /* Currently, IPv6 is not supported */
3127 3127 return (B_FALSE);
3128 3128 } else {
3129 3129 return (B_FALSE);
3130 3130 }
3131 3131
3132 3132 local_addr->a_port = ntohs(local_conn_prop.soa4.sin_port);
3133 3133
3134 3134 return (B_TRUE);
↓ open down ↓ |
21 lines elided |
↑ open up ↑ |
3135 3135 }
3136 3136
3137 3137 static
3138 3138 boolean_t
3139 3139 find_local_portal(iscsi_addr_t *isns_server_addr,
3140 3140 iscsi_addr_t **local_addr, void **listening_so)
3141 3141 {
3142 3142 union {
3143 3143 struct sockaddr_in soa4;
3144 3144 struct sockaddr_in6 soa6;
3145 - } local_conn_prop = { 0 };
3145 + } local_conn_prop = {{0}};
3146 3146 union {
3147 3147 struct sockaddr sin;
3148 3148 struct sockaddr_in s_in4;
3149 3149 struct sockaddr_in6 s_in6;
3150 - } serv_addr = { 0 };
3150 + } serv_addr = {{0}};
3151 3151 void *so;
3152 3152 struct sockaddr_in6 t_addr;
3153 3153 socklen_t t_addrlen;
3154 3154
3155 3155 if (listening_so == NULL) {
3156 3156 return (B_FALSE);
3157 3157 }
3158 3158
3159 3159 if (local_addr != NULL) {
3160 3160 *local_addr = NULL;
3161 3161 }
3162 3162
3163 3163 *listening_so = NULL;
3164 3164 bzero(&t_addr, sizeof (struct sockaddr_in6));
3165 3165 t_addrlen = sizeof (struct sockaddr_in6);
3166 3166
3167 3167 /*
3168 3168 * Determine the local IP address.
3169 3169 */
3170 3170 if (local_addr != NULL) {
3171 3171 so = isns_open(isns_server_addr);
3172 3172 if (so == NULL) {
3173 3173 return (B_FALSE);
3174 3174 }
3175 3175
3176 3176 iscsi_net->getsockname(so,
3177 3177 (struct sockaddr *)&t_addr, &t_addrlen);
3178 3178 if (t_addrlen > sizeof (local_conn_prop)) {
3179 3179 iscsi_net->close(so);
3180 3180 return (B_FALSE);
3181 3181 }
3182 3182
3183 3183 bcopy(&t_addr, &local_conn_prop, t_addrlen);
3184 3184 t_addrlen = sizeof (struct sockaddr_in6);
3185 3185 if (local_conn_prop.soa4.sin_family == AF_INET) {
3186 3186 *local_addr =
3187 3187 (iscsi_addr_t *)kmem_zalloc(sizeof (iscsi_addr_t),
3188 3188 KM_SLEEP);
3189 3189 (*local_addr)->a_addr.i_addr.in4.s_addr =
3190 3190 local_conn_prop.soa4.sin_addr.s_addr;
3191 3191 (*local_addr)->a_addr.i_insize = sizeof (in_addr_t);
3192 3192 } else if (local_conn_prop.soa4.sin_family == AF_INET6) {
3193 3193 /* Currently, IPv6 is not supported */
3194 3194 return (B_FALSE);
3195 3195 } else {
3196 3196 iscsi_net->close(so);
3197 3197 return (B_FALSE);
3198 3198 }
3199 3199
3200 3200 iscsi_net->close(so);
3201 3201 }
3202 3202 /*
3203 3203 * Determine the local IP address. (End)
3204 3204 */
3205 3205
3206 3206 serv_addr.s_in4.sin_family = AF_INET;
3207 3207 /*
3208 3208 * Use INADDR_ANY to accept connections from any of the connected
3209 3209 * networks.
3210 3210 */
3211 3211 serv_addr.s_in4.sin_addr.s_addr = htonl(INADDR_ANY);
3212 3212 /*
3213 3213 * Use port number 0 to allow the system to assign a unique unused
3214 3214 * port.
3215 3215 */
3216 3216 serv_addr.s_in4.sin_port = htons(0);
3217 3217
3218 3218 so = iscsi_net->socket(AF_INET, SOCK_STREAM, 0);
3219 3219 if (so == NULL) {
3220 3220 if (local_addr != NULL && (*local_addr != NULL)) {
3221 3221 kmem_free((*local_addr), sizeof (iscsi_addr_t));
3222 3222 *local_addr = NULL;
3223 3223 }
3224 3224 return (B_FALSE);
3225 3225 }
3226 3226
3227 3227 if (iscsi_net->bind(so, &serv_addr.sin,
3228 3228 sizeof (struct sockaddr), 0, 0) < 0) {
3229 3229 if (local_addr != NULL && (*local_addr != NULL)) {
3230 3230 kmem_free((*local_addr), sizeof (iscsi_addr_t));
3231 3231 *local_addr = NULL;
3232 3232 }
3233 3233 iscsi_net->close(so);
3234 3234 return (B_FALSE);
3235 3235 }
3236 3236
3237 3237 if (local_addr != NULL && (*local_addr != NULL)) {
3238 3238 (void) iscsi_net->getsockname(so, (struct sockaddr *)&t_addr,
3239 3239 &t_addrlen);
3240 3240 if (t_addrlen <= sizeof (local_conn_prop)) {
3241 3241 bcopy(&t_addr, &local_conn_prop, t_addrlen);
3242 3242 (*local_addr)->a_port =
3243 3243 ntohs(local_conn_prop.soa4.sin_port);
3244 3244 } else {
3245 3245 (*local_addr)->a_port = ISNS_DEFAULT_ESI_SCN_PORT;
3246 3246 }
3247 3247 }
3248 3248
3249 3249 *listening_so = so;
3250 3250
3251 3251 return (B_TRUE);
3252 3252 }
3253 3253
3254 3254 /* ARGSUSED */
3255 3255 static
3256 3256 void
3257 3257 (*scn_callback_lookup(uint8_t *lhba_handle))(void *)
3258 3258 {
3259 3259 /*
3260 3260 * When we support multiple HBA instance we will use lhba_handle
3261 3261 * to look up the associated SCN callback. For now, we only support
3262 3262 * one HBA instance therefore we always return the same SCN callback.
3263 3263 */
3264 3264 return (scn_callback_p);
3265 3265 }
3266 3266
3267 3267 static
3268 3268 uint16_t
3269 3269 create_xid()
3270 3270 {
3271 3271 return (xid++ % MAX_XID);
3272 3272 }
3273 3273
3274 3274 static
3275 3275 void
3276 3276 esi_scn_thr_cleanup()
3277 3277 {
3278 3278 boolean_t unblock_esi_scn_thr_b = B_FALSE;
3279 3279 iscsi_addr_t local_addr;
3280 3280
3281 3281 mutex_enter(&esi_scn_thr_mutex);
3282 3282 if (esi_scn_thr_to_shutdown == B_FALSE) {
3283 3283
3284 3284 /* Instruct the ESI/SCN to shut itself down. */
3285 3285 esi_scn_thr_to_shutdown = B_TRUE;
3286 3286 if (instance_listening_so != NULL &&
3287 3287 (find_listening_addr(&local_addr,
3288 3288 instance_listening_so) == B_TRUE)) {
3289 3289 isns_pdu_t *out_pdu;
3290 3290 size_t out_pdu_size;
3291 3291 void *connecting_so;
3292 3292
3293 3293 /*
3294 3294 * Open a connection to the local address and send
3295 3295 * a dummy header to unblock the accept call so that
3296 3296 * the ESI/SCN thread has a chance to terminate
3297 3297 * itself.
3298 3298 */
3299 3299 connecting_so = isns_open(&local_addr);
3300 3300 if (connecting_so == NULL) {
3301 3301 unblock_esi_scn_thr_b = B_FALSE;
3302 3302 esi_scn_thr_to_shutdown = B_FALSE;
3303 3303 } else {
3304 3304 out_pdu_size = isns_create_pdu_header(0,
3305 3305 ISNS_FLAG_FIRST_PDU |
3306 3306 ISNS_FLAG_LAST_PDU,
3307 3307 &out_pdu);
3308 3308 if (isns_send_pdu(connecting_so,
3309 3309 out_pdu) != 0) {
3310 3310 unblock_esi_scn_thr_b = B_FALSE;
3311 3311 esi_scn_thr_to_shutdown = B_FALSE;
3312 3312 } else {
3313 3313 unblock_esi_scn_thr_b = B_TRUE;
3314 3314 }
3315 3315 iscsi_net->close(connecting_so);
3316 3316 kmem_free(out_pdu, out_pdu_size);
3317 3317 out_pdu = NULL;
3318 3318 }
3319 3319 }
3320 3320
3321 3321 if (unblock_esi_scn_thr_b == B_TRUE) {
3322 3322 mutex_exit(&esi_scn_thr_mutex);
3323 3323 (void) iscsi_thread_stop(esi_scn_thr_id);
3324 3324 iscsi_thread_destroy(esi_scn_thr_id);
3325 3325 mutex_enter(&esi_scn_thr_mutex);
3326 3326 esi_scn_thr_id = NULL;
3327 3327
3328 3328 /*
3329 3329 * Shutdown and close the listening socket.
3330 3330 */
3331 3331 iscsi_net->shutdown(instance_listening_so, 2);
3332 3332 iscsi_net->close(instance_listening_so);
3333 3333 instance_listening_so = NULL;
3334 3334 }
3335 3335 }
3336 3336 mutex_exit(&esi_scn_thr_mutex);
3337 3337 }
↓ open down ↓ |
177 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX