xref: /netbsd-src/lib/libc/net/sctp_sys_calls.c (revision ace5b9b5feb0e7608bd2da7a617428d2e1cf8aa3)
1 /*	$KAME: sctp_sys_calls.c,v 1.10 2005/03/06 16:04:16 itojun Exp $ */
2 /*	$NetBSD: sctp_sys_calls.c,v 1.2 2024/01/20 14:52:48 christos Exp $ */
3 
4 /*
5  * Copyright (C) 2002, 2003, 2004 Cisco Systems Inc,
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the project nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 #include <stdio.h>
34 #include <string.h>
35 #include <errno.h>
36 #include <stdlib.h>
37 #include <unistd.h>
38 #include <sys/types.h>
39 #include <sys/socket.h>
40 #include <sys/errno.h>
41 #include <sys/syscall.h>
42 #include <sys/ioctl.h>
43 #include <sys/uio.h>
44 #include <netinet/in.h>
45 #include <arpa/inet.h>
46 #include <netinet/sctp_uio.h>
47 #include <netinet/sctp.h>
48 
49 #include <net/if_dl.h>
50 
51 #ifndef IN6_IS_ADDR_V4MAPPED
52 #define IN6_IS_ADDR_V4MAPPED(a)		     \
53 	((*(const u_int32_t *)(const void *)(&(a)->s6_addr[0]) == 0) &&	\
54 	 (*(const u_int32_t *)(const void *)(&(a)->s6_addr[4]) == 0) &&	\
55 	 (*(const u_int32_t *)(const void *)(&(a)->s6_addr[8]) == ntohl(0x0000ffff)))
56 #endif
57 
58 #define SCTP_CONTROL_VEC_SIZE_RCV	16384
59 
60 #ifdef SCTP_DEBUG_PRINT_ADDRESS
61 static void
SCTPPrintAnAddress(struct sockaddr * a)62 SCTPPrintAnAddress(struct sockaddr *a)
63 {
64 	char stringToPrint[256];
65 	u_short prt;
66 	char *srcaddr, *txt;
67 
68 	if (a == NULL) {
69 		printf("NULL\n");
70 		return;
71 	}
72 	if (a->sa_family == AF_INET) {
73 		srcaddr = (char *)&((struct sockaddr_in *)a)->sin_addr;
74 		txt = "IPv4 Address: ";
75 		prt = ntohs(((struct sockaddr_in *)a)->sin_port);
76 	} else if (a->sa_family == AF_INET6) {
77 		srcaddr = (char *)&((struct sockaddr_in6 *)a)->sin6_addr;
78 		prt = ntohs(((struct sockaddr_in6 *)a)->sin6_port);
79 		txt = "IPv6 Address: ";
80 	} else if (a->sa_family == AF_LINK) {
81 		int i;
82 		char tbuf[200];
83 		u_char adbuf[200];
84 		struct sockaddr_dl *dl;
85 
86 		dl = (struct sockaddr_dl *)a;
87 		strncpy(tbuf, dl->sdl_data, dl->sdl_nlen);
88 		tbuf[dl->sdl_nlen] = 0;
89 		printf("Intf:%s (len:%d)Interface index:%d type:%x(%d) ll-len:%d ",
90 		    tbuf, dl->sdl_nlen, dl->sdl_index, dl->sdl_type,
91 		    dl->sdl_type, dl->sdl_alen);
92 		memcpy(adbuf, LLADDR(dl), dl->sdl_alen);
93 		for (i = 0; i < dl->sdl_alen; i++){
94 			printf("%2.2x", adbuf[i]);
95 			if (i < (dl->sdl_alen - 1))
96 				printf(":");
97 		}
98 		printf("\n");
99 	/*	u_short	sdl_route[16];*/	/* source routing information */
100 		return;
101 	} else {
102 		return;
103 	}
104 	if (inet_ntop(a->sa_family, srcaddr, stringToPrint,
105 	    sizeof(stringToPrint))) {
106 		if (a->sa_family == AF_INET6) {
107 			printf("%s%s:%d scope:%d\n", txt, stringToPrint, prt,
108 			    ((struct sockaddr_in6 *)a)->sin6_scope_id);
109 		} else {
110 			printf("%s%s:%d\n", txt, stringToPrint, prt);
111 		}
112 
113 	} else {
114 		printf("%s unprintable?\n", txt);
115 	}
116 }
117 #endif /* SCTP_DEBUG_PRINT_ADDRESS */
118 
119 void
in6_sin6_2_sin(struct sockaddr_in * sin,struct sockaddr_in6 * sin6)120 in6_sin6_2_sin(struct sockaddr_in *sin, struct sockaddr_in6 *sin6)
121 {
122 	memset(sin, 0, sizeof(*sin));
123 	sin->sin_len = sizeof(struct sockaddr_in);
124 	sin->sin_family = AF_INET;
125 	sin->sin_port = sin6->sin6_port;
126 	sin->sin_addr.s_addr = sin6->sin6_addr.__u6_addr.__u6_addr32[3];
127 }
128 
129 int
sctp_connectx(int sd,struct sockaddr * addrs,int addrcnt,sctp_assoc_t * id)130 sctp_connectx(int sd, struct sockaddr *addrs, int addrcnt,
131 		sctp_assoc_t *id)
132 {
133 	int i, ret, cnt;
134 	struct sockaddr *at;
135 	struct sctp_connectx_addrs sca;
136 #if 0
137 	char *cpto;
138 #endif
139 	size_t len;
140 
141 	at = addrs;
142 	cnt = 0;
143 	len = 0;
144 	/* validate all the addresses and get the size */
145 	for (i = 0; i < addrcnt; i++) {
146 		if (at->sa_family == AF_INET) {
147 			len += at->sa_len;
148 		} else if (at->sa_family == AF_INET6){
149 			if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)(void *)at)->sin6_addr)){
150 				len += sizeof(struct sockaddr_in);
151 #if 0
152 				in6_sin6_2_sin((struct sockaddr_in *)cpto,
153 				    (struct sockaddr_in6 *)at);
154 				cpto = ((caddr_t)cpto + sizeof(struct sockaddr_in));
155 				len += sizeof(struct sockaddr_in);
156 #endif
157 			} else {
158 				len += at->sa_len;
159 			}
160 		} else {
161 			errno = EINVAL;
162 			return (-1);
163 		}
164 		at = (struct sockaddr *)((caddr_t)at + at->sa_len);
165 		cnt++;
166         }
167 	/* do we have any? */
168 	if (cnt == 0) {
169 		errno = EINVAL;
170 		return(-1);
171 	}
172 
173 	sca.cx_num = cnt;
174 	sca.cx_len = (int)len;
175 	sca.cx_addrs = addrs;
176 	ret = ioctl(sd, SIOCCONNECTX, (void *)&sca);
177 	if ((ret == 0) && (id != NULL)) {
178 		memcpy(id, &sca.cx_num, sizeof(sctp_assoc_t));
179 	}
180 	return (ret);
181 }
182 
183 int
sctp_bindx(int sd,struct sockaddr * addrs,int addrcnt,int flags)184 sctp_bindx(int sd, struct sockaddr *addrs, int addrcnt, int flags)
185 {
186 	struct sctp_getaddresses *gaddrs;
187 	struct sockaddr *sa;
188 	int i, sz, fam, argsz;
189 
190 	if ((flags != SCTP_BINDX_ADD_ADDR) &&
191 	    (flags != SCTP_BINDX_REM_ADDR)) {
192 		errno = EFAULT;
193 		return(-1);
194 	}
195 	argsz = (sizeof(struct sockaddr_storage) +
196 	    sizeof(struct sctp_getaddresses));
197 	gaddrs = (struct sctp_getaddresses *)calloc(1, argsz);
198 	if (gaddrs == NULL) {
199 		errno = ENOMEM;
200 		return(-1);
201 	}
202 	gaddrs->sget_assoc_id = 0;
203 	sa = addrs;
204 	for (i = 0; i < addrcnt; i++) {
205 		sz = sa->sa_len;
206 		fam = sa->sa_family;
207 		((struct sockaddr_in *)(void *)&addrs[i])->sin_port = ((struct sockaddr_in *)(void *)sa)->sin_port;
208 		if ((fam != AF_INET) && (fam != AF_INET6)) {
209 			errno = EINVAL;
210 			return(-1);
211 		}
212 		memcpy(gaddrs->addr, sa, sz);
213 		if (setsockopt(sd, IPPROTO_SCTP, flags, gaddrs,
214 		    (unsigned int)argsz) != 0) {
215 			free(gaddrs);
216 			return(-1);
217 		}
218 		memset(gaddrs, 0, argsz);
219 		sa = (struct sockaddr *)((caddr_t)sa + sz);
220 	}
221 	free(gaddrs);
222 	return(0);
223 }
224 
225 
226 int
sctp_opt_info(int sd,sctp_assoc_t id,int opt,void * arg,socklen_t * size)227 sctp_opt_info(int sd, sctp_assoc_t id, int opt, void *arg, socklen_t *size)
228 {
229 	if ((opt == SCTP_RTOINFO) ||
230  	    (opt == SCTP_ASSOCINFO) ||
231 	    (opt == SCTP_PRIMARY_ADDR) ||
232 	    (opt == SCTP_SET_PEER_PRIMARY_ADDR) ||
233 	    (opt == SCTP_PEER_ADDR_PARAMS) ||
234 	    (opt == SCTP_STATUS) ||
235 	    (opt == SCTP_GET_PEER_ADDR_INFO)) {
236 		*(sctp_assoc_t *)arg = id;
237 		return(getsockopt2(sd, IPPROTO_SCTP, opt, arg, size));
238 	} else {
239 		errno = EOPNOTSUPP;
240 		return(-1);
241 	}
242 }
243 
244 int
sctp_getpaddrs(int sd,sctp_assoc_t id,struct sockaddr ** raddrs)245 sctp_getpaddrs(int sd, sctp_assoc_t id, struct sockaddr **raddrs)
246 {
247 	struct sctp_getaddresses *addrs;
248 	struct sockaddr *sa;
249 	struct sockaddr *re;
250 	sctp_assoc_t asoc;
251 	caddr_t lim;
252 	unsigned int siz;
253 	int cnt;
254 
255 	if (raddrs == NULL) {
256 		errno = EFAULT;
257 		return(-1);
258 	}
259 	asoc = id;
260 	siz = sizeof(sctp_assoc_t);
261 	if (getsockopt2(sd, IPPROTO_SCTP, SCTP_GET_REMOTE_ADDR_SIZE,
262 	    &asoc, &siz) != 0) {
263 		return(-1);
264 	}
265 	siz = (unsigned int)asoc;
266 	siz += sizeof(struct sctp_getaddresses);
267 	addrs = calloc((unsigned long)1, (unsigned long)siz);
268 	if (addrs == NULL) {
269 		errno = ENOMEM;
270 		return(-1);
271 	}
272 	memset(addrs, 0, (size_t)siz);
273 	addrs->sget_assoc_id = id;
274 	/* Now lets get the array of addresses */
275 	if (getsockopt2(sd, IPPROTO_SCTP, SCTP_GET_PEER_ADDRESSES,
276 	    addrs, &siz) != 0) {
277 		free(addrs);
278 		return(-1);
279 	}
280 	re = (struct sockaddr *)&addrs->addr[0];
281 	*raddrs = re;
282 	cnt = 0;
283 	sa = (struct sockaddr *)&addrs->addr[0];
284 	lim = (caddr_t)addrs + siz;
285 	while ((caddr_t)sa < lim) {
286 		cnt++;
287 		sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len);
288 		if (sa->sa_len == 0)
289 			break;
290 	}
291 	return(cnt);
292 }
293 
sctp_freepaddrs(struct sockaddr * addrs)294 void sctp_freepaddrs(struct sockaddr *addrs)
295 {
296 	/* Take away the hidden association id */
297 	void *fr_addr;
298 	fr_addr = (void *)((caddr_t)addrs - sizeof(sctp_assoc_t));
299 	/* Now free it */
300 	free(fr_addr);
301 }
302 
303 int
sctp_getladdrs(int sd,sctp_assoc_t id,struct sockaddr ** raddrs)304 sctp_getladdrs (int sd, sctp_assoc_t id, struct sockaddr **raddrs)
305 {
306 	struct sctp_getaddresses *addrs;
307 	struct sockaddr *re;
308 	caddr_t lim;
309 	struct sockaddr *sa;
310 	int size_of_addresses;
311 	socklen_t siz;
312 	int cnt;
313 
314 	if (raddrs == NULL) {
315 		errno = EFAULT;
316 		return(-1);
317 	}
318 	size_of_addresses = 0;
319 	siz = sizeof(int);
320 	if (getsockopt2(sd, IPPROTO_SCTP, SCTP_GET_LOCAL_ADDR_SIZE,
321 	    &size_of_addresses, &siz) != 0) {
322 		return(-1);
323 	}
324 	if (size_of_addresses == 0) {
325 		errno = ENOTCONN;
326 		return(-1);
327 	}
328 	siz = (socklen_t)(size_of_addresses + sizeof(struct sockaddr_storage));
329 	siz += sizeof(struct sctp_getaddresses);
330 	addrs = calloc((unsigned long)1, (unsigned long)siz);
331 	if (addrs == NULL) {
332 		errno = ENOMEM;
333 		return(-1);
334 	}
335 	memset(addrs, 0, (size_t)siz);
336 	addrs->sget_assoc_id = id;
337 	/* Now lets get the array of addresses */
338 	if (getsockopt2(sd, IPPROTO_SCTP, SCTP_GET_LOCAL_ADDRESSES, addrs,
339 	    &siz) != 0) {
340 		free(addrs);
341 		return(-1);
342 	}
343 	re = (struct sockaddr *)&addrs->addr[0];
344 	*raddrs = re;
345 	cnt = 0;
346 	sa = (struct sockaddr *)&addrs->addr[0];
347 	lim = (caddr_t)addrs + siz;
348 	while ((caddr_t)sa < lim) {
349 		cnt++;
350 		sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len);
351 		if (sa->sa_len == 0)
352 			break;
353 	}
354 	return(cnt);
355 }
356 
sctp_freeladdrs(struct sockaddr * addrs)357 void sctp_freeladdrs(struct sockaddr *addrs)
358 {
359 	/* Take away the hidden association id */
360 	void *fr_addr;
361 	fr_addr = (void *)((caddr_t)addrs - sizeof(sctp_assoc_t));
362 	/* Now free it */
363 	free(fr_addr);
364 }
365 
366 ssize_t
sctp_sendmsg(int s,const void * data,size_t len,const struct sockaddr * to,socklen_t tolen,u_int32_t ppid,u_int32_t flags,u_int16_t stream_no,u_int32_t timetolive,u_int32_t context)367 sctp_sendmsg(int s,
368 	     const void *data,
369 	     size_t len,
370 	     const struct sockaddr *to,
371 	     socklen_t tolen __attribute__((unused)),
372 	     u_int32_t ppid,
373 	     u_int32_t flags,
374 	     u_int16_t stream_no,
375 	     u_int32_t timetolive,
376 	     u_int32_t context)
377 {
378 	ssize_t sz;
379 	struct msghdr msg;
380 	struct iovec iov[2];
381 	char controlVector[256];
382 	struct sctp_sndrcvinfo *s_info;
383 	struct cmsghdr *cmsg;
384 	struct sockaddr *who=NULL;
385 	union {
386 		struct sockaddr_in in;
387 		struct sockaddr_in6 in6;
388 	} addr;
389 
390 #if 0
391 	fprintf(io, "sctp_sendmsg(sd:%d, data:%x, len:%d, to:%x, tolen:%d, ppid:%x, flags:%x str:%d ttl:%d ctx:%x\n",
392 	    s, (u_int)data, (int)len, (u_int)to, (int)tolen, ppid, flags,
393 	    (int)stream_no, (int)timetolive, (u_int)context);
394 	fflush(io);
395 #endif
396 	if (to) {
397 		if (to->sa_len == 0) {
398 			/*
399 			 * For the lazy app, that did not
400 			 * set sa_len, we attempt to set for them.
401 			 */
402 			switch (to->sa_family) {
403 			case AF_INET:
404 				memcpy(&addr, to, sizeof(struct sockaddr_in));
405 				addr.in.sin_len = sizeof(struct sockaddr_in);
406 				break;
407 			case AF_INET6:
408 				memcpy(&addr, to, sizeof(struct sockaddr_in6));
409 				addr.in6.sin6_len = sizeof(struct sockaddr_in6);
410 				break;
411 			default:
412 				errno = EAFNOSUPPORT;
413 				return -1;
414 			}
415 		} else {
416 			memcpy (&addr, to, to->sa_len);
417 		}
418 		who = (struct sockaddr *)(void *)&addr;
419 	}
420 	iov[0].iov_base = (void *)(unsigned long)data;
421 	iov[0].iov_len = len;
422 	iov[1].iov_base = NULL;
423 	iov[1].iov_len = 0;
424 
425 	if (to) {
426 		msg.msg_name = (caddr_t)who;
427 		msg.msg_namelen = who->sa_len;
428 	} else {
429 		msg.msg_name = (caddr_t)NULL;
430 		msg.msg_namelen = 0;
431 	}
432 	msg.msg_iov = iov;
433 	msg.msg_iovlen = 1;
434 	msg.msg_control = (caddr_t)controlVector;
435 
436 	cmsg = (struct cmsghdr *)controlVector;
437 
438 	cmsg->cmsg_level = IPPROTO_SCTP;
439 	cmsg->cmsg_type = SCTP_SNDRCV;
440 	cmsg->cmsg_len = CMSG_LEN (sizeof(struct sctp_sndrcvinfo) );
441 	s_info = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
442 
443 	s_info->sinfo_stream = stream_no;
444 	s_info->sinfo_ssn = 0;
445 	s_info->sinfo_flags = flags;
446 	s_info->sinfo_ppid = ppid;
447 	s_info->sinfo_context = context;
448 	s_info->sinfo_assoc_id = 0;
449 	s_info->sinfo_timetolive = timetolive;
450 	errno = 0;
451 	msg.msg_controllen = cmsg->cmsg_len;
452 	sz = sendmsg(s, &msg, 0);
453 	return(sz);
454 }
455 
456 sctp_assoc_t
sctp_getassocid(int sd,struct sockaddr * sa)457 sctp_getassocid(int sd, struct sockaddr *sa)
458 {
459 	struct sctp_paddrparams sp;
460 	socklen_t siz;
461 
462 	/* First get the assoc id */
463 	siz = sizeof(struct sctp_paddrparams);
464 	memset(&sp, 0, sizeof(sp));
465 	memcpy((caddr_t)&sp.spp_address, sa, sa->sa_len);
466 	errno = 0;
467 	if (getsockopt2(sd, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, &sp, &siz) != 0)
468 		return((sctp_assoc_t)0);
469 	/* We depend on the fact that 0 can never be returned */
470 	return(sp.spp_assoc_id);
471 }
472 
473 
474 
475 ssize_t
sctp_send(int sd,const void * data,size_t len,const struct sctp_sndrcvinfo * sinfo,int flags)476 sctp_send(int sd, const void *data, size_t len,
477 	  const struct sctp_sndrcvinfo *sinfo,
478 	  int flags)
479 {
480 	ssize_t sz;
481 	struct msghdr msg;
482 	struct iovec iov[2];
483 	struct sctp_sndrcvinfo *s_info;
484 	char controlVector[256];
485 	struct cmsghdr *cmsg;
486 
487 	iov[0].iov_base = (void *)(unsigned long)data;
488 	iov[0].iov_len = len;
489 	iov[1].iov_base = NULL;
490 	iov[1].iov_len = 0;
491 
492 	msg.msg_name = 0;
493 	msg.msg_namelen = 0;
494 	msg.msg_iov = iov;
495 	msg.msg_iovlen = 1;
496 	msg.msg_control = (caddr_t)controlVector;
497 
498 	cmsg = (struct cmsghdr *)controlVector;
499 
500 	cmsg->cmsg_level = IPPROTO_SCTP;
501 	cmsg->cmsg_type = SCTP_SNDRCV;
502 	cmsg->cmsg_len = CMSG_LEN (sizeof(struct sctp_sndrcvinfo) );
503 	s_info = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
504 	/* copy in the data */
505 	*s_info = *sinfo;
506 	errno = 0;
507 	msg.msg_controllen = cmsg->cmsg_len;
508 	sz = sendmsg(sd, &msg, flags);
509 	return(sz);
510 }
511 
512 
513 ssize_t
sctp_sendx(int sd,const void * msg,size_t len,struct sockaddr * addrs,int addrcnt,struct sctp_sndrcvinfo * sinfo,int flags)514 sctp_sendx(int sd, const void *msg, size_t len,
515 	   struct sockaddr *addrs, int addrcnt,
516 	   struct sctp_sndrcvinfo *sinfo,
517 	   int flags)
518 {
519 	int i, cnt, saved_errno;
520 	ssize_t ret;
521 	int add_len;
522 	struct sockaddr *at;
523 	struct sctp_connectx_addrs sca;
524 
525 	len = 0;
526 	at = addrs;
527 	cnt = 0;
528 	/* validate all the addresses and get the size */
529 	for (i = 0; i < addrcnt; i++) {
530 		if (at->sa_family == AF_INET) {
531 			add_len = sizeof(struct sockaddr_in);
532 		} else if (at->sa_family == AF_INET6) {
533 			add_len = sizeof(struct sockaddr_in6);
534 		} else {
535 			errno = EINVAL;
536 			return (-1);
537 		}
538 		len += add_len;
539 		at = (struct sockaddr *)((caddr_t)at + add_len);
540 		cnt++;
541 	}
542 	/* do we have any? */
543 	if (cnt == 0) {
544 		errno = EINVAL;
545 		return(-1);
546 	}
547 
548 	sca.cx_num = cnt;
549 	sca.cx_len = (int)len;
550 	sca.cx_addrs = addrs;
551 	ret = ioctl(sd, SIOCCONNECTXDEL, (void *)&sca);
552 	if (ret != 0) {
553 		return(ret);
554 	}
555 	sinfo->sinfo_assoc_id = sctp_getassocid(sd, addrs);
556 	if (sinfo->sinfo_assoc_id == 0) {
557 		printf("Huh, can't get associd? TSNH!\n");
558 		(void)setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_COMPLETE, (void *)addrs,
559 				 (unsigned int)addrs->sa_len);
560 		errno = ENOENT;
561 		return (-1);
562 	}
563 	ret = sctp_send(sd, msg, len, sinfo, flags);
564 	saved_errno = errno;
565 	(void)setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_COMPLETE, (void *)addrs,
566 			 (unsigned int)addrs->sa_len);
567 
568 	errno = saved_errno;
569 	return (ret);
570 }
571 
572 ssize_t
sctp_sendmsgx(int sd,const void * msg,size_t len,struct sockaddr * addrs,int addrcnt,u_int32_t ppid,u_int32_t flags,u_int16_t stream_no,u_int32_t timetolive,u_int32_t context)573 sctp_sendmsgx(int sd,
574 	      const void *msg,
575 	      size_t len,
576 	      struct sockaddr *addrs,
577 	      int addrcnt,
578 	      u_int32_t ppid,
579 	      u_int32_t flags,
580 	      u_int16_t stream_no,
581 	      u_int32_t timetolive,
582 	      u_int32_t context)
583 {
584 	struct sctp_sndrcvinfo sinfo;
585 
586 	memset((void *) &sinfo, 0, sizeof(struct sctp_sndrcvinfo));
587 	sinfo.sinfo_ppid       = ppid;
588 	sinfo.sinfo_flags      = flags;
589 	sinfo.sinfo_ssn        = stream_no;
590 	sinfo.sinfo_timetolive = timetolive;
591 	sinfo.sinfo_context    = context;
592 	return sctp_sendx(sd, msg, len, addrs, addrcnt, &sinfo, 0);
593 }
594 
595 ssize_t
sctp_recvmsg(int s,void * dbuf,size_t len,struct sockaddr * from,socklen_t * fromlen,struct sctp_sndrcvinfo * sinfo,int * msg_flags)596 sctp_recvmsg (int s,
597 	      void *dbuf,
598 	      size_t len,
599 	      struct sockaddr *from,
600 	      socklen_t *fromlen,
601 	      struct sctp_sndrcvinfo *sinfo,
602 	      int *msg_flags)
603 {
604 	struct sctp_sndrcvinfo *s_info;
605 	ssize_t sz;
606 	struct msghdr msg;
607 	struct iovec iov[2];
608 	char controlVector[2048];
609 	struct cmsghdr *cmsg;
610 	iov[0].iov_base = dbuf;
611 	iov[0].iov_len = len;
612 	iov[1].iov_base = NULL;
613 	iov[1].iov_len = 0;
614 	msg.msg_name = (caddr_t)from;
615 	msg.msg_namelen = *fromlen;
616 	msg.msg_iov = iov;
617 	msg.msg_iovlen = 1;
618 	msg.msg_control = (caddr_t)controlVector;
619 	msg.msg_controllen = sizeof(controlVector);
620 	errno = 0;
621 	sz = recvmsg(s, &msg, 0);
622 
623 	s_info = NULL;
624 	len = sz;
625 	*msg_flags = msg.msg_flags;
626 	*fromlen = msg.msg_namelen;
627 	if ((msg.msg_controllen) && sinfo) {
628 		/* parse through and see if we find
629 		 * the sctp_sndrcvinfo (if the user wants it).
630 		 */
631 		cmsg = (struct cmsghdr *)controlVector;
632 		while (cmsg) {
633 			if (cmsg->cmsg_level == IPPROTO_SCTP) {
634 				if (cmsg->cmsg_type == SCTP_SNDRCV) {
635 					/* Got it */
636 					s_info = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
637 					/* Copy it to the user */
638 					*sinfo = *s_info;
639 					break;
640 				}
641 			}
642 			cmsg = CMSG_NXTHDR(&msg, cmsg);
643 		}
644 	}
645 	return(sz);
646 }
647 
648 ssize_t
sctp_recvv(int sd,const struct iovec * iov,int iovlen,struct sockaddr * from,socklen_t * fromlen,void * info,socklen_t * infolen,unsigned int * infotype,int * flags)649 sctp_recvv(int sd,
650     const struct iovec *iov,
651     int iovlen,
652     struct sockaddr *from,
653     socklen_t * fromlen,
654     void *info,
655     socklen_t * infolen,
656     unsigned int *infotype,
657     int *flags)
658 {
659 	char cmsgbuf[SCTP_CONTROL_VEC_SIZE_RCV];
660 	struct msghdr msg;
661 	struct cmsghdr *cmsg;
662 	ssize_t ret;
663 	struct sctp_rcvinfo *rcvinfo;
664 	struct sctp_nxtinfo *nxtinfo;
665 
666 	if (((info != NULL) && (infolen == NULL)) ||
667 	    ((info == NULL) && (infolen != NULL) && (*infolen != 0)) ||
668 	    ((info != NULL) && (infotype == NULL))) {
669 		errno = EINVAL;
670 		return (-1);
671 	}
672 	if (infotype) {
673 		*infotype = SCTP_RECVV_NOINFO;
674 	}
675 	msg.msg_name = from;
676 	if (fromlen == NULL) {
677 		msg.msg_namelen = 0;
678 	} else {
679 		msg.msg_namelen = *fromlen;
680 	}
681 	msg.msg_iov = __UNCONST(iov);
682 	msg.msg_iovlen = iovlen;
683 	msg.msg_control = cmsgbuf;
684 	msg.msg_controllen = sizeof(cmsgbuf);
685 	msg.msg_flags = 0;
686 	ret = recvmsg(sd, &msg, *flags);
687 	*flags = msg.msg_flags;
688 	if ((ret > 0) &&
689 	    (msg.msg_controllen > 0) &&
690 	    (infotype != NULL) &&
691 	    (infolen != NULL) &&
692 	    (*infolen > 0)) {
693 		rcvinfo = NULL;
694 		nxtinfo = NULL;
695 		for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
696 			if (cmsg->cmsg_level != IPPROTO_SCTP) {
697 				continue;
698 			}
699 			if (cmsg->cmsg_type == SCTP_RCVINFO) {
700 				rcvinfo = (struct sctp_rcvinfo *)CMSG_DATA(cmsg);
701 				if (nxtinfo != NULL) {
702 					break;
703 				} else {
704 					continue;
705 				}
706 			}
707 			if (cmsg->cmsg_type == SCTP_NXTINFO) {
708 				nxtinfo = (struct sctp_nxtinfo *)CMSG_DATA(cmsg);
709 				if (rcvinfo != NULL) {
710 					break;
711 				} else {
712 					continue;
713 				}
714 			}
715 		}
716 		if (rcvinfo != NULL) {
717 			if ((nxtinfo != NULL) && (*infolen >= sizeof(struct sctp_recvv_rn))) {
718 				struct sctp_recvv_rn *rn_info;
719 
720 				rn_info = (struct sctp_recvv_rn *)info;
721 				rn_info->recvv_rcvinfo = *rcvinfo;
722 				rn_info->recvv_nxtinfo = *nxtinfo;
723 				*infolen = (socklen_t) sizeof(struct sctp_recvv_rn);
724 				*infotype = SCTP_RECVV_RN;
725 			} else if (*infolen >= sizeof(struct sctp_rcvinfo)) {
726 				memcpy(info, rcvinfo, sizeof(struct sctp_rcvinfo));
727 				*infolen = (socklen_t) sizeof(struct sctp_rcvinfo);
728 				*infotype = SCTP_RECVV_RCVINFO;
729 			}
730 		} else if (nxtinfo != NULL) {
731 			if (*infolen >= sizeof(struct sctp_nxtinfo)) {
732 				memcpy(info, nxtinfo, sizeof(struct sctp_nxtinfo));
733 				*infolen = (socklen_t) sizeof(struct sctp_nxtinfo);
734 				*infotype = SCTP_RECVV_NXTINFO;
735 			}
736 		}
737 	}
738 	return (ret);
739 }
740 
741 ssize_t
sctp_sendv(int sd,const struct iovec * iov,int iovcnt,struct sockaddr * addrs,int addrcnt,void * info,socklen_t infolen,unsigned int infotype,int flags)742 sctp_sendv(int sd,
743     const struct iovec *iov, int iovcnt,
744     struct sockaddr *addrs, int addrcnt,
745     void *info, socklen_t infolen, unsigned int infotype,
746     int flags)
747 {
748 	ssize_t ret;
749 	int i;
750 	socklen_t addr_len;
751 	struct msghdr msg;
752 	in_port_t port;
753 	struct sctp_sendv_spa *spa_info;
754 	struct cmsghdr *cmsg;
755 	char *cmsgbuf;
756 	struct sockaddr *addr;
757 	struct sockaddr_in *addr_in;
758 	struct sockaddr_in6 *addr_in6;
759 	void *assoc_id_ptr;
760 	sctp_assoc_t assoc_id;
761 
762 	if ((addrcnt < 0) ||
763 	    (iovcnt < 0) ||
764 	    ((addrs == NULL) && (addrcnt > 0)) ||
765 	    ((addrs != NULL) && (addrcnt == 0)) ||
766 	    ((iov == NULL) && (iovcnt > 0)) ||
767 	    ((iov != NULL) && (iovcnt == 0))) {
768 		errno = EINVAL;
769 		return (-1);
770 	}
771 	cmsgbuf = malloc(CMSG_SPACE(sizeof(struct sctp_sndinfo)) +
772 	    CMSG_SPACE(sizeof(struct sctp_prinfo)) +
773 	    CMSG_SPACE(sizeof(struct sctp_authinfo)) +
774 	    (size_t)addrcnt * CMSG_SPACE(sizeof(struct in6_addr)));
775 	if (cmsgbuf == NULL) {
776 		errno = ENOMEM;
777 		return (-1);
778 	}
779 	assoc_id_ptr = NULL;
780 	msg.msg_control = cmsgbuf;
781 	msg.msg_controllen = 0;
782 	cmsg = (struct cmsghdr *)cmsgbuf;
783 	switch (infotype) {
784 	case SCTP_SENDV_NOINFO:
785 		if ((infolen != 0) || (info != NULL)) {
786 			free(cmsgbuf);
787 			errno = EINVAL;
788 			return (-1);
789 		}
790 		break;
791 	case SCTP_SENDV_SNDINFO:
792 		if ((info == NULL) || (infolen < sizeof(struct sctp_sndinfo))) {
793 			free(cmsgbuf);
794 			errno = EINVAL;
795 			return (-1);
796 		}
797 		cmsg->cmsg_level = IPPROTO_SCTP;
798 		cmsg->cmsg_type = SCTP_SNDINFO;
799 		cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo));
800 		memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_sndinfo));
801 		msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo));
802 		cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_sndinfo)));
803 		assoc_id_ptr = &(((struct sctp_sndinfo *)info)->snd_assoc_id);
804 		break;
805 	case SCTP_SENDV_PRINFO:
806 		if ((info == NULL) || (infolen < sizeof(struct sctp_prinfo))) {
807 			free(cmsgbuf);
808 			errno = EINVAL;
809 			return (-1);
810 		}
811 		cmsg->cmsg_level = IPPROTO_SCTP;
812 		cmsg->cmsg_type = SCTP_PRINFO;
813 		cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo));
814 		memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_prinfo));
815 		msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo));
816 		cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_prinfo)));
817 		break;
818 	case SCTP_SENDV_AUTHINFO:
819 		if ((info == NULL) || (infolen < sizeof(struct sctp_authinfo))) {
820 			free(cmsgbuf);
821 			errno = EINVAL;
822 			return (-1);
823 		}
824 		cmsg->cmsg_level = IPPROTO_SCTP;
825 		cmsg->cmsg_type = SCTP_AUTHINFO;
826 		cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_authinfo));
827 		memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_authinfo));
828 		msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_authinfo));
829 		cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_authinfo)));
830 		break;
831 	case SCTP_SENDV_SPA:
832 		if ((info == NULL) || (infolen < sizeof(struct sctp_sendv_spa))) {
833 			free(cmsgbuf);
834 			errno = EINVAL;
835 			return (-1);
836 		}
837 		spa_info = (struct sctp_sendv_spa *)info;
838 		if (spa_info->sendv_flags & SCTP_SEND_SNDINFO_VALID) {
839 			cmsg->cmsg_level = IPPROTO_SCTP;
840 			cmsg->cmsg_type = SCTP_SNDINFO;
841 			cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo));
842 			memcpy(CMSG_DATA(cmsg), &spa_info->sendv_sndinfo, sizeof(struct sctp_sndinfo));
843 			msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo));
844 			cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_sndinfo)));
845 			assoc_id_ptr = &(spa_info->sendv_sndinfo.snd_assoc_id);
846 		}
847 		if (spa_info->sendv_flags & SCTP_SEND_PRINFO_VALID) {
848 			cmsg->cmsg_level = IPPROTO_SCTP;
849 			cmsg->cmsg_type = SCTP_PRINFO;
850 			cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo));
851 			memcpy(CMSG_DATA(cmsg), &spa_info->sendv_prinfo, sizeof(struct sctp_prinfo));
852 			msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo));
853 			cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_prinfo)));
854 		}
855 		if (spa_info->sendv_flags & SCTP_SEND_AUTHINFO_VALID) {
856 			cmsg->cmsg_level = IPPROTO_SCTP;
857 			cmsg->cmsg_type = SCTP_AUTHINFO;
858 			cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_authinfo));
859 			memcpy(CMSG_DATA(cmsg), &spa_info->sendv_authinfo, sizeof(struct sctp_authinfo));
860 			msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_authinfo));
861 			cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_authinfo)));
862 		}
863 		break;
864 	default:
865 		free(cmsgbuf);
866 		errno = EINVAL;
867 		return (-1);
868 	}
869 	addr = addrs;
870 	msg.msg_name = NULL;
871 	msg.msg_namelen = 0;
872 
873 	for (i = 0; i < addrcnt; i++) {
874 		switch (addr->sa_family) {
875 		case AF_INET:
876 			addr_len = (socklen_t) sizeof(struct sockaddr_in);
877 			addr_in = (struct sockaddr_in *)(void *)addr;
878 			if (addr_in->sin_len != addr_len) {
879 				free(cmsgbuf);
880 				errno = EINVAL;
881 				return (-1);
882 			}
883 			if (i == 0) {
884 				port = addr_in->sin_port;
885 			} else {
886 				if (port == addr_in->sin_port) {
887 					cmsg->cmsg_level = IPPROTO_SCTP;
888 					cmsg->cmsg_type = SCTP_DSTADDRV4;
889 					cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
890 					memcpy(CMSG_DATA(cmsg), &addr_in->sin_addr, sizeof(struct in_addr));
891 					msg.msg_controllen += CMSG_SPACE(sizeof(struct in_addr));
892 					cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct in_addr)));
893 				} else {
894 					free(cmsgbuf);
895 					errno = EINVAL;
896 					return (-1);
897 				}
898 			}
899 			break;
900 		case AF_INET6:
901 			addr_len = (socklen_t) sizeof(struct sockaddr_in6);
902 			addr_in6 = (struct sockaddr_in6 *)(void *)addr;
903 			if (addr_in6->sin6_len != addr_len) {
904 				free(cmsgbuf);
905 				errno = EINVAL;
906 				return (-1);
907 			}
908 			if (i == 0) {
909 				port = addr_in6->sin6_port;
910 			} else {
911 				if (port == addr_in6->sin6_port) {
912 					cmsg->cmsg_level = IPPROTO_SCTP;
913 					cmsg->cmsg_type = SCTP_DSTADDRV6;
914 					cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_addr));
915 					memcpy(CMSG_DATA(cmsg), &addr_in6->sin6_addr, sizeof(struct in6_addr));
916 					msg.msg_controllen += CMSG_SPACE(sizeof(struct in6_addr));
917 					cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct in6_addr)));
918 				} else {
919 					free(cmsgbuf);
920 					errno = EINVAL;
921 					return (-1);
922 				}
923 			}
924 			break;
925 		default:
926 			free(cmsgbuf);
927 			errno = EINVAL;
928 			return (-1);
929 		}
930 		if (i == 0) {
931 			msg.msg_name = addr;
932 			msg.msg_namelen = addr_len;
933 		}
934 		addr = (struct sockaddr *)((caddr_t)addr + addr_len);
935 	}
936 	if (msg.msg_controllen == 0) {
937 		msg.msg_control = NULL;
938 	}
939 	msg.msg_iov = __UNCONST(iov);
940 	msg.msg_iovlen = iovcnt;
941 	msg.msg_flags = 0;
942 	ret = sendmsg(sd, &msg, flags);
943 	free(cmsgbuf);
944 	if ((ret >= 0) && (addrs != NULL) && (assoc_id_ptr != NULL)) {
945 		assoc_id = sctp_getassocid(sd, addrs);
946 		memcpy(assoc_id_ptr, &assoc_id, sizeof(assoc_id));
947 	}
948 	return (ret);
949 }
950 
951 int
sctp_peeloff(int sd,sctp_assoc_t assoc_id)952 sctp_peeloff(int sd, sctp_assoc_t assoc_id)
953 {
954 	int ret;
955 	uint32_t val;
956 
957 	val = assoc_id;
958 	ret = ioctl(sd, SIOCPEELOFF, &val);
959 	if (ret == -1)
960 		return ret;
961 	else
962 		return (int) val;
963 }
964 
965