Imported Upstream version 1.0.10
[platform/upstream/lksctp-tools.git] / src / lib / connectx.c
1 /* SCTP kernel Implementation: User API extensions.
2  *
3  * connectx.c
4  *
5  * Distributed under the terms of the LGPL v2.1 as described in
6  * http://www.gnu.org/copyleft/lesser.txt.
7  *
8  * This file is part of the user library that offers support for the
9  * SCTP kernel Implementation. The main purpose of this
10  * code is to provide the SCTP Socket API mappings for user
11  * application to interface with the SCTP in kernel.
12  *
13  * This implementation is based on the Socket API Extensions for SCTP
14  * defined in <draft-ietf-tsvwg-sctpsocket-10.txt.
15  *
16  * (C) Copyright IBM Corp. 2001, 2005
17  *
18  * Written or modified by:
19  *   Frank Filz     <ffilz@us.ibm.com>
20  */
21
22 #include <sys/socket.h>   /* struct sockaddr_storage, setsockopt() */
23 #include <netinet/in.h>
24 #include <netinet/sctp.h> /* SCTP_SOCKOPT_CONNECTX_* */
25 #include <errno.h>
26 #include <stdio.h>
27
28 /* Support the sctp_connectx() interface.
29  *
30  * See Sockets API Extensions for SCTP. Section 8.1.
31  *
32  * Instead of implementing through a socket call in sys_socketcall(),
33  * tunnel the request through setsockopt().
34  */
35 static int __connectx_addrsize(const struct sockaddr *addrs,
36                                      const int addrcnt)
37 {
38         void *addrbuf;
39         struct sockaddr *sa_addr;
40         int addrs_size = 0;
41         int i;
42
43         addrbuf = addrs;
44         for (i = 0; i < addrcnt; i++) {
45                 sa_addr = (struct sockaddr *)addrbuf;
46                 switch (sa_addr->sa_family) {
47                 case AF_INET:
48                         addrs_size += sizeof(struct sockaddr_in);
49                         addrbuf += sizeof(struct sockaddr_in);
50                         break;
51                 case AF_INET6:
52                         addrs_size += sizeof(struct sockaddr_in6);
53                         addrbuf += sizeof(struct sockaddr_in6);
54                         break;
55                 default:
56                         errno = EINVAL;
57                         return -1;
58                 }
59         }
60
61         return addrs_size;
62 }
63                         
64
65 int __sctp_connectx(int fd, struct sockaddr *addrs, int addrcnt)
66 {
67         socklen_t addrs_size = __connectx_addrsize(addrs, addrcnt);
68
69         if (addrs_size < 0)
70                 return addrs_size;
71
72         return setsockopt(fd, SOL_SCTP, SCTP_SOCKOPT_CONNECTX_OLD, addrs,
73                             addrs_size);
74 }
75
76 extern int sctp_connectx_orig (int)
77         __attribute ((alias ("__sctp_connectx")));
78
79 int sctp_connectx_new(int fd, struct sockaddr *addrs, int addrcnt,
80                       sctp_assoc_t *id)
81 {
82         socklen_t addrs_size = __connectx_addrsize(addrs, addrcnt);
83         int status;
84
85         if (addrs_size < 0)
86                 return addrs_size;
87
88         if (id)
89                 *id = 0;
90
91         status =  setsockopt(fd, SOL_SCTP, SCTP_SOCKOPT_CONNECTX, addrs,
92                              addrs_size);
93
94         /* the kernel doesn't support the new connectx interface */
95         if (status < 0 && errno == ENOPROTOOPT)
96                 return setsockopt(fd, SOL_SCTP, SCTP_SOCKOPT_CONNECTX_OLD,
97                                   addrs, addrs_size);
98
99         /* Normalize status and set association id */
100         if (status > 0) {
101                 if (id)
102                         *id = status;
103                 status = 0;
104         }
105
106         return status;
107 }
108
109 __asm__(".symver __sctp_connectx, sctp_connectx@");
110 __asm__(".symver sctp_connectx_orig, sctp_connectx@VERS_1");
111 __asm__(".symver sctp_connectx_new, sctp_connectx@@VERS_2");