16f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu/* SCTP kernel Implementation: User API extensions. 26f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu * 36f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu * connectx.c 46f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu * 56f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu * Distributed under the terms of the LGPL v2.1 as described in 66f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu * http://www.gnu.org/copyleft/lesser.txt. 76f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu * 86f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu * This file is part of the user library that offers support for the 96f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu * SCTP kernel Implementation. The main purpose of this 106f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu * code is to provide the SCTP Socket API mappings for user 116f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu * application to interface with the SCTP in kernel. 126f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu * 136f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu * This implementation is based on the Socket API Extensions for SCTP 146f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu * defined in <draft-ietf-tsvwg-sctpsocket-10.txt. 156f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu * 166f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu * (C) Copyright IBM Corp. 2001, 2005 176f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu * 186f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu * Written or modified by: 196f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu * Frank Filz <ffilz@us.ibm.com> 206f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu */ 216f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu 226f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu#include <sys/socket.h> /* struct sockaddr_storage, setsockopt() */ 236f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu#include <netinet/in.h> 246f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu#include <netinet/sctp.h> /* SCTP_SOCKOPT_CONNECTX_* */ 256f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu#include <errno.h> 266f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu#include <stdlib.h> 276f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu#include <string.h> 286f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu#include <fcntl.h> 296f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu 306f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu/* Support the sctp_connectx() interface. 316f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu * 326f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu * See Sockets API Extensions for SCTP. Section 8.1. 336f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu * 346f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu * Instead of implementing through a socket call in sys_socketcall(), 356f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu * tunnel the request through setsockopt(). 366f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu */ 376f22494d19b605ded308dc0fa713e91cb873f44aSimon Xustatic int __connectx_addrsize(const struct sockaddr *addrs, 386f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu const int addrcnt) 396f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu{ 406f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu const void *addrbuf; 416f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu const struct sockaddr *sa_addr; 426f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu int addrs_size = 0; 436f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu int i; 446f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu 456f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu addrbuf = addrs; 466f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu for (i = 0; i < addrcnt; i++) { 476f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu sa_addr = (const struct sockaddr *)addrbuf; 486f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu switch (sa_addr->sa_family) { 496f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu case AF_INET: 506f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu addrs_size += sizeof(struct sockaddr_in); 516f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu addrbuf += sizeof(struct sockaddr_in); 526f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu break; 536f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu case AF_INET6: 546f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu addrs_size += sizeof(struct sockaddr_in6); 556f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu addrbuf += sizeof(struct sockaddr_in6); 566f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu break; 576f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu default: 586f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu errno = EINVAL; 596f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu return -1; 606f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu } 616f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu } 626f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu 636f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu return addrs_size; 646f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu} 656f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu 666f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu 676f22494d19b605ded308dc0fa713e91cb873f44aSimon Xuint __sctp_connectx(int fd, struct sockaddr *addrs, int addrcnt) 686f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu{ 699d048f81cb2c60d2f019ea3677f12928f8629cf1Zeng Linggang int addrs_size = __connectx_addrsize(addrs, addrcnt); 706f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu 716f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu if (addrs_size < 0) 726f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu return addrs_size; 736f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu 746f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu return setsockopt(fd, SOL_SCTP, SCTP_SOCKOPT_CONNECTX_OLD, addrs, 756f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu addrs_size); 766f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu} 776f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu 786f22494d19b605ded308dc0fa713e91cb873f44aSimon Xuextern int sctp_connectx_orig (int) 796f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu __attribute ((alias ("__sctp_connectx"))); 806f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu 816f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu 826f22494d19b605ded308dc0fa713e91cb873f44aSimon Xustatic int __connectx(int fd, struct sockaddr *addrs, socklen_t addrs_size, 836f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu sctp_assoc_t *id) 846f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu{ 856f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu int status; 866f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu 876f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu if (id) 886f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu *id = 0; 896f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu 906f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu status = setsockopt(fd, SOL_SCTP, SCTP_SOCKOPT_CONNECTX, addrs, 916f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu addrs_size); 926f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu 936f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu /* Normalize status and set association id */ 946f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu if (status > 0) { 956f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu if (id) 966f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu *id = status; 976f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu return 0; 986f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu } 996f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu 1006f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu /* The error is something other then "Option not supported" */ 1016f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu if (status < 0 && errno != ENOPROTOOPT) 1026f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu return status; 1036f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu 1046f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu /* At this point, if the application wanted the id, we can't 1056f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu * really provide it, so we can return ENOPROTOOPT. 1066f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu */ 1076f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu if (id) { 1086f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu errno = ENOPROTOOPT; 1096f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu return -1; 1106f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu } 1116f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu 1126f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu /* Finally, try the old API */ 1136f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu return setsockopt(fd, SOL_SCTP, SCTP_SOCKOPT_CONNECTX_OLD, 1146f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu addrs, addrs_size); 1156f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu} 1166f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu 1176f22494d19b605ded308dc0fa713e91cb873f44aSimon Xuint sctp_connectx2(int fd, struct sockaddr *addrs, int addrcnt, 1186f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu sctp_assoc_t *id) 1196f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu{ 1209d048f81cb2c60d2f019ea3677f12928f8629cf1Zeng Linggang int addrs_size = __connectx_addrsize(addrs, addrcnt); 1216f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu 1226f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu if (addrs_size < 0) 1236f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu return addrs_size; 1246f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu 1256f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu return __connectx(fd, addrs, addrs_size, id); 1266f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu} 1276f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu 1286f22494d19b605ded308dc0fa713e91cb873f44aSimon Xuint sctp_connectx3(int fd, struct sockaddr *addrs, int addrcnt, 1296f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu sctp_assoc_t *id) 1306f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu{ 1319d048f81cb2c60d2f019ea3677f12928f8629cf1Zeng Linggang int addrs_size = __connectx_addrsize(addrs, addrcnt); 1326f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu int status; 1336f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu struct sctp_getaddrs_old param; 1346f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu socklen_t opt_len = sizeof(param); 1356f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu 1366f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu if (addrs_size < 0) 1376f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu return addrs_size; 1386f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu 1396f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu /* First try the new socket api 1406f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu * Because the id is returned in the option buffer we have prepend 1416f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu * 32bit to it for the returned association id 1426f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu */ 1436f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu param.assoc_id = 0; 1446f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu param.addr_num = addrs_size; 1456f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu param.addrs = addrs; 1466f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu status = getsockopt(fd, SOL_SCTP, SCTP_SOCKOPT_CONNECTX3, 1476f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu ¶m, &opt_len); 1486f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu if (status == 0 || errno == EINPROGRESS) { 1496f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu /* Succeeded immediately, or initiated on non-blocking 1506f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu * socket. 1516f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu */ 1526f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu if (id) 1536f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu *id = param.assoc_id; 1546f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu } 1556f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu 1566f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu if (errno != ENOPROTOOPT) { 1576f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu /* No point in trying the fallbacks*/ 1586f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu return status; 1596f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu } 1606f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu 1616f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu /* The first incarnation of updated connectx api didn't work for 1626f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu * non-blocking sockets. So if the application wants the association 1636f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu * id and the socket is non-blocking, we can't really do anything. 1646f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu */ 1656f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu if (id) { 1666f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu /* Program wants the association-id returned. We can only do 1676f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu * that if the socket is blocking */ 1686f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu status = fcntl(fd, F_GETFL); 1696f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu if (status < 0) 1706f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu return status; 1716f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu 1726f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu if (status & O_NONBLOCK) { 1736f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu /* Socket is non-blocking. Fail */ 1746f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu errno = ENOPROTOOPT; 1756f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu return -1; 1766f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu } 1776f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu } 1786f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu 1796f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu return __connectx(fd, addrs, addrs_size, id); 1806f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu} 1816f22494d19b605ded308dc0fa713e91cb873f44aSimon Xu 182699a579e3d8a30bc4cec93616696848a8ae8b225Markos Chandras#define __SYMPFX(pfx, sym) #pfx sym 183699a579e3d8a30bc4cec93616696848a8ae8b225Markos Chandras#define _SYMPFX(pfx, sym) __SYMPFX(pfx, sym) 184699a579e3d8a30bc4cec93616696848a8ae8b225Markos Chandras#define SYMPFX(sym) _SYMPFX(__USER_LABEL_PREFIX__, #sym) 185699a579e3d8a30bc4cec93616696848a8ae8b225Markos Chandras#define SYMVER(name, name2) __asm__(".symver " SYMPFX(name) "," SYMPFX(name2)) 186699a579e3d8a30bc4cec93616696848a8ae8b225Markos Chandras 187699a579e3d8a30bc4cec93616696848a8ae8b225Markos ChandrasSYMVER(__sctp_connectx, sctp_connectx@); 188699a579e3d8a30bc4cec93616696848a8ae8b225Markos ChandrasSYMVER(sctp_connectx_orig, sctp_connectx@VERS_1); 189699a579e3d8a30bc4cec93616696848a8ae8b225Markos ChandrasSYMVER(sctp_connectx2, sctp_connectx@VERS_2); 190699a579e3d8a30bc4cec93616696848a8ae8b225Markos ChandrasSYMVER(sctp_connectx3, sctp_connectx@@VERS_3); 191