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
isns_rcv_pdu(int fd,isns_pdu_t ** pdu,size_t * pdu_size,int rcv_timeout)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
isns_send_pdu(int fd,isns_pdu_t * pdu,size_t pl)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
pdu_reset(isns_pdu_t ** rsp,size_t * sz)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
pdu_reset_rsp(isns_pdu_t ** rsp,size_t * pl,size_t * sz)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
pdu_reset_scn(isns_pdu_t ** pdu,size_t * pl,size_t * sz)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
pdu_reset_esi(isns_pdu_t ** pdu,size_t * pl,size_t * sz)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
pdu_update_code(isns_pdu_t * pdu,size_t * pl,int code)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
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*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 *
pdu_get_source(isns_pdu_t * pdu)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 *
pdu_get_key(isns_pdu_t * pdu,size_t * key_len)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 *
pdu_get_operand(isns_pdu_t * pdu,size_t * op_len)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