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