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