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