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