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.
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.
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]
23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
27 #include <sys/cpuvar.h>
28 #include <sys/types.h>
32 #include <sys/sunddi.h>
33 #include <sys/modctl.h>
34 #include <sys/sysmacros.h>
35 #include <sys/socket.h>
36 #include <sys/strsubr.h>
38 #include <sys/nvpair.h>
41 #include <sys/stmf_ioctl.h>
42 #include <sys/portif.h>
43 #include <sys/idm/idm.h>
44 #include <sys/idm/idm_conn_sm.h>
45 #include <sys/idm/idm_text.h>
46 #include <sys/idm/idm_so.h>
48 #include "iscsit_isns.h"
51 #define IPADDRSTRLEN INET6_ADDRSTRLEN /* space for ipaddr string */
52 #define PORTALSTRLEN (IPADDRSTRLEN+16) /* add space for :port,tag */
55 iscsit_text_cmd_fini(iscsit_conn_t
*ict
);
58 * The kernel inet_ntop() function formats ipv4 address fields with
59 * leading zeros which the win2k initiator interprets as octal.
63 iscsit_v4_ntop(struct in_addr
*in
, char a
[], int size
)
65 unsigned char *p
= (unsigned char *) in
;
67 (void) snprintf(a
, size
, "%d.%d.%d.%d", *p
, *(p
+1), *(p
+2), *(p
+3));
71 iscsit_bump_ttt(iscsit_conn_t
*ict
)
74 * Set the target task tag. The value will be zero when
75 * the connection is created. Increment it and wrap it
76 * back to one if we hit the reserved value.
78 * The TTT is fabricated since there is no real task associated
79 * with a text request. The idm task range is reused here since
80 * no real tasks can be started from a discovery session and
81 * thus no conflicts are possible.
83 if (++ict
->ict_text_rsp_ttt
== IDM_TASKIDS_MAX
)
84 ict
->ict_text_rsp_ttt
= 1;
88 iscsit_text_resp_complete_cb(idm_pdu_t
*pdu
, idm_status_t status
)
90 iscsit_conn_t
*ict
= pdu
->isp_private
;
93 if (status
!= IDM_STATUS_SUCCESS
) {
95 * Could not send the last text response.
96 * Clear any state and bump the TTT so subsequent
97 * requests will not match.
99 iscsit_text_cmd_fini(ict
);
100 iscsit_bump_ttt(ict
);
102 iscsit_conn_rele(ict
);
106 iscsit_text_reject(idm_pdu_t
*req_pdu
, uint8_t reason_code
)
108 iscsit_conn_t
*ict
= req_pdu
->isp_ic
->ic_handle
;
111 * A reject means abandoning this text request.
112 * Cleanup any state from the request and increment the TTT
113 * in case the initiator does not get the reject response
114 * and attempts to resume this request.
116 iscsit_text_cmd_fini(ict
);
117 iscsit_bump_ttt(ict
);
118 iscsit_send_reject(ict
, req_pdu
, reason_code
);
119 idm_pdu_complete(req_pdu
, IDM_STATUS_SUCCESS
);
125 * Add individual <TargetAddress=ipaddr> tuple to the nvlist
128 iscsit_add_portal(struct sockaddr_storage
*ss
, int tag
, nvlist_t
*nv_resp
)
130 char ipaddr
[IPADDRSTRLEN
]; /* ip address string */
131 char ta_value
[PORTALSTRLEN
]; /* target address value */
132 struct sockaddr_in
*sin
;
133 struct sockaddr_in6
*sin6
;
135 switch (ss
->ss_family
) {
137 sin
= (struct sockaddr_in
*)ss
;
138 iscsit_v4_ntop(&sin
->sin_addr
, ipaddr
, sizeof (ipaddr
));
139 (void) snprintf(ta_value
, sizeof (ta_value
), "%s:%d,%d",
140 ipaddr
, ntohs(sin
->sin_port
), tag
);
143 sin6
= (struct sockaddr_in6
*)ss
;
144 (void) inet_ntop(AF_INET6
, &sin6
->sin6_addr
, ipaddr
,
146 (void) snprintf(ta_value
, sizeof (ta_value
), "[%s]:%d,%d",
147 ipaddr
, ntohs(sin6
->sin6_port
), tag
);
153 (void) nvlist_add_string(nv_resp
, "TargetAddress", ta_value
);
157 * Process the special case of the default portal group.
158 * Network addresses are obtained from the network stack and
159 * require some reformatting.
162 iscsit_add_default_portals(iscsit_conn_t
*ict
, idm_addr_list_t
*ipaddr_p
,
167 struct sockaddr_storage ss
;
168 struct sockaddr_in
*sin
;
169 struct sockaddr_in6
*sin6
;
172 * If this request was received on one of the portals,
173 * output that portal first. Most initiators will try to
174 * connect on the first portal in the SendTargets response.
175 * For example, this will avoid the confusing situation of a
176 * discovery coming in on an IB interface and the initiator
177 * then doing the normal login on an ethernet interface.
179 sin
= (struct sockaddr_in
*)&ss
;
180 sin6
= (struct sockaddr_in6
*)&ss
;
181 for (pass
= 1; pass
<= 2; pass
++) {
182 tip
= &ipaddr_p
->al_addrs
[0];
183 for (i
= 0; i
< ipaddr_p
->al_out_cnt
; i
++, tip
++) {
184 /* Convert the address into sockaddr_storage format */
185 switch (tip
->a_addr
.i_insize
) {
186 case sizeof (struct in_addr
):
187 sin
->sin_family
= AF_INET
;
188 sin
->sin_port
= htons(ISCSI_LISTEN_PORT
);
189 sin
->sin_addr
= tip
->a_addr
.i_addr
.in4
;
191 case sizeof (struct in6_addr
):
192 sin6
->sin6_family
= AF_INET6
;
193 sin6
->sin6_port
= htons(ISCSI_LISTEN_PORT
);
194 sin6
->sin6_addr
= tip
->a_addr
.i_addr
.in6
;
203 * On the first pass, skip portals that
204 * do not match the incoming connection.
206 if (idm_ss_compare(&ss
, &ict
->ict_ic
->ic_laddr
,
207 B_TRUE
, B_TRUE
) != 0)
212 * On the second pass, process the
215 if (idm_ss_compare(&ss
, &ict
->ict_ic
->ic_laddr
,
216 B_TRUE
, B_TRUE
) == 0)
221 * Add portal to the response list.
222 * By convention, the default portal group tag == 1
224 iscsit_add_portal(&ss
, 1, nv_resp
);
230 * Process a portal group from the configuration database.
233 iscsit_add_portals(iscsit_conn_t
*ict
, iscsit_tpgt_t
*tpg_list
,
237 iscsit_portal_t
*portal
, *next_portal
;
239 struct sockaddr_storage
*ss
;
242 * As with the default portal group, output the portal used by
243 * the incoming request first.
245 tpg
= tpg_list
->tpgt_tpg
;
246 for (pass
= 1; pass
<= 2; pass
++) {
247 for (portal
= avl_first(&tpg
->tpg_portal_list
);
249 portal
= next_portal
) {
251 next_portal
= AVL_NEXT(&tpg
->tpg_portal_list
, portal
);
252 ss
= &portal
->portal_addr
;
256 * On the first pass, skip portals that
257 * do not match the incoming connection.
259 if (idm_ss_compare(ss
, &ict
->ict_ic
->ic_laddr
,
260 B_TRUE
, B_TRUE
) != 0)
265 * On the second pass, process the
268 if (idm_ss_compare(ss
, &ict
->ict_ic
->ic_laddr
,
269 B_TRUE
, B_TRUE
) == 0)
273 /* Add portal to the response list */
274 iscsit_add_portal(ss
, tpg_list
->tpgt_tag
, nv_resp
);
280 * Process all the portal groups bound to a particular target.
283 iscsit_add_tpgs(iscsit_conn_t
*ict
, iscsit_tgt_t
*target
,
284 idm_addr_list_t
*ipaddr_p
, nvlist_t
*nv_resp
)
286 iscsit_tpgt_t
*tpg_list
;
289 * Look through the portal groups associated with this target.
291 mutex_enter(&target
->target_mutex
);
292 tpg_list
= avl_first(&target
->target_tpgt_list
);
294 /* check for the default portal group */
295 if (tpg_list
->tpgt_tpg
== iscsit_global
.global_default_tpg
) {
297 * The default portal group is a special case and will
298 * return all reasonable interfaces on this node.
300 * A target cannot be bound to other portal groups
301 * if it is bound to the default portal group.
303 ASSERT(AVL_NEXT(&target
->target_tpgt_list
, tpg_list
) == NULL
);
305 if (ipaddr_p
!= NULL
) {
306 /* convert the ip address list to nvlist format */
307 iscsit_add_default_portals(ict
, ipaddr_p
, nv_resp
);
309 mutex_exit(&target
->target_mutex
);
314 * Not the default portal group - process the user defined tpgs
316 ASSERT(tpg_list
!= NULL
);
317 while (tpg_list
!= NULL
) {
319 ASSERT(tpg_list
->tpgt_tpg
!= iscsit_global
.global_default_tpg
);
322 * Found a defined portal group - add each portal address.
323 * As with the default portal group, make 2 passes over
324 * the addresses in order to output the connection
327 iscsit_add_portals(ict
, tpg_list
, nv_resp
);
329 tpg_list
= AVL_NEXT(&target
->target_tpgt_list
, tpg_list
);
331 mutex_exit(&target
->target_mutex
);
336 * To test with smaller PDUs in order to force multi-PDU responses,
337 * set this value such that: 0 < test_max_len < 8192
339 uint32_t iscsit_text_max_len
= ISCSI_DEFAULT_MAX_RECV_SEG_LEN
;
343 * Format a text response PDU from the text buffer and send it.
346 iscsit_send_next_text_response(iscsit_conn_t
*ict
, idm_pdu_t
*rx_pdu
)
348 iscsi_text_hdr_t
*th_req
= (iscsi_text_hdr_t
*)rx_pdu
->isp_hdr
;
349 iscsi_text_rsp_hdr_t
*th_resp
;
351 uint32_t len
, remainder
, max_len
;
355 max_len
= ISCSI_DEFAULT_MAX_RECV_SEG_LEN
;
357 if (iscsit_text_max_len
> 0 && iscsit_text_max_len
< max_len
)
358 max_len
= iscsit_text_max_len
;
361 remainder
= ict
->ict_text_rsp_valid_len
- ict
->ict_text_rsp_off
;
362 if (remainder
<= max_len
) {
370 * Allocate a PDU and copy in text response buffer
372 resp
= idm_pdu_alloc(sizeof (iscsi_hdr_t
), len
);
373 idm_pdu_init(resp
, ict
->ict_ic
, ict
,
374 iscsit_text_resp_complete_cb
);
375 /* Advance the StatSN for each Text Response sent */
376 resp
->isp_flags
|= IDM_PDU_SET_STATSN
| IDM_PDU_ADVANCE_STATSN
;
377 base
= ict
->ict_text_rsp_buf
+ ict
->ict_text_rsp_off
;
378 bcopy(base
, resp
->isp_data
, len
);
380 * Fill in the response header
382 th_resp
= (iscsi_text_rsp_hdr_t
*)resp
->isp_hdr
;
383 bzero(th_resp
, sizeof (*th_resp
));
384 th_resp
->opcode
= ISCSI_OP_TEXT_RSP
;
385 th_resp
->itt
= th_req
->itt
;
386 hton24(th_resp
->dlength
, len
);
388 th_resp
->flags
= ISCSI_FLAG_FINAL
;
389 th_resp
->ttt
= ISCSI_RSVD_TASK_TAG
;
390 kmem_free(ict
->ict_text_rsp_buf
, ict
->ict_text_rsp_len
);
391 ict
->ict_text_rsp_buf
= NULL
;
392 ict
->ict_text_rsp_len
= 0;
393 ict
->ict_text_rsp_valid_len
= 0;
394 ict
->ict_text_rsp_off
= 0;
396 th_resp
->flags
= ISCSI_FLAG_TEXT_CONTINUE
;
397 th_resp
->ttt
= ict
->ict_text_rsp_ttt
;
398 ict
->ict_text_rsp_off
+= len
;
400 /* Send the response on its way */
401 iscsit_conn_hold(ict
);
404 /* Free the request pdu */
405 idm_pdu_complete(rx_pdu
, IDM_STATUS_SUCCESS
);
409 * Clean-up the text buffer if it exists.
412 iscsit_text_cmd_fini(iscsit_conn_t
*ict
)
414 if (ict
->ict_text_rsp_buf
!= NULL
) {
415 ASSERT(ict
->ict_text_rsp_len
!= 0);
416 kmem_free(ict
->ict_text_rsp_buf
, ict
->ict_text_rsp_len
);
418 ict
->ict_text_rsp_buf
= NULL
;
419 ict
->ict_text_rsp_len
= 0;
420 ict
->ict_text_rsp_valid_len
= 0;
421 ict
->ict_text_rsp_off
= 0;
425 * Process an iSCSI text command.
427 * This code only handles the common case of a text command
428 * containing the single tuple SendTargets=All issued during
429 * a discovery session. The request will always arrive in a
430 * single PDU, but the response may span multiple PDUs if the
431 * configuration is large. I.e. many targets and portals.
433 * The request is checked for correctness and then the response
434 * is generated from the global target into nvlist format. Then
435 * the nvlist is reformatted into idm textbuf format which reflects
436 * the iSCSI defined <name=value> specification. Finally, the
437 * textbuf is sent to the initiator in one or more text response PDUs
440 iscsit_pdu_op_text_cmd(iscsit_conn_t
*ict
, idm_pdu_t
*rx_pdu
)
442 iscsi_text_hdr_t
*th_req
= (iscsi_text_hdr_t
*)rx_pdu
->isp_hdr
;
451 flags
= th_req
->flags
;
452 if ((flags
& ISCSI_FLAG_FINAL
) != ISCSI_FLAG_FINAL
) {
453 /* Cannot handle multi-PDU requests now */
454 iscsit_text_reject(rx_pdu
, ISCSI_REJECT_CMD_NOT_SUPPORTED
);
457 if (th_req
->ttt
!= ISCSI_RSVD_TASK_TAG
) {
459 * This is the initiator acknowledging our last PDU and
460 * indicating it is ready for the next PDU in the sequence.
463 * There can only be one outstanding text request on a
464 * connection. Make sure this one PDU has the current TTT.
466 /* XXX combine the following 3 checks after testing */
467 if (th_req
->ttt
!= ict
->ict_text_rsp_ttt
) {
468 /* Not part of this sequence */
469 iscsit_text_reject(rx_pdu
,
470 ISCSI_REJECT_CMD_NOT_SUPPORTED
);
474 * ITT should match what was saved from first PDU.
476 if (th_req
->itt
!= ict
->ict_text_req_itt
) {
477 /* Not part of this sequence */
478 iscsit_text_reject(rx_pdu
,
479 ISCSI_REJECT_CMD_NOT_SUPPORTED
);
483 * Cannot deal with more key/value pairs now.
485 if (rx_pdu
->isp_datalen
!= 0) {
486 iscsit_text_reject(rx_pdu
,
487 ISCSI_REJECT_CMD_NOT_SUPPORTED
);
490 iscsit_send_next_text_response(ict
, rx_pdu
);
495 * Initiator has started a new text request. Only
496 * one can be active at a time, so abandon any previous
497 * text request on this connection.
499 iscsit_text_cmd_fini(ict
);
501 /* Set the target task tag. */
502 iscsit_bump_ttt(ict
);
504 /* Save the initiator task tag */
505 ict
->ict_text_req_itt
= th_req
->itt
;
508 * Make sure this is a proper SendTargets request
510 textbuf
= (char *)rx_pdu
->isp_data
;
511 textbuflen
= rx_pdu
->isp_datalen
;
512 kv_pair
= "SendTargets=All";
513 if (textbuflen
>= strlen(kv_pair
) &&
514 strcmp(kv_pair
, textbuf
) == 0 &&
515 ict
->ict_op
.op_discovery_session
== B_TRUE
) {
517 * Most common case of SendTargets=All during discovery.
519 idm_addr_list_t
*ipaddr_p
;
520 iscsit_tgt_t
*tgt
, *ntgt
;
524 /* Create an nvlist for response */
525 if (nvlist_alloc(&nv_resp
, 0, KM_SLEEP
) != 0) {
526 iscsit_text_reject(rx_pdu
,
527 ISCSI_REJECT_CMD_NOT_SUPPORTED
);
531 /* Get the list of local interface addresses */
532 ipsize
= idm_get_ipaddr(&ipaddr_p
);
534 /* Add targets to the response list */
535 ISCSIT_GLOBAL_LOCK(RW_READER
);
536 for (tgt
= avl_first(&iscsit_global
.global_target_list
);
537 tgt
!= NULL
; tgt
= ntgt
) {
538 struct sockaddr_storage v4sa
, *sa
;
539 iscsit_tgt_state_t state
;
540 iscsit_portal_t
*portal
;
543 ntgt
= AVL_NEXT(&iscsit_global
.global_target_list
, tgt
);
545 /* Only report online and onlining targets */
546 state
= tgt
->target_state
;
547 if (state
!= TS_ONLINING
&& state
!= TS_ONLINE
&&
548 state
!= TS_STMF_ONLINE
)
553 * - it is bound to default TPG
554 * - one of the addresses of TPGs the target is bound
555 * to matches incoming connection dst address
557 sa
= &ict
->ict_ic
->ic_laddr
;
558 mutex_enter(&tgt
->target_mutex
);
559 tpgt
= avl_first(&tgt
->target_tpgt_list
);
560 if (!(IS_DEFAULT_TPGT(tpgt
))) {
561 portal
= iscsit_tgt_lookup_portal(tgt
, sa
,
563 if (portal
== NULL
&&
564 iscsit_is_v4_mapped(sa
, &v4sa
)) {
565 portal
= iscsit_tgt_lookup_portal(tgt
,
568 if (portal
== NULL
) {
569 mutex_exit(&tgt
->target_mutex
);
572 iscsit_portal_rele(portal
);
573 iscsit_tpgt_rele(tpgt
);
575 mutex_exit(&tgt
->target_mutex
);
577 if (nvlist_add_string(nv_resp
, "TargetName",
578 tgt
->target_name
) == 0) {
579 /* Add the portal groups bound to this target */
580 iscsit_add_tpgs(ict
, tgt
, ipaddr_p
, nv_resp
);
583 ISCSIT_GLOBAL_UNLOCK();
585 kmem_free(ipaddr_p
, ipsize
);
587 /* Convert the response nvlist into an idm text buffer */
591 rc
= idm_nvlist_to_textbuf(nv_resp
, &textbuf
,
592 &textbuflen
, &validlen
);
593 nvlist_free(nv_resp
);
595 if (textbuf
&& textbuflen
)
596 kmem_free(textbuf
, textbuflen
);
597 iscsit_text_reject(rx_pdu
,
598 ISCSI_REJECT_CMD_NOT_SUPPORTED
);
601 ict
->ict_text_rsp_buf
= textbuf
;
602 ict
->ict_text_rsp_len
= textbuflen
;
603 ict
->ict_text_rsp_valid_len
= validlen
;
604 ict
->ict_text_rsp_off
= 0;
605 iscsit_send_next_text_response(ict
, rx_pdu
);
608 * Other cases to handle
610 * SendTargets=<target_name>
612 * SendTargets=<NULL> - assume target name of session
616 iscsit_text_reject(rx_pdu
, ISCSI_REJECT_CMD_NOT_SUPPORTED
);