xref: /aosp_15_r20/external/ltp/utils/sctp/lib/connectx.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1*49cdfc7eSAndroid Build Coastguard Worker /* SCTP kernel Implementation: User API extensions.
2*49cdfc7eSAndroid Build Coastguard Worker  *
3*49cdfc7eSAndroid Build Coastguard Worker  * connectx.c
4*49cdfc7eSAndroid Build Coastguard Worker  *
5*49cdfc7eSAndroid Build Coastguard Worker  * Distributed under the terms of the LGPL v2.1 as described in
6*49cdfc7eSAndroid Build Coastguard Worker  * http://www.gnu.org/copyleft/lesser.txt.
7*49cdfc7eSAndroid Build Coastguard Worker  *
8*49cdfc7eSAndroid Build Coastguard Worker  * This file is part of the user library that offers support for the
9*49cdfc7eSAndroid Build Coastguard Worker  * SCTP kernel Implementation. The main purpose of this
10*49cdfc7eSAndroid Build Coastguard Worker  * code is to provide the SCTP Socket API mappings for user
11*49cdfc7eSAndroid Build Coastguard Worker  * application to interface with the SCTP in kernel.
12*49cdfc7eSAndroid Build Coastguard Worker  *
13*49cdfc7eSAndroid Build Coastguard Worker  * This implementation is based on the Socket API Extensions for SCTP
14*49cdfc7eSAndroid Build Coastguard Worker  * defined in <draft-ietf-tsvwg-sctpsocket-10.txt.
15*49cdfc7eSAndroid Build Coastguard Worker  *
16*49cdfc7eSAndroid Build Coastguard Worker  * (C) Copyright IBM Corp. 2001, 2005
17*49cdfc7eSAndroid Build Coastguard Worker  *
18*49cdfc7eSAndroid Build Coastguard Worker  * Written or modified by:
19*49cdfc7eSAndroid Build Coastguard Worker  *   Frank Filz     <[email protected]>
20*49cdfc7eSAndroid Build Coastguard Worker  */
21*49cdfc7eSAndroid Build Coastguard Worker 
22*49cdfc7eSAndroid Build Coastguard Worker #include <sys/socket.h>   /* struct sockaddr_storage, setsockopt() */
23*49cdfc7eSAndroid Build Coastguard Worker #include <netinet/in.h>
24*49cdfc7eSAndroid Build Coastguard Worker #include <netinet/sctp.h> /* SCTP_SOCKOPT_CONNECTX_* */
25*49cdfc7eSAndroid Build Coastguard Worker #include <errno.h>
26*49cdfc7eSAndroid Build Coastguard Worker #include <stdlib.h>
27*49cdfc7eSAndroid Build Coastguard Worker #include <string.h>
28*49cdfc7eSAndroid Build Coastguard Worker #include <fcntl.h>
29*49cdfc7eSAndroid Build Coastguard Worker 
30*49cdfc7eSAndroid Build Coastguard Worker /* Support the sctp_connectx() interface.
31*49cdfc7eSAndroid Build Coastguard Worker  *
32*49cdfc7eSAndroid Build Coastguard Worker  * See Sockets API Extensions for SCTP. Section 8.1.
33*49cdfc7eSAndroid Build Coastguard Worker  *
34*49cdfc7eSAndroid Build Coastguard Worker  * Instead of implementing through a socket call in sys_socketcall(),
35*49cdfc7eSAndroid Build Coastguard Worker  * tunnel the request through setsockopt().
36*49cdfc7eSAndroid Build Coastguard Worker  */
__connectx_addrsize(const struct sockaddr * addrs,const int addrcnt)37*49cdfc7eSAndroid Build Coastguard Worker static int __connectx_addrsize(const struct sockaddr *addrs,
38*49cdfc7eSAndroid Build Coastguard Worker 				const int addrcnt)
39*49cdfc7eSAndroid Build Coastguard Worker {
40*49cdfc7eSAndroid Build Coastguard Worker 	const void *addrbuf;
41*49cdfc7eSAndroid Build Coastguard Worker 	const struct sockaddr *sa_addr;
42*49cdfc7eSAndroid Build Coastguard Worker 	int addrs_size = 0;
43*49cdfc7eSAndroid Build Coastguard Worker 	int i;
44*49cdfc7eSAndroid Build Coastguard Worker 
45*49cdfc7eSAndroid Build Coastguard Worker 	addrbuf = addrs;
46*49cdfc7eSAndroid Build Coastguard Worker 	for (i = 0; i < addrcnt; i++) {
47*49cdfc7eSAndroid Build Coastguard Worker 		sa_addr = (const struct sockaddr *)addrbuf;
48*49cdfc7eSAndroid Build Coastguard Worker 		switch (sa_addr->sa_family) {
49*49cdfc7eSAndroid Build Coastguard Worker 		case AF_INET:
50*49cdfc7eSAndroid Build Coastguard Worker 			addrs_size += sizeof(struct sockaddr_in);
51*49cdfc7eSAndroid Build Coastguard Worker 			addrbuf += sizeof(struct sockaddr_in);
52*49cdfc7eSAndroid Build Coastguard Worker 			break;
53*49cdfc7eSAndroid Build Coastguard Worker 		case AF_INET6:
54*49cdfc7eSAndroid Build Coastguard Worker 			addrs_size += sizeof(struct sockaddr_in6);
55*49cdfc7eSAndroid Build Coastguard Worker 			addrbuf += sizeof(struct sockaddr_in6);
56*49cdfc7eSAndroid Build Coastguard Worker 			break;
57*49cdfc7eSAndroid Build Coastguard Worker 		default:
58*49cdfc7eSAndroid Build Coastguard Worker 			errno = EINVAL;
59*49cdfc7eSAndroid Build Coastguard Worker 			return -1;
60*49cdfc7eSAndroid Build Coastguard Worker 		}
61*49cdfc7eSAndroid Build Coastguard Worker 	}
62*49cdfc7eSAndroid Build Coastguard Worker 
63*49cdfc7eSAndroid Build Coastguard Worker 	return addrs_size;
64*49cdfc7eSAndroid Build Coastguard Worker }
65*49cdfc7eSAndroid Build Coastguard Worker 
66*49cdfc7eSAndroid Build Coastguard Worker 
__sctp_connectx(int fd,struct sockaddr * addrs,int addrcnt)67*49cdfc7eSAndroid Build Coastguard Worker int __sctp_connectx(int fd, struct sockaddr *addrs, int addrcnt)
68*49cdfc7eSAndroid Build Coastguard Worker {
69*49cdfc7eSAndroid Build Coastguard Worker 	int addrs_size = __connectx_addrsize(addrs, addrcnt);
70*49cdfc7eSAndroid Build Coastguard Worker 
71*49cdfc7eSAndroid Build Coastguard Worker 	if (addrs_size < 0)
72*49cdfc7eSAndroid Build Coastguard Worker 		return addrs_size;
73*49cdfc7eSAndroid Build Coastguard Worker 
74*49cdfc7eSAndroid Build Coastguard Worker 	return setsockopt(fd, SOL_SCTP, SCTP_SOCKOPT_CONNECTX_OLD, addrs,
75*49cdfc7eSAndroid Build Coastguard Worker 			    addrs_size);
76*49cdfc7eSAndroid Build Coastguard Worker }
77*49cdfc7eSAndroid Build Coastguard Worker 
78*49cdfc7eSAndroid Build Coastguard Worker extern int sctp_connectx_orig (int)
79*49cdfc7eSAndroid Build Coastguard Worker 	__attribute ((alias ("__sctp_connectx")));
80*49cdfc7eSAndroid Build Coastguard Worker 
81*49cdfc7eSAndroid Build Coastguard Worker 
__connectx(int fd,struct sockaddr * addrs,socklen_t addrs_size,sctp_assoc_t * id)82*49cdfc7eSAndroid Build Coastguard Worker static int __connectx(int fd, struct sockaddr *addrs, socklen_t addrs_size,
83*49cdfc7eSAndroid Build Coastguard Worker 			sctp_assoc_t *id)
84*49cdfc7eSAndroid Build Coastguard Worker {
85*49cdfc7eSAndroid Build Coastguard Worker 	int status;
86*49cdfc7eSAndroid Build Coastguard Worker 
87*49cdfc7eSAndroid Build Coastguard Worker 	if (id)
88*49cdfc7eSAndroid Build Coastguard Worker 		*id = 0;
89*49cdfc7eSAndroid Build Coastguard Worker 
90*49cdfc7eSAndroid Build Coastguard Worker 	status = setsockopt(fd, SOL_SCTP, SCTP_SOCKOPT_CONNECTX, addrs,
91*49cdfc7eSAndroid Build Coastguard Worker 			    addrs_size);
92*49cdfc7eSAndroid Build Coastguard Worker 
93*49cdfc7eSAndroid Build Coastguard Worker 	/* Normalize status and set association id */
94*49cdfc7eSAndroid Build Coastguard Worker 	if (status > 0) {
95*49cdfc7eSAndroid Build Coastguard Worker 		if (id)
96*49cdfc7eSAndroid Build Coastguard Worker 			*id = status;
97*49cdfc7eSAndroid Build Coastguard Worker 		return 0;
98*49cdfc7eSAndroid Build Coastguard Worker 	}
99*49cdfc7eSAndroid Build Coastguard Worker 
100*49cdfc7eSAndroid Build Coastguard Worker 	/* The error is something other then "Option not supported" */
101*49cdfc7eSAndroid Build Coastguard Worker 	if (status < 0 && errno != ENOPROTOOPT)
102*49cdfc7eSAndroid Build Coastguard Worker 		return status;
103*49cdfc7eSAndroid Build Coastguard Worker 
104*49cdfc7eSAndroid Build Coastguard Worker 	/* At this point, if the application wanted the id, we can't
105*49cdfc7eSAndroid Build Coastguard Worker 	 * really provide it, so we can return ENOPROTOOPT.
106*49cdfc7eSAndroid Build Coastguard Worker 	 */
107*49cdfc7eSAndroid Build Coastguard Worker 	if (id) {
108*49cdfc7eSAndroid Build Coastguard Worker 		errno = ENOPROTOOPT;
109*49cdfc7eSAndroid Build Coastguard Worker 		return -1;
110*49cdfc7eSAndroid Build Coastguard Worker 	}
111*49cdfc7eSAndroid Build Coastguard Worker 
112*49cdfc7eSAndroid Build Coastguard Worker 	/* Finally, try the old API */
113*49cdfc7eSAndroid Build Coastguard Worker 	return setsockopt(fd, SOL_SCTP, SCTP_SOCKOPT_CONNECTX_OLD,
114*49cdfc7eSAndroid Build Coastguard Worker 			  addrs, addrs_size);
115*49cdfc7eSAndroid Build Coastguard Worker }
116*49cdfc7eSAndroid Build Coastguard Worker 
sctp_connectx2(int fd,struct sockaddr * addrs,int addrcnt,sctp_assoc_t * id)117*49cdfc7eSAndroid Build Coastguard Worker int sctp_connectx2(int fd, struct sockaddr *addrs, int addrcnt,
118*49cdfc7eSAndroid Build Coastguard Worker 		      sctp_assoc_t *id)
119*49cdfc7eSAndroid Build Coastguard Worker {
120*49cdfc7eSAndroid Build Coastguard Worker 	int addrs_size = __connectx_addrsize(addrs, addrcnt);
121*49cdfc7eSAndroid Build Coastguard Worker 
122*49cdfc7eSAndroid Build Coastguard Worker 	if (addrs_size < 0)
123*49cdfc7eSAndroid Build Coastguard Worker 		return addrs_size;
124*49cdfc7eSAndroid Build Coastguard Worker 
125*49cdfc7eSAndroid Build Coastguard Worker 	return __connectx(fd, addrs, addrs_size, id);
126*49cdfc7eSAndroid Build Coastguard Worker }
127*49cdfc7eSAndroid Build Coastguard Worker 
sctp_connectx3(int fd,struct sockaddr * addrs,int addrcnt,sctp_assoc_t * id)128*49cdfc7eSAndroid Build Coastguard Worker int sctp_connectx3(int fd, struct sockaddr *addrs, int addrcnt,
129*49cdfc7eSAndroid Build Coastguard Worker 		      sctp_assoc_t *id)
130*49cdfc7eSAndroid Build Coastguard Worker {
131*49cdfc7eSAndroid Build Coastguard Worker 	int addrs_size = __connectx_addrsize(addrs, addrcnt);
132*49cdfc7eSAndroid Build Coastguard Worker 	int status;
133*49cdfc7eSAndroid Build Coastguard Worker 	struct sctp_getaddrs_old param;
134*49cdfc7eSAndroid Build Coastguard Worker 	socklen_t opt_len = sizeof(param);
135*49cdfc7eSAndroid Build Coastguard Worker 
136*49cdfc7eSAndroid Build Coastguard Worker 	if (addrs_size < 0)
137*49cdfc7eSAndroid Build Coastguard Worker 		return addrs_size;
138*49cdfc7eSAndroid Build Coastguard Worker 
139*49cdfc7eSAndroid Build Coastguard Worker 	/* First try the new socket api
140*49cdfc7eSAndroid Build Coastguard Worker 	 * Because the id is returned in the option buffer we have prepend
141*49cdfc7eSAndroid Build Coastguard Worker 	 * 32bit to it for the returned association id
142*49cdfc7eSAndroid Build Coastguard Worker 	 */
143*49cdfc7eSAndroid Build Coastguard Worker 	param.assoc_id = 0;
144*49cdfc7eSAndroid Build Coastguard Worker 	param.addr_num = addrs_size;
145*49cdfc7eSAndroid Build Coastguard Worker 	param.addrs = addrs;
146*49cdfc7eSAndroid Build Coastguard Worker 	status = getsockopt(fd, SOL_SCTP, SCTP_SOCKOPT_CONNECTX3,
147*49cdfc7eSAndroid Build Coastguard Worker 		            &param, &opt_len);
148*49cdfc7eSAndroid Build Coastguard Worker 	if (status == 0 || errno == EINPROGRESS) {
149*49cdfc7eSAndroid Build Coastguard Worker 		/* Succeeded immediately, or initiated on non-blocking
150*49cdfc7eSAndroid Build Coastguard Worker 		 * socket.
151*49cdfc7eSAndroid Build Coastguard Worker 		 */
152*49cdfc7eSAndroid Build Coastguard Worker 		if (id)
153*49cdfc7eSAndroid Build Coastguard Worker 			*id = param.assoc_id;
154*49cdfc7eSAndroid Build Coastguard Worker 	}
155*49cdfc7eSAndroid Build Coastguard Worker 
156*49cdfc7eSAndroid Build Coastguard Worker 	if (errno != ENOPROTOOPT) {
157*49cdfc7eSAndroid Build Coastguard Worker 		/* No point in trying the fallbacks*/
158*49cdfc7eSAndroid Build Coastguard Worker 		return status;
159*49cdfc7eSAndroid Build Coastguard Worker 	}
160*49cdfc7eSAndroid Build Coastguard Worker 
161*49cdfc7eSAndroid Build Coastguard Worker 	/* The first incarnation of updated connectx api didn't work for
162*49cdfc7eSAndroid Build Coastguard Worker 	 * non-blocking sockets.  So if the application wants the association
163*49cdfc7eSAndroid Build Coastguard Worker 	 * id and the socket is non-blocking, we can't really do anything.
164*49cdfc7eSAndroid Build Coastguard Worker 	 */
165*49cdfc7eSAndroid Build Coastguard Worker 	if (id) {
166*49cdfc7eSAndroid Build Coastguard Worker 		/* Program wants the association-id returned. We can only do
167*49cdfc7eSAndroid Build Coastguard Worker 		 * that if the socket is blocking */
168*49cdfc7eSAndroid Build Coastguard Worker 		status = fcntl(fd, F_GETFL);
169*49cdfc7eSAndroid Build Coastguard Worker 		if (status < 0)
170*49cdfc7eSAndroid Build Coastguard Worker 			return status;
171*49cdfc7eSAndroid Build Coastguard Worker 
172*49cdfc7eSAndroid Build Coastguard Worker 		if (status & O_NONBLOCK) {
173*49cdfc7eSAndroid Build Coastguard Worker 			/* Socket is non-blocking. Fail */
174*49cdfc7eSAndroid Build Coastguard Worker 			errno = ENOPROTOOPT;
175*49cdfc7eSAndroid Build Coastguard Worker 			return -1;
176*49cdfc7eSAndroid Build Coastguard Worker 		}
177*49cdfc7eSAndroid Build Coastguard Worker 	}
178*49cdfc7eSAndroid Build Coastguard Worker 
179*49cdfc7eSAndroid Build Coastguard Worker 	return __connectx(fd, addrs, addrs_size, id);
180*49cdfc7eSAndroid Build Coastguard Worker }
181*49cdfc7eSAndroid Build Coastguard Worker 
182*49cdfc7eSAndroid Build Coastguard Worker #define __SYMPFX(pfx, sym) #pfx sym
183*49cdfc7eSAndroid Build Coastguard Worker #define _SYMPFX(pfx, sym) __SYMPFX(pfx, sym)
184*49cdfc7eSAndroid Build Coastguard Worker #define SYMPFX(sym) _SYMPFX(__USER_LABEL_PREFIX__, #sym)
185*49cdfc7eSAndroid Build Coastguard Worker #define SYMVER(name, name2) __asm__(".symver " SYMPFX(name) "," SYMPFX(name2))
186*49cdfc7eSAndroid Build Coastguard Worker 
187*49cdfc7eSAndroid Build Coastguard Worker SYMVER(__sctp_connectx, sctp_connectx@);
188*49cdfc7eSAndroid Build Coastguard Worker SYMVER(sctp_connectx_orig, sctp_connectx@VERS_1);
189*49cdfc7eSAndroid Build Coastguard Worker SYMVER(sctp_connectx2, sctp_connectx@VERS_2);
190*49cdfc7eSAndroid Build Coastguard Worker SYMVER(sctp_connectx3, sctp_connectx@@VERS_3);
191