xref: /titanic_52/usr/src/cmd/isns/isnsd/pdu.c (revision fcf3ce441efd61da9bb2884968af01cb7c1452cc)
1*fcf3ce44SJohn Forte /*
2*fcf3ce44SJohn Forte  * CDDL HEADER START
3*fcf3ce44SJohn Forte  *
4*fcf3ce44SJohn Forte  * The contents of this file are subject to the terms of the
5*fcf3ce44SJohn Forte  * Common Development and Distribution License (the "License").
6*fcf3ce44SJohn Forte  * You may not use this file except in compliance with the License.
7*fcf3ce44SJohn Forte  *
8*fcf3ce44SJohn Forte  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*fcf3ce44SJohn Forte  * or http://www.opensolaris.org/os/licensing.
10*fcf3ce44SJohn Forte  * See the License for the specific language governing permissions
11*fcf3ce44SJohn Forte  * and limitations under the License.
12*fcf3ce44SJohn Forte  *
13*fcf3ce44SJohn Forte  * When distributing Covered Code, include this CDDL HEADER in each
14*fcf3ce44SJohn Forte  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*fcf3ce44SJohn Forte  * If applicable, add the following below this CDDL HEADER, with the
16*fcf3ce44SJohn Forte  * fields enclosed by brackets "[]" replaced with your own identifying
17*fcf3ce44SJohn Forte  * information: Portions Copyright [yyyy] [name of copyright owner]
18*fcf3ce44SJohn Forte  *
19*fcf3ce44SJohn Forte  * CDDL HEADER END
20*fcf3ce44SJohn Forte  */
21*fcf3ce44SJohn Forte 
22*fcf3ce44SJohn Forte /*
23*fcf3ce44SJohn Forte  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24*fcf3ce44SJohn Forte  * Use is subject to license terms.
25*fcf3ce44SJohn Forte  */
26*fcf3ce44SJohn Forte 
27*fcf3ce44SJohn Forte #include <stdio.h>
28*fcf3ce44SJohn Forte #include <stdlib.h>
29*fcf3ce44SJohn Forte #include <string.h>
30*fcf3ce44SJohn Forte #include <strings.h>
31*fcf3ce44SJohn Forte #include <sys/types.h>
32*fcf3ce44SJohn Forte #include <sys/socket.h>
33*fcf3ce44SJohn Forte #include <netinet/in.h>
34*fcf3ce44SJohn Forte #include <arpa/inet.h>
35*fcf3ce44SJohn Forte #include <unistd.h>
36*fcf3ce44SJohn Forte #include <poll.h>
37*fcf3ce44SJohn Forte #include <errno.h>
38*fcf3ce44SJohn Forte 
39*fcf3ce44SJohn Forte #include "isns_server.h"
40*fcf3ce44SJohn Forte #include "isns_log.h"
41*fcf3ce44SJohn Forte #include "isns_pdu.h"
42*fcf3ce44SJohn Forte 
43*fcf3ce44SJohn Forte #define	ISNS_MAX_IOVEC		5
44*fcf3ce44SJohn Forte #define	MAX_XID			(2^16)
45*fcf3ce44SJohn Forte #define	MAX_RCV_RSP_COUNT	10	/* Maximum number of unmatched xid */
46*fcf3ce44SJohn Forte #define	ISNS_RCV_RETRY_MAX	2
47*fcf3ce44SJohn Forte #define	IPV4_RSVD_BYTES		10
48*fcf3ce44SJohn Forte 
49*fcf3ce44SJohn Forte /* externs */
50*fcf3ce44SJohn Forte #ifdef DEBUG
51*fcf3ce44SJohn Forte extern void dump_pdu2(isns_pdu_t *);
52*fcf3ce44SJohn Forte #endif
53*fcf3ce44SJohn Forte 
54*fcf3ce44SJohn Forte /*
55*fcf3ce44SJohn Forte  * local functions.
56*fcf3ce44SJohn Forte  */
57*fcf3ce44SJohn Forte 
58*fcf3ce44SJohn Forte size_t
59*fcf3ce44SJohn Forte isns_rcv_pdu(
60*fcf3ce44SJohn Forte 	int fd,
61*fcf3ce44SJohn Forte 	isns_pdu_t **pdu,
62*fcf3ce44SJohn Forte 	size_t *pdu_size,
63*fcf3ce44SJohn Forte 	int rcv_timeout
64*fcf3ce44SJohn Forte )
65*fcf3ce44SJohn Forte {
66*fcf3ce44SJohn Forte 	int poll_cnt;
67*fcf3ce44SJohn Forte 	struct pollfd fds;
68*fcf3ce44SJohn Forte 	iovec_t iovec[ISNS_MAX_IOVEC];
69*fcf3ce44SJohn Forte 	isns_pdu_t *tmp_pdu_hdr;
70*fcf3ce44SJohn Forte 	ssize_t bytes_received, total_bytes_received = 0;
71*fcf3ce44SJohn Forte 	struct msghdr msg;
72*fcf3ce44SJohn Forte 	uint8_t *tmp_pdu_data;
73*fcf3ce44SJohn Forte 
74*fcf3ce44SJohn Forte 	uint16_t payload_len = 0;
75*fcf3ce44SJohn Forte 
76*fcf3ce44SJohn Forte 	/* initialize to zero */
77*fcf3ce44SJohn Forte 	*pdu = NULL;
78*fcf3ce44SJohn Forte 	*pdu_size = 0;
79*fcf3ce44SJohn Forte 
80*fcf3ce44SJohn Forte 	fds.fd = fd;
81*fcf3ce44SJohn Forte 	fds.events = (POLLIN | POLLRDNORM);
82*fcf3ce44SJohn Forte 	fds.revents = 0;
83*fcf3ce44SJohn Forte 
84*fcf3ce44SJohn Forte 	/* Receive the header first */
85*fcf3ce44SJohn Forte 	tmp_pdu_hdr = (isns_pdu_t *)malloc(ISNSP_HEADER_SIZE);
86*fcf3ce44SJohn Forte 	if (tmp_pdu_hdr == NULL) {
87*fcf3ce44SJohn Forte 		return (0);
88*fcf3ce44SJohn Forte 	}
89*fcf3ce44SJohn Forte 	(void) memset((void *)&tmp_pdu_hdr[0], 0, ISNSP_HEADER_SIZE);
90*fcf3ce44SJohn Forte 	(void) memset((void *)&iovec[0], 0, sizeof (iovec_t));
91*fcf3ce44SJohn Forte 	iovec[0].iov_base = (void *)tmp_pdu_hdr;
92*fcf3ce44SJohn Forte 	iovec[0].iov_len = ISNSP_HEADER_SIZE;
93*fcf3ce44SJohn Forte 
94*fcf3ce44SJohn Forte 	/* Initialization of the message header. */
95*fcf3ce44SJohn Forte 	bzero(&msg, sizeof (msg));
96*fcf3ce44SJohn Forte 	msg.msg_iov = &iovec[0];
97*fcf3ce44SJohn Forte 	/* msg.msg_flags   = MSG_WAITALL, */
98*fcf3ce44SJohn Forte 	msg.msg_iovlen  = 1;
99*fcf3ce44SJohn Forte 
100*fcf3ce44SJohn Forte 	/* Poll and receive the pdu header */
101*fcf3ce44SJohn Forte 	poll_cnt = 0;
102*fcf3ce44SJohn Forte 	do {
103*fcf3ce44SJohn Forte 		int err = poll(&fds, 1, rcv_timeout * 1000);
104*fcf3ce44SJohn Forte 		if (err <= 0) {
105*fcf3ce44SJohn Forte 			poll_cnt ++;
106*fcf3ce44SJohn Forte 		} else {
107*fcf3ce44SJohn Forte 			bytes_received = recvmsg(fd, &msg, MSG_WAITALL);
108*fcf3ce44SJohn Forte 			break;
109*fcf3ce44SJohn Forte 		}
110*fcf3ce44SJohn Forte 	} while (poll_cnt < ISNS_RCV_RETRY_MAX);
111*fcf3ce44SJohn Forte 
112*fcf3ce44SJohn Forte 	if (poll_cnt >= ISNS_RCV_RETRY_MAX) {
113*fcf3ce44SJohn Forte 		free(tmp_pdu_hdr);
114*fcf3ce44SJohn Forte 		return (0);
115*fcf3ce44SJohn Forte 	}
116*fcf3ce44SJohn Forte 
117*fcf3ce44SJohn Forte 	if (bytes_received <= 0) {
118*fcf3ce44SJohn Forte 		free(tmp_pdu_hdr);
119*fcf3ce44SJohn Forte 		return (0);
120*fcf3ce44SJohn Forte 	}
121*fcf3ce44SJohn Forte 
122*fcf3ce44SJohn Forte 	total_bytes_received += bytes_received;
123*fcf3ce44SJohn Forte 
124*fcf3ce44SJohn Forte 	payload_len = ntohs(tmp_pdu_hdr->payload_len);
125*fcf3ce44SJohn Forte 	/* Verify the received payload len is within limit */
126*fcf3ce44SJohn Forte 	if (payload_len > ISNSP_MAX_PAYLOAD_SIZE) {
127*fcf3ce44SJohn Forte 		free(tmp_pdu_hdr);
128*fcf3ce44SJohn Forte 		return (0);
129*fcf3ce44SJohn Forte 	}
130*fcf3ce44SJohn Forte 
131*fcf3ce44SJohn Forte 	/* Proceed to receive additional data. */
132*fcf3ce44SJohn Forte 	tmp_pdu_data = malloc(payload_len);
133*fcf3ce44SJohn Forte 	if (tmp_pdu_data == NULL) {
134*fcf3ce44SJohn Forte 		free(tmp_pdu_hdr);
135*fcf3ce44SJohn Forte 		return (0);
136*fcf3ce44SJohn Forte 	}
137*fcf3ce44SJohn Forte 	(void) memset((void *)&iovec[0], 0, sizeof (iovec_t));
138*fcf3ce44SJohn Forte 	iovec[0].iov_base = (void *)tmp_pdu_data;
139*fcf3ce44SJohn Forte 	iovec[0].iov_len = payload_len;
140*fcf3ce44SJohn Forte 
141*fcf3ce44SJohn Forte 	/* Initialization of the message header. */
142*fcf3ce44SJohn Forte 	bzero(&msg, sizeof (msg));
143*fcf3ce44SJohn Forte 	msg.msg_iov = &iovec[0];
144*fcf3ce44SJohn Forte 	/* msg.msg_flags   = MSG_WAITALL, */
145*fcf3ce44SJohn Forte 	msg.msg_iovlen  = 1;
146*fcf3ce44SJohn Forte 
147*fcf3ce44SJohn Forte 	/* poll and receive the pdu payload */
148*fcf3ce44SJohn Forte 	poll_cnt = 0;
149*fcf3ce44SJohn Forte 	do {
150*fcf3ce44SJohn Forte 		int err = poll(&fds, 1, rcv_timeout * 1000);
151*fcf3ce44SJohn Forte 		if (err <= 0) {
152*fcf3ce44SJohn Forte 			poll_cnt ++;
153*fcf3ce44SJohn Forte 		} else {
154*fcf3ce44SJohn Forte 			bytes_received = recvmsg(fd, &msg, MSG_WAITALL);
155*fcf3ce44SJohn Forte 			break;
156*fcf3ce44SJohn Forte 		}
157*fcf3ce44SJohn Forte 	} while (poll_cnt < ISNS_RCV_RETRY_MAX);
158*fcf3ce44SJohn Forte 
159*fcf3ce44SJohn Forte 	if (poll_cnt >= ISNS_RCV_RETRY_MAX) {
160*fcf3ce44SJohn Forte 		free(tmp_pdu_data);
161*fcf3ce44SJohn Forte 		free(tmp_pdu_hdr);
162*fcf3ce44SJohn Forte 		return (0);
163*fcf3ce44SJohn Forte 	}
164*fcf3ce44SJohn Forte 
165*fcf3ce44SJohn Forte 	if (bytes_received <= 0) {
166*fcf3ce44SJohn Forte 		free(tmp_pdu_data);
167*fcf3ce44SJohn Forte 		free(tmp_pdu_hdr);
168*fcf3ce44SJohn Forte 		return (0);
169*fcf3ce44SJohn Forte 	}
170*fcf3ce44SJohn Forte 
171*fcf3ce44SJohn Forte 	total_bytes_received += bytes_received;
172*fcf3ce44SJohn Forte 
173*fcf3ce44SJohn Forte 	*pdu_size = ISNSP_HEADER_SIZE + payload_len;
174*fcf3ce44SJohn Forte 	(*pdu) = (isns_pdu_t *)malloc(*pdu_size);
175*fcf3ce44SJohn Forte 	if (*pdu == NULL) {
176*fcf3ce44SJohn Forte 		*pdu_size = 0;
177*fcf3ce44SJohn Forte 		free(tmp_pdu_data);
178*fcf3ce44SJohn Forte 		free(tmp_pdu_hdr);
179*fcf3ce44SJohn Forte 		return (0);
180*fcf3ce44SJohn Forte 	}
181*fcf3ce44SJohn Forte 	(*pdu)->version = ntohs(tmp_pdu_hdr->version);
182*fcf3ce44SJohn Forte 	(*pdu)->func_id = ntohs(tmp_pdu_hdr->func_id);
183*fcf3ce44SJohn Forte 	(*pdu)->payload_len = payload_len;
184*fcf3ce44SJohn Forte 	(*pdu)->flags = ntohs(tmp_pdu_hdr->flags);
185*fcf3ce44SJohn Forte 	(*pdu)->xid = ntohs(tmp_pdu_hdr->xid);
186*fcf3ce44SJohn Forte 	(*pdu)->seq = ntohs(tmp_pdu_hdr->seq);
187*fcf3ce44SJohn Forte 	(void) memcpy(&((*pdu)->payload), tmp_pdu_data, payload_len);
188*fcf3ce44SJohn Forte 
189*fcf3ce44SJohn Forte 	free(tmp_pdu_data);
190*fcf3ce44SJohn Forte 	tmp_pdu_data = NULL;
191*fcf3ce44SJohn Forte 	free(tmp_pdu_hdr);
192*fcf3ce44SJohn Forte 	tmp_pdu_hdr = NULL;
193*fcf3ce44SJohn Forte 
194*fcf3ce44SJohn Forte 	return (total_bytes_received);
195*fcf3ce44SJohn Forte }
196*fcf3ce44SJohn Forte 
197*fcf3ce44SJohn Forte int
198*fcf3ce44SJohn Forte isns_send_pdu(
199*fcf3ce44SJohn Forte 	int fd,
200*fcf3ce44SJohn Forte 	isns_pdu_t *pdu,
201*fcf3ce44SJohn Forte 	size_t pl
202*fcf3ce44SJohn Forte )
203*fcf3ce44SJohn Forte {
204*fcf3ce44SJohn Forte 	uint8_t *payload;
205*fcf3ce44SJohn Forte 	uint16_t flags;
206*fcf3ce44SJohn Forte 	uint16_t seq;
207*fcf3ce44SJohn Forte 	iovec_t iovec[ISNS_MAX_IOVEC];
208*fcf3ce44SJohn Forte 	struct msghdr msg = { 0 };
209*fcf3ce44SJohn Forte 
210*fcf3ce44SJohn Forte 	size_t send_len;
211*fcf3ce44SJohn Forte 	ssize_t bytes_sent;
212*fcf3ce44SJohn Forte 
213*fcf3ce44SJohn Forte 
214*fcf3ce44SJohn Forte 	/* Initialization of the message header. */
215*fcf3ce44SJohn Forte 	msg.msg_iov = &iovec[0];
216*fcf3ce44SJohn Forte 	/* msg.msg_flags   = MSG_WAITALL, */
217*fcf3ce44SJohn Forte 	msg.msg_iovlen  = 2;
218*fcf3ce44SJohn Forte 
219*fcf3ce44SJohn Forte 	/*
220*fcf3ce44SJohn Forte 	 * Initialize the pdu flags.
221*fcf3ce44SJohn Forte 	 */
222*fcf3ce44SJohn Forte 	flags = ISNS_FLAG_SERVER;
223*fcf3ce44SJohn Forte 	flags |= ISNS_FLAG_FIRST_PDU;
224*fcf3ce44SJohn Forte 
225*fcf3ce44SJohn Forte 	/*
226*fcf3ce44SJohn Forte 	 * Initialize the pdu sequence id.
227*fcf3ce44SJohn Forte 	 */
228*fcf3ce44SJohn Forte 	seq = 0;
229*fcf3ce44SJohn Forte 
230*fcf3ce44SJohn Forte 	iovec[0].iov_base = (void *)pdu;
231*fcf3ce44SJohn Forte 	iovec[0].iov_len = (ISNSP_HEADER_SIZE);
232*fcf3ce44SJohn Forte 
233*fcf3ce44SJohn Forte 	payload = pdu->payload;
234*fcf3ce44SJohn Forte 
235*fcf3ce44SJohn Forte #ifdef DEBUG
236*fcf3ce44SJohn Forte 	pdu->flags = htons(flags);
237*fcf3ce44SJohn Forte 	pdu->seq = htons(0);
238*fcf3ce44SJohn Forte 	pdu->payload_len = htons(pl);
239*fcf3ce44SJohn Forte 	dump_pdu2(pdu);
240*fcf3ce44SJohn Forte #endif
241*fcf3ce44SJohn Forte 
242*fcf3ce44SJohn Forte 	do {
243*fcf3ce44SJohn Forte 		/* set the payload for sending */
244*fcf3ce44SJohn Forte 		iovec[1].iov_base = (void *)payload;
245*fcf3ce44SJohn Forte 
246*fcf3ce44SJohn Forte 		if (pl > ISNSP_MAX_PAYLOAD_SIZE) {
247*fcf3ce44SJohn Forte 			send_len = ISNSP_MAX_PAYLOAD_SIZE;
248*fcf3ce44SJohn Forte 		} else {
249*fcf3ce44SJohn Forte 			send_len = pl;
250*fcf3ce44SJohn Forte 			/* set the last pdu flag */
251*fcf3ce44SJohn Forte 			flags |= ISNS_FLAG_LAST_PDU;
252*fcf3ce44SJohn Forte 		}
253*fcf3ce44SJohn Forte 		iovec[1].iov_len = send_len;
254*fcf3ce44SJohn Forte 		pdu->payload_len = htons(send_len);
255*fcf3ce44SJohn Forte 
256*fcf3ce44SJohn Forte 		/* set the pdu flags */
257*fcf3ce44SJohn Forte 		pdu->flags = htons(flags);
258*fcf3ce44SJohn Forte 		/* set the pdu sequence id */
259*fcf3ce44SJohn Forte 		pdu->seq = htons(seq);
260*fcf3ce44SJohn Forte 
261*fcf3ce44SJohn Forte 		/* send the packet */
262*fcf3ce44SJohn Forte 		bytes_sent = sendmsg(fd, &msg, 0);
263*fcf3ce44SJohn Forte 
264*fcf3ce44SJohn Forte 		/* get rid of the first pdu flag */
265*fcf3ce44SJohn Forte 		flags &= ~(ISNS_FLAG_FIRST_PDU);
266*fcf3ce44SJohn Forte 
267*fcf3ce44SJohn Forte 		/* next part of payload */
268*fcf3ce44SJohn Forte 		payload += send_len;
269*fcf3ce44SJohn Forte 		pl -= send_len;
270*fcf3ce44SJohn Forte 
271*fcf3ce44SJohn Forte 		/* add the length of header for verification */
272*fcf3ce44SJohn Forte 		send_len += ISNSP_HEADER_SIZE;
273*fcf3ce44SJohn Forte 
274*fcf3ce44SJohn Forte 		/* increase the sequence id by one */
275*fcf3ce44SJohn Forte 		seq ++;
276*fcf3ce44SJohn Forte 	} while (bytes_sent == send_len && pl > 0);
277*fcf3ce44SJohn Forte 
278*fcf3ce44SJohn Forte 	if (bytes_sent == send_len) {
279*fcf3ce44SJohn Forte 		return (0);
280*fcf3ce44SJohn Forte 	} else {
281*fcf3ce44SJohn Forte 		isnslog(LOG_DEBUG, "isns_send_pdu", "sending pdu failed.");
282*fcf3ce44SJohn Forte 		return (-1);
283*fcf3ce44SJohn Forte 	}
284*fcf3ce44SJohn Forte }
285*fcf3ce44SJohn Forte 
286*fcf3ce44SJohn Forte #define	RSP_PDU_FRAG_SZ	(ISNSP_MAX_PDU_SIZE / 10)
287*fcf3ce44SJohn Forte static int
288*fcf3ce44SJohn Forte pdu_reset(
289*fcf3ce44SJohn Forte 	isns_pdu_t **rsp,
290*fcf3ce44SJohn Forte 	size_t *sz
291*fcf3ce44SJohn Forte )
292*fcf3ce44SJohn Forte {
293*fcf3ce44SJohn Forte 	int ec = 0;
294*fcf3ce44SJohn Forte 
295*fcf3ce44SJohn Forte 	if (*rsp == NULL) {
296*fcf3ce44SJohn Forte 		*rsp = (isns_pdu_t *)malloc(RSP_PDU_FRAG_SZ);
297*fcf3ce44SJohn Forte 		if (*rsp != NULL) {
298*fcf3ce44SJohn Forte 			*sz = RSP_PDU_FRAG_SZ;
299*fcf3ce44SJohn Forte 		} else {
300*fcf3ce44SJohn Forte 			ec = ISNS_RSP_INTERNAL_ERROR;
301*fcf3ce44SJohn Forte 		}
302*fcf3ce44SJohn Forte 	}
303*fcf3ce44SJohn Forte 
304*fcf3ce44SJohn Forte 	return (ec);
305*fcf3ce44SJohn Forte }
306*fcf3ce44SJohn Forte 
307*fcf3ce44SJohn Forte int
308*fcf3ce44SJohn Forte pdu_reset_rsp(
309*fcf3ce44SJohn Forte 	isns_pdu_t **rsp,
310*fcf3ce44SJohn Forte 	size_t *pl,
311*fcf3ce44SJohn Forte 	size_t *sz
312*fcf3ce44SJohn Forte )
313*fcf3ce44SJohn Forte {
314*fcf3ce44SJohn Forte 	int ec = pdu_reset(rsp, sz);
315*fcf3ce44SJohn Forte 
316*fcf3ce44SJohn Forte 	if (ec == 0) {
317*fcf3ce44SJohn Forte 		/* leave space for status code */
318*fcf3ce44SJohn Forte 		*pl = 4;
319*fcf3ce44SJohn Forte 	}
320*fcf3ce44SJohn Forte 
321*fcf3ce44SJohn Forte 	return (ec);
322*fcf3ce44SJohn Forte }
323*fcf3ce44SJohn Forte 
324*fcf3ce44SJohn Forte int
325*fcf3ce44SJohn Forte pdu_reset_scn(
326*fcf3ce44SJohn Forte 	isns_pdu_t **pdu,
327*fcf3ce44SJohn Forte 	size_t *pl,
328*fcf3ce44SJohn Forte 	size_t *sz
329*fcf3ce44SJohn Forte )
330*fcf3ce44SJohn Forte {
331*fcf3ce44SJohn Forte 	int ec = pdu_reset(pdu, sz);
332*fcf3ce44SJohn Forte 
333*fcf3ce44SJohn Forte 	if (ec == 0) {
334*fcf3ce44SJohn Forte 		*pl = 0;
335*fcf3ce44SJohn Forte 	}
336*fcf3ce44SJohn Forte 
337*fcf3ce44SJohn Forte 	return (ec);
338*fcf3ce44SJohn Forte }
339*fcf3ce44SJohn Forte 
340*fcf3ce44SJohn Forte int
341*fcf3ce44SJohn Forte pdu_reset_esi(
342*fcf3ce44SJohn Forte 	isns_pdu_t **pdu,
343*fcf3ce44SJohn Forte 	size_t *pl,
344*fcf3ce44SJohn Forte 	size_t *sz
345*fcf3ce44SJohn Forte )
346*fcf3ce44SJohn Forte {
347*fcf3ce44SJohn Forte 	return (pdu_reset_scn(pdu, pl, sz));
348*fcf3ce44SJohn Forte }
349*fcf3ce44SJohn Forte 
350*fcf3ce44SJohn Forte int
351*fcf3ce44SJohn Forte pdu_update_code(
352*fcf3ce44SJohn Forte 	isns_pdu_t *pdu,
353*fcf3ce44SJohn Forte 	size_t *pl,
354*fcf3ce44SJohn Forte 	int code
355*fcf3ce44SJohn Forte )
356*fcf3ce44SJohn Forte {
357*fcf3ce44SJohn Forte 	isns_resp_t *resp;
358*fcf3ce44SJohn Forte 
359*fcf3ce44SJohn Forte 	resp = (isns_resp_t *)pdu->payload;
360*fcf3ce44SJohn Forte 
361*fcf3ce44SJohn Forte 	/* reset the payload length */
362*fcf3ce44SJohn Forte 	if (code != ISNS_RSP_SUCCESSFUL || *pl == 0) {
363*fcf3ce44SJohn Forte 		*pl = 4;
364*fcf3ce44SJohn Forte 	}
365*fcf3ce44SJohn Forte 
366*fcf3ce44SJohn Forte 	resp->status = htonl(code);
367*fcf3ce44SJohn Forte 
368*fcf3ce44SJohn Forte 	return (0);
369*fcf3ce44SJohn Forte }
370*fcf3ce44SJohn Forte 
371*fcf3ce44SJohn Forte int
372*fcf3ce44SJohn Forte pdu_add_tlv(
373*fcf3ce44SJohn Forte 	isns_pdu_t **pdu,
374*fcf3ce44SJohn Forte 	size_t *pl,
375*fcf3ce44SJohn Forte 	size_t *sz,
376*fcf3ce44SJohn Forte 	uint32_t attr_id,
377*fcf3ce44SJohn Forte 	uint32_t attr_len,
378*fcf3ce44SJohn Forte 	void *attr_data,
379*fcf3ce44SJohn Forte 	int pflag
380*fcf3ce44SJohn Forte )
381*fcf3ce44SJohn Forte {
382*fcf3ce44SJohn Forte 	int ec = 0;
383*fcf3ce44SJohn Forte 
384*fcf3ce44SJohn Forte 	isns_pdu_t *new_pdu;
385*fcf3ce44SJohn Forte 	size_t new_sz;
386*fcf3ce44SJohn Forte 
387*fcf3ce44SJohn Forte 	isns_tlv_t *attr_tlv;
388*fcf3ce44SJohn Forte 	uint8_t *payload_ptr;
389*fcf3ce44SJohn Forte 	uint32_t normalized_attr_len;
390*fcf3ce44SJohn Forte 	uint64_t attr_tlv_len;
391*fcf3ce44SJohn Forte 
392*fcf3ce44SJohn Forte 	/* The attribute length must be 4-byte aligned. Section 5.1.3. */
393*fcf3ce44SJohn Forte 	normalized_attr_len = (attr_len % 4) == 0 ? (attr_len) :
394*fcf3ce44SJohn Forte 	    (attr_len + (4 - (attr_len % 4)));
395*fcf3ce44SJohn Forte 	attr_tlv_len = ISNS_TLV_ATTR_ID_LEN
396*fcf3ce44SJohn Forte 	    + ISNS_TLV_ATTR_LEN_LEN
397*fcf3ce44SJohn Forte 	    + normalized_attr_len;
398*fcf3ce44SJohn Forte 	/* Check if we are going to exceed the maximum PDU length. */
399*fcf3ce44SJohn Forte 	if ((ISNSP_HEADER_SIZE + *pl + attr_tlv_len) > *sz) {
400*fcf3ce44SJohn Forte 		new_sz = *sz + RSP_PDU_FRAG_SZ;
401*fcf3ce44SJohn Forte 		new_pdu = (isns_pdu_t *)realloc(*pdu, new_sz);
402*fcf3ce44SJohn Forte 		if (new_pdu != NULL) {
403*fcf3ce44SJohn Forte 			*sz = new_sz;
404*fcf3ce44SJohn Forte 			*pdu = new_pdu;
405*fcf3ce44SJohn Forte 		} else {
406*fcf3ce44SJohn Forte 			ec = ISNS_RSP_INTERNAL_ERROR;
407*fcf3ce44SJohn Forte 			return (ec);
408*fcf3ce44SJohn Forte 		}
409*fcf3ce44SJohn Forte 	}
410*fcf3ce44SJohn Forte 
411*fcf3ce44SJohn Forte 	attr_tlv = (isns_tlv_t *)malloc(attr_tlv_len);
412*fcf3ce44SJohn Forte 	(void) memset((void *)attr_tlv, 0, attr_tlv_len);
413*fcf3ce44SJohn Forte 
414*fcf3ce44SJohn Forte 	attr_tlv->attr_id = htonl(attr_id);
415*fcf3ce44SJohn Forte 
416*fcf3ce44SJohn Forte 	switch (attr_id) {
417*fcf3ce44SJohn Forte 		case ISNS_DELIMITER_ATTR_ID:
418*fcf3ce44SJohn Forte 		break;
419*fcf3ce44SJohn Forte 
420*fcf3ce44SJohn Forte 		case ISNS_PORTAL_IP_ADDR_ATTR_ID:
421*fcf3ce44SJohn Forte 		case ISNS_PG_PORTAL_IP_ADDR_ATTR_ID:
422*fcf3ce44SJohn Forte 			/* IPv6 */
423*fcf3ce44SJohn Forte 			ASSERT(attr_len == sizeof (in6_addr_t));
424*fcf3ce44SJohn Forte 			(void) memcpy(attr_tlv->attr_value, attr_data,
425*fcf3ce44SJohn Forte 			    sizeof (in6_addr_t));
426*fcf3ce44SJohn Forte 		break;
427*fcf3ce44SJohn Forte 
428*fcf3ce44SJohn Forte 		case ISNS_EID_ATTR_ID:
429*fcf3ce44SJohn Forte 		case ISNS_ISCSI_NAME_ATTR_ID:
430*fcf3ce44SJohn Forte 		case ISNS_ISCSI_ALIAS_ATTR_ID:
431*fcf3ce44SJohn Forte 		case ISNS_PG_ISCSI_NAME_ATTR_ID:
432*fcf3ce44SJohn Forte 			(void) memcpy(attr_tlv->attr_value, (char *)attr_data,
433*fcf3ce44SJohn Forte 			    attr_len);
434*fcf3ce44SJohn Forte 		break;
435*fcf3ce44SJohn Forte 
436*fcf3ce44SJohn Forte 		default:
437*fcf3ce44SJohn Forte 			if (attr_len == 8) {
438*fcf3ce44SJohn Forte 				if (pflag == 0) {
439*fcf3ce44SJohn Forte 				/*
440*fcf3ce44SJohn Forte 				 * In the iSNS protocol, there is only one
441*fcf3ce44SJohn Forte 				 * attribute ISNS_TIMESTAMP_ATTR_ID which has
442*fcf3ce44SJohn Forte 				 * 8 bytes length integer value and when the
443*fcf3ce44SJohn Forte 				 * function "pdu_add_tlv" is called for adding
444*fcf3ce44SJohn Forte 				 * the timestamp attribute, the value of
445*fcf3ce44SJohn Forte 				 * the attribute is always passed in as its
446*fcf3ce44SJohn Forte 				 * address, i.e. the pflag sets to 1.
447*fcf3ce44SJohn Forte 				 * So it is an error when we get to this code
448*fcf3ce44SJohn Forte 				 * path.
449*fcf3ce44SJohn Forte 				 */
450*fcf3ce44SJohn Forte 					ec = ISNS_RSP_INTERNAL_ERROR;
451*fcf3ce44SJohn Forte 					return (ec);
452*fcf3ce44SJohn Forte 				} else {
453*fcf3ce44SJohn Forte 					*(uint64_t *)attr_tlv->attr_value =
454*fcf3ce44SJohn Forte 					    *(uint64_t *)attr_data;
455*fcf3ce44SJohn Forte 				}
456*fcf3ce44SJohn Forte 			} else if (attr_len == 4) {
457*fcf3ce44SJohn Forte 				if (pflag == 0) {
458*fcf3ce44SJohn Forte 					*(uint32_t *)attr_tlv->attr_value =
459*fcf3ce44SJohn Forte 					    htonl((uint32_t)attr_data);
460*fcf3ce44SJohn Forte 				} else {
461*fcf3ce44SJohn Forte 					*(uint32_t *)attr_tlv->attr_value =
462*fcf3ce44SJohn Forte 					    *(uint32_t *)attr_data;
463*fcf3ce44SJohn Forte 				}
464*fcf3ce44SJohn Forte 			}
465*fcf3ce44SJohn Forte 		break;
466*fcf3ce44SJohn Forte 	}
467*fcf3ce44SJohn Forte 
468*fcf3ce44SJohn Forte 	attr_tlv->attr_len = htonl(normalized_attr_len);
469*fcf3ce44SJohn Forte 	/*
470*fcf3ce44SJohn Forte 	 * Convert the network byte ordered payload length to host byte
471*fcf3ce44SJohn Forte 	 * ordered for local address calculation.
472*fcf3ce44SJohn Forte 	 */
473*fcf3ce44SJohn Forte 	payload_ptr = (*pdu)->payload + *pl;
474*fcf3ce44SJohn Forte 	(void) memcpy(payload_ptr, attr_tlv, attr_tlv_len);
475*fcf3ce44SJohn Forte 	*pl += attr_tlv_len;
476*fcf3ce44SJohn Forte 
477*fcf3ce44SJohn Forte 	/*
478*fcf3ce44SJohn Forte 	 * The payload length might exceed the maximum length of a
479*fcf3ce44SJohn Forte 	 * payload that isnsp allows, we will split the payload and
480*fcf3ce44SJohn Forte 	 * set the size of each payload before they are sent.
481*fcf3ce44SJohn Forte 	 */
482*fcf3ce44SJohn Forte 
483*fcf3ce44SJohn Forte 	free(attr_tlv);
484*fcf3ce44SJohn Forte 	attr_tlv = NULL;
485*fcf3ce44SJohn Forte 
486*fcf3ce44SJohn Forte 	return (ec);
487*fcf3ce44SJohn Forte }
488*fcf3ce44SJohn Forte 
489*fcf3ce44SJohn Forte isns_tlv_t *
490*fcf3ce44SJohn Forte pdu_get_source(
491*fcf3ce44SJohn Forte 	isns_pdu_t *pdu
492*fcf3ce44SJohn Forte )
493*fcf3ce44SJohn Forte {
494*fcf3ce44SJohn Forte 	uint8_t *payload = &pdu->payload[0];
495*fcf3ce44SJohn Forte 	uint16_t payload_len = pdu->payload_len;
496*fcf3ce44SJohn Forte 	isns_tlv_t *tlv = NULL;
497*fcf3ce44SJohn Forte 
498*fcf3ce44SJohn Forte 	/* response code */
499*fcf3ce44SJohn Forte 	if (pdu->func_id & ISNS_RSP_MASK) {
500*fcf3ce44SJohn Forte 		if (payload_len < 4) {
501*fcf3ce44SJohn Forte 			return (NULL);
502*fcf3ce44SJohn Forte 		}
503*fcf3ce44SJohn Forte 		payload += 4;
504*fcf3ce44SJohn Forte 		payload_len -= 4;
505*fcf3ce44SJohn Forte 	}
506*fcf3ce44SJohn Forte 
507*fcf3ce44SJohn Forte 	if (payload_len > 8) {
508*fcf3ce44SJohn Forte 		tlv = (isns_tlv_t *)payload;
509*fcf3ce44SJohn Forte 		tlv->attr_id = ntohl(tlv->attr_id);
510*fcf3ce44SJohn Forte 		tlv->attr_len = ntohl(tlv->attr_len);
511*fcf3ce44SJohn Forte 	}
512*fcf3ce44SJohn Forte 
513*fcf3ce44SJohn Forte 	return (tlv);
514*fcf3ce44SJohn Forte }
515*fcf3ce44SJohn Forte 
516*fcf3ce44SJohn Forte isns_tlv_t *
517*fcf3ce44SJohn Forte pdu_get_key(
518*fcf3ce44SJohn Forte 	isns_pdu_t *pdu,
519*fcf3ce44SJohn Forte 	size_t *key_len
520*fcf3ce44SJohn Forte )
521*fcf3ce44SJohn Forte {
522*fcf3ce44SJohn Forte 	uint8_t *payload = &pdu->payload[0];
523*fcf3ce44SJohn Forte 	uint16_t payload_len = pdu->payload_len;
524*fcf3ce44SJohn Forte 	isns_tlv_t *tlv, *key;
525*fcf3ce44SJohn Forte 
526*fcf3ce44SJohn Forte 	/* reset */
527*fcf3ce44SJohn Forte 	*key_len = 0;
528*fcf3ce44SJohn Forte 
529*fcf3ce44SJohn Forte 	/* response code */
530*fcf3ce44SJohn Forte 	if (pdu->func_id & ISNS_RSP_MASK) {
531*fcf3ce44SJohn Forte 		if (payload_len <= 4) {
532*fcf3ce44SJohn Forte 			return (NULL);
533*fcf3ce44SJohn Forte 		}
534*fcf3ce44SJohn Forte 		payload += 4;
535*fcf3ce44SJohn Forte 		payload_len -= 4;
536*fcf3ce44SJohn Forte 	}
537*fcf3ce44SJohn Forte 
538*fcf3ce44SJohn Forte 	/* skip the soure */
539*fcf3ce44SJohn Forte 	if (payload_len >= 8) {
540*fcf3ce44SJohn Forte 		tlv = (isns_tlv_t *)payload;
541*fcf3ce44SJohn Forte 		payload += (8 + tlv->attr_len);
542*fcf3ce44SJohn Forte 		payload_len -= (8 + tlv->attr_len);
543*fcf3ce44SJohn Forte 		key = (isns_tlv_t *)payload;
544*fcf3ce44SJohn Forte 		while (payload_len >= 8) {
545*fcf3ce44SJohn Forte 			tlv = (isns_tlv_t *)payload;
546*fcf3ce44SJohn Forte 			tlv->attr_id = ntohl(tlv->attr_id);
547*fcf3ce44SJohn Forte 			tlv->attr_len = ntohl(tlv->attr_len);
548*fcf3ce44SJohn Forte 			if (tlv->attr_id == ISNS_DELIMITER_ATTR_ID) {
549*fcf3ce44SJohn Forte 				break;
550*fcf3ce44SJohn Forte 			}
551*fcf3ce44SJohn Forte 			*key_len += (8 + tlv->attr_len);
552*fcf3ce44SJohn Forte 			payload += (8 + tlv->attr_len);
553*fcf3ce44SJohn Forte 			payload_len -= (8 + tlv->attr_len);
554*fcf3ce44SJohn Forte 		}
555*fcf3ce44SJohn Forte 	}
556*fcf3ce44SJohn Forte 
557*fcf3ce44SJohn Forte 	if (*key_len >= 8) {
558*fcf3ce44SJohn Forte 		return (key);
559*fcf3ce44SJohn Forte 	}
560*fcf3ce44SJohn Forte 
561*fcf3ce44SJohn Forte 	return (NULL);
562*fcf3ce44SJohn Forte }
563*fcf3ce44SJohn Forte 
564*fcf3ce44SJohn Forte isns_tlv_t *
565*fcf3ce44SJohn Forte pdu_get_operand(
566*fcf3ce44SJohn Forte 	isns_pdu_t *pdu,
567*fcf3ce44SJohn Forte 	size_t *op_len
568*fcf3ce44SJohn Forte )
569*fcf3ce44SJohn Forte {
570*fcf3ce44SJohn Forte 	uint8_t *payload = &pdu->payload[0];
571*fcf3ce44SJohn Forte 	uint16_t payload_len = pdu->payload_len;
572*fcf3ce44SJohn Forte 	isns_tlv_t *tlv, *op = NULL;
573*fcf3ce44SJohn Forte 	int found_op = 0;
574*fcf3ce44SJohn Forte 
575*fcf3ce44SJohn Forte 	/* reset */
576*fcf3ce44SJohn Forte 	*op_len = 0;
577*fcf3ce44SJohn Forte 
578*fcf3ce44SJohn Forte 	/* response code */
579*fcf3ce44SJohn Forte 	if (pdu->func_id & ISNS_RSP_MASK) {
580*fcf3ce44SJohn Forte 		if (payload_len < 4) {
581*fcf3ce44SJohn Forte 			return (NULL);
582*fcf3ce44SJohn Forte 		}
583*fcf3ce44SJohn Forte 		payload += 4;
584*fcf3ce44SJohn Forte 		payload_len -= 4;
585*fcf3ce44SJohn Forte 	}
586*fcf3ce44SJohn Forte 
587*fcf3ce44SJohn Forte 	/* tlvs */
588*fcf3ce44SJohn Forte 	while (payload_len >= 8) {
589*fcf3ce44SJohn Forte 		tlv = (isns_tlv_t *)payload;
590*fcf3ce44SJohn Forte 		if (found_op != 0) {
591*fcf3ce44SJohn Forte 			tlv->attr_id = ntohl(tlv->attr_id);
592*fcf3ce44SJohn Forte 			tlv->attr_len = ntohl(tlv->attr_len);
593*fcf3ce44SJohn Forte 			payload += (8 + tlv->attr_len);
594*fcf3ce44SJohn Forte 			payload_len -= (8 + tlv->attr_len);
595*fcf3ce44SJohn Forte 		} else {
596*fcf3ce44SJohn Forte 			payload += (8 + tlv->attr_len);
597*fcf3ce44SJohn Forte 			payload_len -= (8 + tlv->attr_len);
598*fcf3ce44SJohn Forte 			if (tlv->attr_id == ISNS_DELIMITER_ATTR_ID) {
599*fcf3ce44SJohn Forte 				/* found it */
600*fcf3ce44SJohn Forte 				op = (isns_tlv_t *)payload;
601*fcf3ce44SJohn Forte 				*op_len = payload_len;
602*fcf3ce44SJohn Forte 				found_op = 1;
603*fcf3ce44SJohn Forte 			}
604*fcf3ce44SJohn Forte 		}
605*fcf3ce44SJohn Forte 	}
606*fcf3ce44SJohn Forte 
607*fcf3ce44SJohn Forte 	if (*op_len >= 8) {
608*fcf3ce44SJohn Forte 		return (op);
609*fcf3ce44SJohn Forte 	}
610*fcf3ce44SJohn Forte 
611*fcf3ce44SJohn Forte 	return (NULL);
612*fcf3ce44SJohn Forte }
613