1a6d42e7dSPeter Dunlap /*
2a6d42e7dSPeter Dunlap * CDDL HEADER START
3a6d42e7dSPeter Dunlap *
4a6d42e7dSPeter Dunlap * The contents of this file are subject to the terms of the
5a6d42e7dSPeter Dunlap * Common Development and Distribution License (the "License").
6a6d42e7dSPeter Dunlap * You may not use this file except in compliance with the License.
7a6d42e7dSPeter Dunlap *
8a6d42e7dSPeter Dunlap * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9a6d42e7dSPeter Dunlap * or http://www.opensolaris.org/os/licensing.
10a6d42e7dSPeter Dunlap * See the License for the specific language governing permissions
11a6d42e7dSPeter Dunlap * and limitations under the License.
12a6d42e7dSPeter Dunlap *
13a6d42e7dSPeter Dunlap * When distributing Covered Code, include this CDDL HEADER in each
14a6d42e7dSPeter Dunlap * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15a6d42e7dSPeter Dunlap * If applicable, add the following below this CDDL HEADER, with the
16a6d42e7dSPeter Dunlap * fields enclosed by brackets "[]" replaced with your own identifying
17a6d42e7dSPeter Dunlap * information: Portions Copyright [yyyy] [name of copyright owner]
18a6d42e7dSPeter Dunlap *
19a6d42e7dSPeter Dunlap * CDDL HEADER END
20a6d42e7dSPeter Dunlap */
21a6d42e7dSPeter Dunlap /*
22a6d42e7dSPeter Dunlap * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23a6d42e7dSPeter Dunlap * Use is subject to license terms.
24a6d42e7dSPeter Dunlap */
25a6d42e7dSPeter Dunlap
26a6d42e7dSPeter Dunlap #include <sys/ddi.h>
27a6d42e7dSPeter Dunlap #include <sys/sunddi.h>
28a6d42e7dSPeter Dunlap #include <sys/iscsit/iscsi_if.h>
29a6d42e7dSPeter Dunlap #include <sys/md5.h>
30a6d42e7dSPeter Dunlap
31a6d42e7dSPeter Dunlap #include <sys/idm/idm.h>
32a6d42e7dSPeter Dunlap #include <sys/idm/idm_so.h>
33a6d42e7dSPeter Dunlap #include <sys/iscsit/radius_packet.h>
34a6d42e7dSPeter Dunlap #include <sys/iscsit/radius_protocol.h>
35*0f1702c5SYu Xiangning #include <sys/ksocket.h>
36a6d42e7dSPeter Dunlap
37a6d42e7dSPeter Dunlap static void encode_chap_password(int identifier, int chap_passwd_len,
38a6d42e7dSPeter Dunlap uint8_t *chap_passwd, uint8_t *result);
39a6d42e7dSPeter Dunlap
40*0f1702c5SYu Xiangning static size_t iscsit_net_recvmsg(ksocket_t socket, struct msghdr *msg,
41a6d42e7dSPeter Dunlap int timeout);
42a6d42e7dSPeter Dunlap
43a6d42e7dSPeter Dunlap /*
44a6d42e7dSPeter Dunlap * See radius_packet.h.
45a6d42e7dSPeter Dunlap */
46a6d42e7dSPeter Dunlap int
iscsit_snd_radius_request(ksocket_t socket,iscsi_ipaddr_t rsvr_ip_addr,uint32_t rsvr_port,radius_packet_data_t * req_data)47*0f1702c5SYu Xiangning iscsit_snd_radius_request(ksocket_t socket, iscsi_ipaddr_t rsvr_ip_addr,
48a6d42e7dSPeter Dunlap uint32_t rsvr_port, radius_packet_data_t *req_data)
49a6d42e7dSPeter Dunlap {
50a6d42e7dSPeter Dunlap int i; /* Loop counter. */
51a6d42e7dSPeter Dunlap int data_len;
52a6d42e7dSPeter Dunlap int len;
53a6d42e7dSPeter Dunlap ushort_t total_length; /* Has to be 2 octets in size */
54a6d42e7dSPeter Dunlap uint8_t *ptr; /* Pointer to RADIUS packet data */
55a6d42e7dSPeter Dunlap uint8_t *length_ptr; /* Points to the Length field of the */
56a6d42e7dSPeter Dunlap /* packet. */
57a6d42e7dSPeter Dunlap uint8_t *data; /* RADIUS data to be sent */
58a6d42e7dSPeter Dunlap radius_attr_t *req_attr; /* Request attributes */
59a6d42e7dSPeter Dunlap radius_packet_t *packet; /* Outbound RADIUS packet */
60a6d42e7dSPeter Dunlap union {
61a6d42e7dSPeter Dunlap struct sockaddr_in s_in4;
62a6d42e7dSPeter Dunlap struct sockaddr_in6 s_in6;
63a6d42e7dSPeter Dunlap } sa_rsvr; /* Socket address of the server */
64a6d42e7dSPeter Dunlap int err;
65a6d42e7dSPeter Dunlap
66a6d42e7dSPeter Dunlap /*
67a6d42e7dSPeter Dunlap * Create a RADIUS packet with minimal length for now.
68a6d42e7dSPeter Dunlap */
69a6d42e7dSPeter Dunlap total_length = MIN_RAD_PACKET_LEN;
70a6d42e7dSPeter Dunlap data = kmem_zalloc(MAX_RAD_PACKET_LEN, KM_SLEEP);
71a6d42e7dSPeter Dunlap packet = (radius_packet_t *)data;
72a6d42e7dSPeter Dunlap packet->code = req_data->code;
73a6d42e7dSPeter Dunlap packet->identifier = req_data->identifier;
74a6d42e7dSPeter Dunlap bcopy(req_data->authenticator, packet->authenticator,
75a6d42e7dSPeter Dunlap RAD_AUTHENTICATOR_LEN);
76a6d42e7dSPeter Dunlap ptr = packet->data;
77a6d42e7dSPeter Dunlap
78a6d42e7dSPeter Dunlap /* Loop over all attributes of the request. */
79a6d42e7dSPeter Dunlap for (i = 0; i < req_data->num_of_attrs; i++) {
80a6d42e7dSPeter Dunlap if (total_length > MAX_RAD_PACKET_LEN) {
81a6d42e7dSPeter Dunlap /* The packet has exceed its maximum size. */
82a6d42e7dSPeter Dunlap kmem_free(data, MAX_RAD_PACKET_LEN);
83a6d42e7dSPeter Dunlap return (-1);
84a6d42e7dSPeter Dunlap }
85a6d42e7dSPeter Dunlap
86a6d42e7dSPeter Dunlap req_attr = &req_data->attrs[i];
87a6d42e7dSPeter Dunlap *ptr++ = (req_attr->attr_type_code & 0xFF);
88a6d42e7dSPeter Dunlap length_ptr = ptr;
89a6d42e7dSPeter Dunlap /* Length is 2 octets - RFC 2865 section 3 */
90a6d42e7dSPeter Dunlap *ptr++ = 2;
91a6d42e7dSPeter Dunlap total_length += 2;
92a6d42e7dSPeter Dunlap
93a6d42e7dSPeter Dunlap /* If the attribute is CHAP-Password, encode it. */
94a6d42e7dSPeter Dunlap if (req_attr->attr_type_code == RAD_CHAP_PASSWORD) {
95a6d42e7dSPeter Dunlap /*
96a6d42e7dSPeter Dunlap * Identifier plus CHAP response. RFC 2865
97a6d42e7dSPeter Dunlap * section 5.3.
98a6d42e7dSPeter Dunlap */
99a6d42e7dSPeter Dunlap uint8_t encoded_chap_passwd[
100a6d42e7dSPeter Dunlap RAD_CHAP_PASSWD_STR_LEN + RAD_IDENTIFIER_LEN + 1];
101a6d42e7dSPeter Dunlap encode_chap_password(
102a6d42e7dSPeter Dunlap req_data->identifier,
103a6d42e7dSPeter Dunlap req_attr->attr_value_len,
104a6d42e7dSPeter Dunlap req_attr->attr_value,
105a6d42e7dSPeter Dunlap encoded_chap_passwd);
106a6d42e7dSPeter Dunlap
107a6d42e7dSPeter Dunlap req_attr->attr_value_len =
108a6d42e7dSPeter Dunlap RAD_CHAP_PASSWD_STR_LEN + RAD_IDENTIFIER_LEN;
109a6d42e7dSPeter Dunlap
110a6d42e7dSPeter Dunlap bcopy(encoded_chap_passwd,
111a6d42e7dSPeter Dunlap req_attr->attr_value,
112a6d42e7dSPeter Dunlap req_attr->attr_value_len);
113a6d42e7dSPeter Dunlap }
114a6d42e7dSPeter Dunlap
115a6d42e7dSPeter Dunlap len = req_attr->attr_value_len;
116a6d42e7dSPeter Dunlap *length_ptr += len;
117a6d42e7dSPeter Dunlap
118a6d42e7dSPeter Dunlap bcopy(req_attr->attr_value, ptr, req_attr->attr_value_len);
119a6d42e7dSPeter Dunlap ptr += req_attr->attr_value_len;
120a6d42e7dSPeter Dunlap
121a6d42e7dSPeter Dunlap total_length += len;
122a6d42e7dSPeter Dunlap } /* Done looping over all attributes */
123a6d42e7dSPeter Dunlap
124a6d42e7dSPeter Dunlap data_len = total_length;
125a6d42e7dSPeter Dunlap total_length = htons(total_length);
126a6d42e7dSPeter Dunlap bcopy(&total_length, packet->length, sizeof (ushort_t));
127a6d42e7dSPeter Dunlap
128a6d42e7dSPeter Dunlap /*
129a6d42e7dSPeter Dunlap * Send the packet to the RADIUS server.
130a6d42e7dSPeter Dunlap */
131a6d42e7dSPeter Dunlap bzero((char *)&sa_rsvr, sizeof (sa_rsvr));
132a6d42e7dSPeter Dunlap if (rsvr_ip_addr.i_insize == sizeof (in_addr_t)) {
133a6d42e7dSPeter Dunlap
134a6d42e7dSPeter Dunlap /* IPv4 */
135a6d42e7dSPeter Dunlap sa_rsvr.s_in4.sin_family = AF_INET;
136a6d42e7dSPeter Dunlap sa_rsvr.s_in4.sin_addr.s_addr =
137a6d42e7dSPeter Dunlap rsvr_ip_addr.i_addr.in4.s_addr;
138a6d42e7dSPeter Dunlap sa_rsvr.s_in4.sin_port = htons((ushort_t)rsvr_port);
139a6d42e7dSPeter Dunlap
140a6d42e7dSPeter Dunlap err = idm_sosendto(socket, data, data_len,
141a6d42e7dSPeter Dunlap (struct sockaddr *)&sa_rsvr.s_in4,
142a6d42e7dSPeter Dunlap sizeof (struct sockaddr_in));
143a6d42e7dSPeter Dunlap kmem_free(data, MAX_RAD_PACKET_LEN);
144a6d42e7dSPeter Dunlap return (err);
145a6d42e7dSPeter Dunlap } else if (rsvr_ip_addr.i_insize == sizeof (in6_addr_t)) {
146a6d42e7dSPeter Dunlap /* IPv6 */
147a6d42e7dSPeter Dunlap sa_rsvr.s_in6.sin6_family = AF_INET6;
148a6d42e7dSPeter Dunlap bcopy(rsvr_ip_addr.i_addr.in6.s6_addr,
149a6d42e7dSPeter Dunlap sa_rsvr.s_in6.sin6_addr.s6_addr, sizeof (struct in6_addr));
150a6d42e7dSPeter Dunlap sa_rsvr.s_in6.sin6_port = htons((ushort_t)rsvr_port);
151a6d42e7dSPeter Dunlap
152a6d42e7dSPeter Dunlap err = idm_sosendto(socket, data, data_len,
153a6d42e7dSPeter Dunlap (struct sockaddr *)&sa_rsvr.s_in6,
154a6d42e7dSPeter Dunlap sizeof (struct sockaddr_in6));
155a6d42e7dSPeter Dunlap kmem_free(data, MAX_RAD_PACKET_LEN);
156a6d42e7dSPeter Dunlap return (err);
157a6d42e7dSPeter Dunlap } else {
158a6d42e7dSPeter Dunlap /* Invalid IP address for RADIUS server. */
159a6d42e7dSPeter Dunlap kmem_free(data, MAX_RAD_PACKET_LEN);
160a6d42e7dSPeter Dunlap return (-1);
161a6d42e7dSPeter Dunlap }
162a6d42e7dSPeter Dunlap }
163a6d42e7dSPeter Dunlap
164a6d42e7dSPeter Dunlap /*
165a6d42e7dSPeter Dunlap * See radius_packet.h.
166a6d42e7dSPeter Dunlap */
167a6d42e7dSPeter Dunlap int
iscsit_rcv_radius_response(ksocket_t socket,uint8_t * shared_secret,uint32_t shared_secret_len,uint8_t * req_authenticator,radius_packet_data_t * resp_data)168*0f1702c5SYu Xiangning iscsit_rcv_radius_response(ksocket_t socket, uint8_t *shared_secret,
169a6d42e7dSPeter Dunlap uint32_t shared_secret_len, uint8_t *req_authenticator,
170a6d42e7dSPeter Dunlap radius_packet_data_t *resp_data)
171a6d42e7dSPeter Dunlap {
172a6d42e7dSPeter Dunlap radius_packet_t *packet;
173a6d42e7dSPeter Dunlap MD5_CTX context;
174a6d42e7dSPeter Dunlap uint8_t *tmp_data;
175a6d42e7dSPeter Dunlap uint8_t md5_digest[16]; /* MD5 Digest Length 16 */
176a6d42e7dSPeter Dunlap uint16_t declared_len = 0;
177a6d42e7dSPeter Dunlap size_t received_len = 0;
178a6d42e7dSPeter Dunlap
179a6d42e7dSPeter Dunlap struct iovec iov[1];
180a6d42e7dSPeter Dunlap struct nmsghdr msg;
181a6d42e7dSPeter Dunlap
182a6d42e7dSPeter Dunlap tmp_data = kmem_zalloc(MAX_RAD_PACKET_LEN, KM_SLEEP);
183a6d42e7dSPeter Dunlap iov[0].iov_base = (char *)tmp_data;
184a6d42e7dSPeter Dunlap iov[0].iov_len = MAX_RAD_PACKET_LEN;
185a6d42e7dSPeter Dunlap
186a6d42e7dSPeter Dunlap bzero(&msg, sizeof (msg));
187a6d42e7dSPeter Dunlap msg.msg_name = NULL;
188a6d42e7dSPeter Dunlap msg.msg_namelen = 0;
189a6d42e7dSPeter Dunlap msg.msg_control = NULL;
190a6d42e7dSPeter Dunlap msg.msg_controllen = 0;
191a6d42e7dSPeter Dunlap msg.msg_flags = MSG_WAITALL;
192a6d42e7dSPeter Dunlap msg.msg_iov = iov;
193a6d42e7dSPeter Dunlap msg.msg_iovlen = 1;
194a6d42e7dSPeter Dunlap
195a6d42e7dSPeter Dunlap received_len = iscsit_net_recvmsg(socket, &msg, RAD_RCV_TIMEOUT);
196a6d42e7dSPeter Dunlap
197a6d42e7dSPeter Dunlap if (received_len <= (size_t)0) {
198a6d42e7dSPeter Dunlap kmem_free(tmp_data, MAX_RAD_PACKET_LEN);
199a6d42e7dSPeter Dunlap return (RAD_RSP_RCVD_NO_DATA);
200a6d42e7dSPeter Dunlap }
201a6d42e7dSPeter Dunlap
202a6d42e7dSPeter Dunlap /*
203a6d42e7dSPeter Dunlap * Check if the received packet length is within allowable range.
204a6d42e7dSPeter Dunlap * RFC 2865 section 3.
205a6d42e7dSPeter Dunlap */
206a6d42e7dSPeter Dunlap if (received_len < MIN_RAD_PACKET_LEN) {
207a6d42e7dSPeter Dunlap kmem_free(tmp_data, MAX_RAD_PACKET_LEN);
208a6d42e7dSPeter Dunlap return (RAD_RSP_RCVD_PROTOCOL_ERR);
209a6d42e7dSPeter Dunlap } else if (received_len > MAX_RAD_PACKET_LEN) {
210a6d42e7dSPeter Dunlap kmem_free(tmp_data, MAX_RAD_PACKET_LEN);
211a6d42e7dSPeter Dunlap return (RAD_RSP_RCVD_PROTOCOL_ERR);
212a6d42e7dSPeter Dunlap }
213a6d42e7dSPeter Dunlap
214a6d42e7dSPeter Dunlap packet = (radius_packet_t *)tmp_data;
215a6d42e7dSPeter Dunlap bcopy(packet->length, &declared_len, sizeof (ushort_t));
216a6d42e7dSPeter Dunlap declared_len = ntohs(declared_len);
217a6d42e7dSPeter Dunlap
218a6d42e7dSPeter Dunlap /*
219a6d42e7dSPeter Dunlap * Discard packet with received length shorter than declared
220a6d42e7dSPeter Dunlap * length. RFC 2865 section 3.
221a6d42e7dSPeter Dunlap */
222a6d42e7dSPeter Dunlap if (received_len < declared_len) {
223a6d42e7dSPeter Dunlap kmem_free(tmp_data, MAX_RAD_PACKET_LEN);
224a6d42e7dSPeter Dunlap return (RAD_RSP_RCVD_PROTOCOL_ERR);
225a6d42e7dSPeter Dunlap }
226a6d42e7dSPeter Dunlap
227a6d42e7dSPeter Dunlap /*
228a6d42e7dSPeter Dunlap * Check if the declared packet length is within allowable range.
229a6d42e7dSPeter Dunlap * RFC 2865 section 3.
230a6d42e7dSPeter Dunlap */
231a6d42e7dSPeter Dunlap if (declared_len < MIN_RAD_PACKET_LEN) {
232a6d42e7dSPeter Dunlap kmem_free(tmp_data, MAX_RAD_PACKET_LEN);
233a6d42e7dSPeter Dunlap return (RAD_RSP_RCVD_PROTOCOL_ERR);
234a6d42e7dSPeter Dunlap } else if (declared_len > MAX_RAD_PACKET_LEN) {
235a6d42e7dSPeter Dunlap kmem_free(tmp_data, MAX_RAD_PACKET_LEN);
236a6d42e7dSPeter Dunlap return (RAD_RSP_RCVD_PROTOCOL_ERR);
237a6d42e7dSPeter Dunlap }
238a6d42e7dSPeter Dunlap
239a6d42e7dSPeter Dunlap /*
240a6d42e7dSPeter Dunlap * Authenticate the incoming packet, using the following algorithm
241a6d42e7dSPeter Dunlap * (RFC 2865 section 3):
242a6d42e7dSPeter Dunlap *
243a6d42e7dSPeter Dunlap * MD5(Code+ID+Length+RequestAuth+Attributes+Secret)
244a6d42e7dSPeter Dunlap *
245a6d42e7dSPeter Dunlap * Code = RADIUS packet code
246a6d42e7dSPeter Dunlap * ID = RADIUS packet identifier
247a6d42e7dSPeter Dunlap * Length = Declared length of the packet
248a6d42e7dSPeter Dunlap * RequestAuth = The request authenticator
249a6d42e7dSPeter Dunlap * Attributes = The response attributes
250a6d42e7dSPeter Dunlap * Secret = The shared secret
251a6d42e7dSPeter Dunlap */
252a6d42e7dSPeter Dunlap MD5Init(&context);
253a6d42e7dSPeter Dunlap bzero(&md5_digest, 16);
254a6d42e7dSPeter Dunlap MD5Update(&context, &packet->code, 1);
255a6d42e7dSPeter Dunlap MD5Update(&context, &packet->identifier, 1);
256a6d42e7dSPeter Dunlap MD5Update(&context, packet->length, 2);
257a6d42e7dSPeter Dunlap MD5Update(&context, req_authenticator, RAD_AUTHENTICATOR_LEN);
258a6d42e7dSPeter Dunlap
259a6d42e7dSPeter Dunlap /*
260a6d42e7dSPeter Dunlap * Include response attributes only if there is a payload
261a6d42e7dSPeter Dunlap * If the received length is greater than the declared length,
262a6d42e7dSPeter Dunlap * trust the declared length and shorten the packet (i.e., to
263a6d42e7dSPeter Dunlap * treat the octets outside the range of the Length field as
264a6d42e7dSPeter Dunlap * padding - RFC 2865 section 3).
265a6d42e7dSPeter Dunlap */
266a6d42e7dSPeter Dunlap if (declared_len > RAD_PACKET_HDR_LEN) {
267a6d42e7dSPeter Dunlap /* Response Attributes */
268a6d42e7dSPeter Dunlap MD5Update(&context, packet->data,
269a6d42e7dSPeter Dunlap declared_len - RAD_PACKET_HDR_LEN);
270a6d42e7dSPeter Dunlap }
271a6d42e7dSPeter Dunlap MD5Update(&context, shared_secret, shared_secret_len);
272a6d42e7dSPeter Dunlap MD5Final(md5_digest, &context);
273a6d42e7dSPeter Dunlap
274a6d42e7dSPeter Dunlap if (bcmp(md5_digest, packet->authenticator, RAD_AUTHENTICATOR_LEN)
275a6d42e7dSPeter Dunlap != 0) {
276a6d42e7dSPeter Dunlap kmem_free(tmp_data, MAX_RAD_PACKET_LEN);
277a6d42e7dSPeter Dunlap return (RAD_RSP_RCVD_AUTH_FAILED);
278a6d42e7dSPeter Dunlap }
279a6d42e7dSPeter Dunlap
280a6d42e7dSPeter Dunlap /*
281a6d42e7dSPeter Dunlap * Annotate the RADIUS packet data with the data we received from
282a6d42e7dSPeter Dunlap * the server.
283a6d42e7dSPeter Dunlap */
284a6d42e7dSPeter Dunlap resp_data->code = packet->code;
285a6d42e7dSPeter Dunlap resp_data->identifier = packet->identifier;
286a6d42e7dSPeter Dunlap
287a6d42e7dSPeter Dunlap kmem_free(tmp_data, MAX_RAD_PACKET_LEN);
288a6d42e7dSPeter Dunlap return (RAD_RSP_RCVD_SUCCESS);
289a6d42e7dSPeter Dunlap }
290a6d42e7dSPeter Dunlap
291a6d42e7dSPeter Dunlap /*
292a6d42e7dSPeter Dunlap * encode_chap_password -
293a6d42e7dSPeter Dunlap *
294a6d42e7dSPeter Dunlap * Encode a CHAP-Password attribute. This function basically prepends
295a6d42e7dSPeter Dunlap * the identifier in front of chap_passwd and copy the results to
296a6d42e7dSPeter Dunlap * *result.
297a6d42e7dSPeter Dunlap */
298a6d42e7dSPeter Dunlap static void
encode_chap_password(int identifier,int chap_passwd_len,uint8_t * chap_passwd,uint8_t * result)299a6d42e7dSPeter Dunlap encode_chap_password(int identifier, int chap_passwd_len,
300a6d42e7dSPeter Dunlap uint8_t *chap_passwd, uint8_t *result)
301a6d42e7dSPeter Dunlap {
302a6d42e7dSPeter Dunlap result[0] = (uint8_t)identifier;
303a6d42e7dSPeter Dunlap bcopy(chap_passwd, &result[1], chap_passwd_len);
304a6d42e7dSPeter Dunlap }
305a6d42e7dSPeter Dunlap /*
306a6d42e7dSPeter Dunlap * iscsi_net_recvmsg - receive message on socket
307a6d42e7dSPeter Dunlap */
308a6d42e7dSPeter Dunlap /* ARGSUSED */
309a6d42e7dSPeter Dunlap static size_t
iscsit_net_recvmsg(ksocket_t socket,struct msghdr * msg,int timeout)310*0f1702c5SYu Xiangning iscsit_net_recvmsg(ksocket_t socket, struct msghdr *msg, int timeout)
311a6d42e7dSPeter Dunlap {
312*0f1702c5SYu Xiangning int prflag = msg->msg_flags;
313*0f1702c5SYu Xiangning size_t recv = 0;
314*0f1702c5SYu Xiangning struct sockaddr_in6 l_addr, f_addr;
315*0f1702c5SYu Xiangning socklen_t l_addrlen;
316*0f1702c5SYu Xiangning socklen_t f_addrlen;
317*0f1702c5SYu Xiangning
318*0f1702c5SYu Xiangning bzero(&l_addr, sizeof (struct sockaddr_in6));
319*0f1702c5SYu Xiangning bzero(&f_addr, sizeof (struct sockaddr_in6));
320*0f1702c5SYu Xiangning l_addrlen = sizeof (struct sockaddr_in6);
321*0f1702c5SYu Xiangning f_addrlen = sizeof (struct sockaddr_in6);
322a6d42e7dSPeter Dunlap /* If timeout requested on receive */
323a6d42e7dSPeter Dunlap if (timeout > 0) {
324a6d42e7dSPeter Dunlap boolean_t loopback = B_FALSE;
325*0f1702c5SYu Xiangning (void) ksocket_getsockname(socket, (struct sockaddr *)(&l_addr),
326*0f1702c5SYu Xiangning &l_addrlen, CRED());
327*0f1702c5SYu Xiangning (void) ksocket_getpeername(socket, (struct sockaddr *)(&f_addr),
328*0f1702c5SYu Xiangning &f_addrlen, CRED());
329*0f1702c5SYu Xiangning
330a6d42e7dSPeter Dunlap /* And this isn't a loopback connection */
331*0f1702c5SYu Xiangning if (((struct sockaddr *)(&l_addr))->sa_family == AF_INET) {
332a6d42e7dSPeter Dunlap struct sockaddr_in *lin = (struct sockaddr_in *)
333*0f1702c5SYu Xiangning ((void *)(&l_addr));
334a6d42e7dSPeter Dunlap struct sockaddr_in *fin = (struct sockaddr_in *)
335*0f1702c5SYu Xiangning ((void *)(&f_addr));
336a6d42e7dSPeter Dunlap
337a6d42e7dSPeter Dunlap if ((lin->sin_family == fin->sin_family) &&
338a6d42e7dSPeter Dunlap (bcmp(&lin->sin_addr, &fin->sin_addr,
339a6d42e7dSPeter Dunlap sizeof (struct in_addr)) == 0)) {
340a6d42e7dSPeter Dunlap loopback = B_TRUE;
341a6d42e7dSPeter Dunlap }
342a6d42e7dSPeter Dunlap } else {
343a6d42e7dSPeter Dunlap struct sockaddr_in6 *lin6 = (struct sockaddr_in6 *)
344*0f1702c5SYu Xiangning ((void *)(&l_addr));
345a6d42e7dSPeter Dunlap struct sockaddr_in6 *fin6 = (struct sockaddr_in6 *)
346*0f1702c5SYu Xiangning ((void *)(&f_addr));
347a6d42e7dSPeter Dunlap
348a6d42e7dSPeter Dunlap if ((lin6->sin6_family == fin6->sin6_family) &&
349a6d42e7dSPeter Dunlap (bcmp(&lin6->sin6_addr, &fin6->sin6_addr,
350a6d42e7dSPeter Dunlap sizeof (struct in6_addr)) == 0)) {
351a6d42e7dSPeter Dunlap loopback = B_TRUE;
352a6d42e7dSPeter Dunlap }
353a6d42e7dSPeter Dunlap }
354a6d42e7dSPeter Dunlap if (loopback == B_FALSE) {
355*0f1702c5SYu Xiangning struct timeval tl;
356*0f1702c5SYu Xiangning tl.tv_sec = timeout;
357*0f1702c5SYu Xiangning tl.tv_usec = 0;
358*0f1702c5SYu Xiangning /* Set recv timeout */
359*0f1702c5SYu Xiangning if (ksocket_setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO,
360*0f1702c5SYu Xiangning &tl, sizeof (struct timeval), CRED()))
361a6d42e7dSPeter Dunlap return (0);
362a6d42e7dSPeter Dunlap }
363a6d42e7dSPeter Dunlap }
364a6d42e7dSPeter Dunlap
365a6d42e7dSPeter Dunlap /*
366a6d42e7dSPeter Dunlap * Receive the requested data. Block until all
367*0f1702c5SYu Xiangning * data is received or timeout.
368a6d42e7dSPeter Dunlap *
369a6d42e7dSPeter Dunlap * resid occurs only when the connection is
370a6d42e7dSPeter Dunlap * disconnected. In that case it will return
371a6d42e7dSPeter Dunlap * the amount of data that was not received.
372a6d42e7dSPeter Dunlap * In general this is the total amount we
373a6d42e7dSPeter Dunlap * requested.
374a6d42e7dSPeter Dunlap */
375*0f1702c5SYu Xiangning (void) ksocket_recvmsg(socket, msg, prflag, &recv, CRED());
376*0f1702c5SYu Xiangning return (recv);
377a6d42e7dSPeter Dunlap }
378