| /* SCTP kernel Implementation: User API extensions. |
| * |
| * addrs.c |
| * |
| * Distributed under the terms of the LGPL v2.1 as described in |
| * http://www.gnu.org/copyleft/lesser.txt |
| * |
| * This file is part of the user library that offers support for the |
| * SCTP kernel Implementation. The main purpose of this |
| * code is to provide the SCTP Socket API mappings for user |
| * application to interface with the SCTP in kernel. |
| * |
| * This implementation is based on the Socket API Extensions for SCTP |
| * defined in <draft-ietf-tsvwg-sctpsocket-10.txt. |
| * |
| * (C) Copyright IBM Corp. 2003 |
| * Copyright (c) 2001-2002 Intel Corp. |
| * |
| * Written or modified by: |
| * Ardelle Fan <ardelle.fan@intel.com> |
| * Sridhar Samudrala <sri@us.ibm.com> |
| * Ivan Skytte Jørgensen <isj-sctp@i1.dk> |
| */ |
| |
| #include <malloc.h> |
| #include <netinet/in.h> |
| #include <netinet/sctp.h> |
| #include <string.h> |
| #include <errno.h> |
| |
| /* |
| * Common getsockopt() layer |
| * If the NEW getsockopt() API fails this function will fall back to using |
| * the old API |
| */ |
| static int |
| sctp_getaddrs(int sd, sctp_assoc_t id, int optname_new, |
| struct sockaddr **addrs) |
| { |
| int cnt, err; |
| socklen_t len; |
| size_t bufsize = 4096; /*enough for most cases*/ |
| |
| struct sctp_getaddrs *getaddrs = (struct sctp_getaddrs*)malloc(bufsize); |
| if(!getaddrs) |
| return -1; |
| |
| for(;;) { |
| char *new_buf; |
| |
| len = bufsize; |
| getaddrs->assoc_id = id; |
| err = getsockopt(sd, SOL_SCTP, optname_new, getaddrs, &len); |
| if (err == 0) { |
| /*got it*/ |
| break; |
| } |
| if (errno != ENOMEM ) { |
| /*unknown error*/ |
| free(getaddrs); |
| return -1; |
| } |
| /*expand buffer*/ |
| if (bufsize > 128*1024) { |
| /*this is getting ridiculous*/ |
| free(getaddrs); |
| errno = ENOBUFS; |
| return -1; |
| } |
| new_buf = realloc(getaddrs, bufsize+4096); |
| if (!new_buf) { |
| free(getaddrs); |
| return -1; |
| } |
| bufsize += 4096; |
| getaddrs = (struct sctp_getaddrs*)new_buf; |
| } |
| |
| /* we skip traversing the list, allocating a new buffer etc. and enjoy |
| * a simple hack*/ |
| cnt = getaddrs->addr_num; |
| memmove(getaddrs, getaddrs + 1, len); |
| *addrs = (struct sockaddr*)getaddrs; |
| |
| return cnt; |
| } /* sctp_getaddrs() */ |
| |
| /* Get all peer address on a socket. This is a new SCTP API |
| * described in the section 8.3 of the Sockets API Extensions for SCTP. |
| * This is implemented using the getsockopt() interface. |
| */ |
| int |
| sctp_getpaddrs(int sd, sctp_assoc_t id, struct sockaddr **addrs) |
| { |
| return sctp_getaddrs(sd, id, |
| SCTP_GET_PEER_ADDRS, |
| addrs); |
| } /* sctp_getpaddrs() */ |
| |
| /* Frees all resources allocated by sctp_getpaddrs(). This is a new SCTP API |
| * described in the section 8.4 of the Sockets API Extensions for SCTP. |
| */ |
| int |
| sctp_freepaddrs(struct sockaddr *addrs) |
| { |
| free(addrs); |
| return 0; |
| |
| } /* sctp_freepaddrs() */ |
| |
| /* Get all locally bound address on a socket. This is a new SCTP API |
| * described in the section 8.5 of the Sockets API Extensions for SCTP. |
| * This is implemented using the getsockopt() interface. |
| */ |
| int |
| sctp_getladdrs(int sd, sctp_assoc_t id, struct sockaddr **addrs) |
| { |
| return sctp_getaddrs(sd, id, |
| SCTP_GET_LOCAL_ADDRS, |
| addrs); |
| } /* sctp_getladdrs() */ |
| |
| /* Frees all resources allocated by sctp_getladdrs(). This is a new SCTP API |
| * described in the section 8.6 of the Sockets API Extensions for SCTP. |
| */ |
| int |
| sctp_freeladdrs(struct sockaddr *addrs) |
| { |
| free(addrs); |
| return 0; |
| |
| } /* sctp_freeladdrs() */ |
| |
| int |
| sctp_getaddrlen(sa_family_t family) |
| { |
| /* We could call into the kernel to see what it thinks the size should |
| * be, but hardcoding the address families here is: (a) faster, |
| * (b) easier, and (c) probably good enough for forseeable future. |
| */ |
| switch(family) { |
| case AF_INET: |
| return sizeof(struct sockaddr_in); |
| case AF_INET6: |
| return sizeof(struct sockaddr_in6); |
| default: |
| /* Currently there is no defined error handling in |
| * draft-ietf-tsvwg-sctpsocket-13.txt. |
| * -1 might cause the application to overwrite buffer |
| * or misinterpret data. 0 is more likely to cause |
| * an endless loop. |
| */ |
| return 0; |
| } |
| } |