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 
26 #include <sys/cpuvar.h>
27 #include <sys/types.h>
28 #include <sys/conf.h>
29 #include <sys/file.h>
30 #include <sys/ddi.h>
31 #include <sys/sunddi.h>
32 #include <sys/modctl.h>
33 #include <sys/sysmacros.h>
34 #include <sys/socket.h>
35 #include <sys/strsubr.h>
36 #include <inet/tcp.h>
37 #include <sys/nvpair.h>
38 
39 #include <sys/stmf.h>
40 #include <sys/stmf_ioctl.h>
41 #include <sys/portif.h>
42 #include <sys/idm/idm.h>
43 #include <sys/idm/idm_conn_sm.h>
44 #include <sys/idm/idm_text.h>
45 #include <sys/idm/idm_so.h>
46 #include <iscsit_isns.h>
47 #include <iscsit.h>
48 
49 #define	IPADDRSTRLEN	INET6_ADDRSTRLEN	/* space for ipaddr string */
50 #define	PORTALSTRLEN	(IPADDRSTRLEN+16)	/* add space for :port,tag */
51 
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 
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
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
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
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
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
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) != 0)
224 					continue;
225 				break;
226 			case 2:
227 				/*
228 				 * On the second pass, process the
229 				 * remaining portals.
230 				 */
231 				if (idm_ss_compare(&ss, &ict->ict_ic->ic_laddr,
232 				    B_TRUE) == 0)
233 					continue;
234 				break;
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
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,
277 				    &ict->ict_ic->ic_laddr, 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,
286 				    &ict->ict_ic->ic_laddr, 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
303 iscsit_add_tpgs(iscsit_conn_t *ict, iscsit_tgt_t *target, nvlist_t *nv_resp)
304 {
305 	iscsit_tpgt_t *tpg_list;
306 	idm_addr_list_t *ipaddr_p;
307 	int ipsize;
308 
309 
310 	/*
311 	 * Look through the portal groups associated with this target.
312 	 */
313 	mutex_enter(&target->target_mutex);
314 	tpg_list = avl_first(&target->target_tpgt_list);
315 
316 	/* check for the default portal group */
317 	if (tpg_list->tpgt_tpg == iscsit_global.global_default_tpg) {
318 		/*
319 		 * The default portal group is a special case and will
320 		 * return all reasonable interfaces on this node.
321 		 *
322 		 * A target cannot be bound to other portal groups
323 		 * if it is bound to the default portal group.
324 		 */
325 		ASSERT(AVL_NEXT(&target->target_tpgt_list, tpg_list) == NULL);
326 
327 		/*
328 		 * get the list of local interface addresses
329 		 */
330 		ipsize = idm_get_ipaddr(&ipaddr_p);
331 		if (ipsize > 0) {
332 			/* convert the ip address list to nvlist format */
333 			iscsit_add_default_portals(ict, ipaddr_p, nv_resp);
334 			kmem_free(ipaddr_p, ipsize);
335 		}
336 		mutex_exit(&target->target_mutex);
337 		return;
338 	}
339 
340 	/*
341 	 * Not the default portal group - process the user defined tpgs
342 	 */
343 	ASSERT(tpg_list != NULL);
344 	while (tpg_list != NULL) {
345 
346 		ASSERT(tpg_list->tpgt_tpg != iscsit_global.global_default_tpg);
347 
348 		/*
349 		 * Found a defined portal group - add each portal address.
350 		 * As with the default portal group, make 2 passes over
351 		 * the addresses in order to output the connection
352 		 * address first.
353 		 */
354 		iscsit_add_portals(ict, tpg_list, nv_resp);
355 
356 		tpg_list = AVL_NEXT(&target->target_tpgt_list, tpg_list);
357 	}
358 	mutex_exit(&target->target_mutex);
359 }
360 
361 #ifdef DEBUG
362 /*
363  * To test with smaller PDUs in order to force multi-PDU responses,
364  * set this value such that: 0 < test_max_len < 8192
365  */
366 uint32_t iscsit_text_max_len = 0;
367 #endif
368 
369 /*
370  * Format a text response PDU from the text buffer and send it.
371  */
372 static void
373 iscsit_send_next_text_response(iscsit_conn_t *ict, idm_pdu_t *rx_pdu)
374 {
375 	iscsi_text_hdr_t *th_req = (iscsi_text_hdr_t *)rx_pdu->isp_hdr;
376 	iscsi_text_rsp_hdr_t *th_resp;
377 	idm_pdu_t	*resp;
378 	uint32_t	len, remainder, max_len;
379 	char 		*base;
380 	int		final;
381 
382 	max_len = ISCSI_DEFAULT_MAX_RECV_SEG_LEN;
383 #ifdef DEBUG
384 	if (iscsit_text_max_len > 0 && iscsit_text_max_len < 8192)
385 		max_len = iscsit_text_max_len;
386 #endif
387 	remainder = ict->ict_text_rsp_valid_len - ict->ict_text_rsp_off;
388 	if (remainder <= max_len) {
389 		len = remainder;
390 		final = 1;
391 	} else {
392 		len = max_len;
393 		final = 0;
394 	}
395 	/*
396 	 * Allocate a PDU and copy in text response buffer
397 	 */
398 	resp = idm_pdu_alloc(sizeof (iscsi_hdr_t), len);
399 	idm_pdu_init(resp, ict->ict_ic, ict, iscsit_text_resp_complete_cb);
400 	base = ict->ict_text_rsp_buf + ict->ict_text_rsp_off;
401 	bcopy(base, resp->isp_data, len);
402 	/*
403 	 * Fill in the response header
404 	 */
405 	th_resp = (iscsi_text_rsp_hdr_t *)resp->isp_hdr;
406 	bzero(th_resp, sizeof (*th_resp));
407 	th_resp->opcode = ISCSI_OP_TEXT_RSP;
408 	th_resp->itt = th_req->itt;
409 	hton24(th_resp->dlength, len);
410 	if (final) {
411 		th_resp->flags = ISCSI_FLAG_FINAL;
412 		th_resp->ttt = ISCSI_RSVD_TASK_TAG;
413 		kmem_free(ict->ict_text_rsp_buf, ict->ict_text_rsp_len);
414 		ict->ict_text_rsp_buf = NULL;
415 		ict->ict_text_rsp_len = 0;
416 		ict->ict_text_rsp_valid_len = 0;
417 		ict->ict_text_rsp_off = 0;
418 	} else {
419 		th_resp->flags = ISCSI_FLAG_TEXT_CONTINUE;
420 		th_resp->ttt = ict->ict_text_rsp_ttt;
421 		ict->ict_text_rsp_off += len;
422 	}
423 	/* Send the response on its way */
424 	iscsit_conn_hold(ict);
425 	iscsit_pdu_tx(resp);
426 	/* Free the request pdu */
427 	idm_pdu_complete(rx_pdu, IDM_STATUS_SUCCESS);
428 }
429 
430 /*
431  * Clean-up the text buffer if it exists.
432  */
433 void
434 iscsit_text_cmd_fini(iscsit_conn_t *ict)
435 {
436 	if (ict->ict_text_rsp_buf != NULL) {
437 		ASSERT(ict->ict_text_rsp_len != 0);
438 		kmem_free(ict->ict_text_rsp_buf, ict->ict_text_rsp_len);
439 	}
440 	ict->ict_text_rsp_buf = NULL;
441 	ict->ict_text_rsp_len = 0;
442 	ict->ict_text_rsp_valid_len = 0;
443 	ict->ict_text_rsp_off = 0;
444 }
445 
446 /*
447  * Process an iSCSI text command.
448  *
449  * This code only handles the common case of a text command
450  * containing the single tuple SendTargets=All issued during
451  * a discovery session. The request will always arrive in a
452  * single PDU, but the response may span multiple PDUs if the
453  * configuration is large. I.e. many targets and portals.
454  *
455  * The request is checked for correctness and then the response
456  * is generated from the global target into nvlist format. Then
457  * the nvlist is reformatted into idm textbuf format which reflects
458  * the iSCSI defined <name=value> specification. Finally, the
459  * textbuf is sent to the initiator in one or more text response PDUs
460  */
461 void
462 iscsit_pdu_op_text_cmd(iscsit_conn_t *ict, idm_pdu_t *rx_pdu)
463 {
464 	iscsi_text_hdr_t *th_req = (iscsi_text_hdr_t *)rx_pdu->isp_hdr;
465 	nvlist_t *nv_resp;
466 	char *kv_pair;
467 	int flags;
468 	char *textbuf;
469 	int textbuflen;
470 	int validlen;
471 	iscsit_tgt_t *target, *next_target;
472 	int rc;
473 
474 	flags =  th_req->flags;
475 	if ((flags & ISCSI_FLAG_FINAL) != ISCSI_FLAG_FINAL) {
476 		/* Cannot handle multi-PDU requests now */
477 		iscsit_text_reject(rx_pdu, ISCSI_REJECT_CMD_NOT_SUPPORTED);
478 		return;
479 	}
480 	if (th_req->ttt != ISCSI_RSVD_TASK_TAG) {
481 		/*
482 		 * This is the initiator acknowledging our last PDU and
483 		 * indicating it is ready for the next PDU in the sequence.
484 		 */
485 		/*
486 		 * There can only be one outstanding text request on a
487 		 * connection. Make sure this one PDU has the current TTT.
488 		 */
489 		/* XXX combine the following 3 checks after testing */
490 		if (th_req->ttt != ict->ict_text_rsp_ttt) {
491 			/* Not part of this sequence */
492 			iscsit_text_reject(rx_pdu,
493 			    ISCSI_REJECT_CMD_NOT_SUPPORTED);
494 			return;
495 		}
496 		/*
497 		 * ITT should match what was saved from first PDU.
498 		 */
499 		if (th_req->itt != ict->ict_text_req_itt) {
500 			/* Not part of this sequence */
501 			iscsit_text_reject(rx_pdu,
502 			    ISCSI_REJECT_CMD_NOT_SUPPORTED);
503 			return;
504 		}
505 		/*
506 		 * Cannot deal with more key/value pairs now.
507 		 */
508 		if (rx_pdu->isp_datalen != 0) {
509 			iscsit_text_reject(rx_pdu,
510 			    ISCSI_REJECT_CMD_NOT_SUPPORTED);
511 			return;
512 		}
513 		iscsit_send_next_text_response(ict, rx_pdu);
514 		return;
515 	}
516 
517 	/*
518 	 * Initiator has started a new text request. Only
519 	 * one can be active at a time, so abandon any previous
520 	 * text request on this connection.
521 	 */
522 	iscsit_text_cmd_fini(ict);
523 
524 	/* Set the target task tag. */
525 	iscsit_bump_ttt(ict);
526 
527 	/* Save the initiator task tag */
528 	ict->ict_text_req_itt = th_req->itt;
529 
530 	/*
531 	 * Make sure this is a proper SendTargets request
532 	 */
533 	textbuf = (char *)rx_pdu->isp_data;
534 	textbuflen = rx_pdu->isp_datalen;
535 	kv_pair = "SendTargets=All";
536 	if (textbuflen >= strlen(kv_pair) &&
537 	    strcmp(kv_pair, textbuf) == 0 &&
538 	    ict->ict_op.op_discovery_session == B_TRUE) {
539 
540 		/*
541 		 * Most common case of SendTargets=All during discovery.
542 		 */
543 		/*
544 		 * Create an nvlist for response.
545 		 */
546 		if (nvlist_alloc(&nv_resp, 0, KM_SLEEP) != 0) {
547 			iscsit_text_reject(rx_pdu,
548 			    ISCSI_REJECT_CMD_NOT_SUPPORTED);
549 			return;
550 		}
551 
552 		/*
553 		 * Add all the targets to the response list.
554 		 */
555 		ISCSIT_GLOBAL_LOCK(RW_READER);
556 		for (target = avl_first(&iscsit_global.global_target_list);
557 		    target != NULL;
558 		    target = next_target) {
559 			char *key, *value;
560 			iscsit_tgt_state_t state;
561 
562 			next_target = AVL_NEXT(
563 			    &iscsit_global.global_target_list, target);
564 
565 			/* only report online and onlining targets */
566 			state = target->target_state;
567 			if (state != TS_ONLINING && state != TS_ONLINE &&
568 			    state != TS_STMF_ONLINE)
569 				continue;
570 
571 			key = "TargetName";
572 			value = target->target_name;
573 			if (nvlist_add_string(nv_resp, key, value) == 0) {
574 				/* add the portal groups bound to this target */
575 				iscsit_add_tpgs(ict, target, nv_resp);
576 			}
577 		}
578 		ISCSIT_GLOBAL_UNLOCK();
579 
580 		/*
581 		 * Convert the response nvlist into an idm text buffer.
582 		 */
583 		textbuf = 0;
584 		textbuflen = 0;
585 		validlen = 0;
586 		rc = idm_nvlist_to_textbuf(nv_resp, &textbuf,
587 		    &textbuflen, &validlen);
588 		nvlist_free(nv_resp);
589 		if (rc != 0) {
590 			if (textbuf && textbuflen)
591 				kmem_free(textbuf, textbuflen);
592 			iscsit_text_reject(rx_pdu,
593 			    ISCSI_REJECT_CMD_NOT_SUPPORTED);
594 			return;
595 		}
596 		ict->ict_text_rsp_buf = textbuf;
597 		ict->ict_text_rsp_len = textbuflen;
598 		ict->ict_text_rsp_valid_len = validlen;
599 		ict->ict_text_rsp_off = 0;
600 		iscsit_send_next_text_response(ict, rx_pdu);
601 	} else {
602 		/*
603 		 * Other cases to handle
604 		 *    Discovery session:
605 		 *	SendTargets=<target_name>
606 		 *    Normal session
607 		 *	SendTargets=<NULL> - assume target name of session
608 		 *    All others
609 		 *	Error
610 		 */
611 		iscsit_text_reject(rx_pdu, ISCSI_REJECT_CMD_NOT_SUPPORTED);
612 		return;
613 	}
614 }
615