1/* SCTP kernel Implementation: User API extensions.
2 *
3 * addrs.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. 2003
17 * Copyright (c) 2001-2002 Intel Corp.
18 *
19 * Written or modified by:
20 *  Ardelle Fan     <ardelle.fan@intel.com>
21 *  Sridhar Samudrala <sri@us.ibm.com>
22 *  Ivan Skytte Jørgensen <isj-sctp@i1.dk>
23 */
24
25#include <malloc.h>
26#include <netinet/in.h>
27#include <netinet/sctp.h>
28#include <string.h>
29#include <errno.h>
30
31/*
32 * Common getsockopt() layer
33 * If the NEW getsockopt() API fails this function will fall back to using
34 * the old API
35 */
36static int
37sctp_getaddrs(int sd, sctp_assoc_t id, int optname_new,
38	      struct sockaddr **addrs)
39{
40	int cnt, err;
41	socklen_t len;
42	size_t bufsize = 4096; /*enough for most cases*/
43
44	struct sctp_getaddrs *getaddrs = (struct sctp_getaddrs*)malloc(bufsize);
45	if(!getaddrs)
46		return -1;
47
48	for(;;) {
49		char *new_buf;
50
51		len = bufsize;
52		getaddrs->assoc_id = id;
53		err = getsockopt(sd, SOL_SCTP, optname_new, getaddrs, &len);
54		if (err == 0) {
55			/*got it*/
56			break;
57		}
58		if (errno != ENOMEM ) {
59			/*unknown error*/
60			free(getaddrs);
61			return -1;
62		}
63		/*expand buffer*/
64		if (bufsize > 128*1024) {
65			/*this is getting ridiculous*/
66			free(getaddrs);
67			errno = ENOBUFS;
68			return -1;
69		}
70		new_buf = realloc(getaddrs, bufsize+4096);
71		if (!new_buf) {
72			free(getaddrs);
73			return -1;
74		}
75		bufsize += 4096;
76		getaddrs = (struct sctp_getaddrs*)new_buf;
77	}
78
79	/* we skip traversing the list, allocating a new buffer etc. and enjoy
80	 * a simple hack*/
81	cnt = getaddrs->addr_num;
82	memmove(getaddrs, getaddrs + 1, len);
83	*addrs = (struct sockaddr*)getaddrs;
84
85	return cnt;
86} /* sctp_getaddrs() */
87
88/* Get all peer address on a socket.  This is a new SCTP API
89 * described in the section 8.3 of the Sockets API Extensions for SCTP.
90 * This is implemented using the getsockopt() interface.
91 */
92int
93sctp_getpaddrs(int sd, sctp_assoc_t id, struct sockaddr **addrs)
94{
95	return sctp_getaddrs(sd, id,
96			     SCTP_GET_PEER_ADDRS,
97			     addrs);
98} /* sctp_getpaddrs() */
99
100/* Frees all resources allocated by sctp_getpaddrs().  This is a new SCTP API
101 * described in the section 8.4 of the Sockets API Extensions for SCTP.
102 */
103int
104sctp_freepaddrs(struct sockaddr *addrs)
105{
106	free(addrs);
107	return 0;
108
109} /* sctp_freepaddrs() */
110
111/* Get all locally bound address on a socket.  This is a new SCTP API
112 * described in the section 8.5 of the Sockets API Extensions for SCTP.
113 * This is implemented using the getsockopt() interface.
114 */
115int
116sctp_getladdrs(int sd, sctp_assoc_t id, struct sockaddr **addrs)
117{
118	return sctp_getaddrs(sd, id,
119			     SCTP_GET_LOCAL_ADDRS,
120			     addrs);
121} /* sctp_getladdrs() */
122
123/* Frees all resources allocated by sctp_getladdrs().  This is a new SCTP API
124 * described in the section 8.6 of the Sockets API Extensions for SCTP.
125 */
126int
127sctp_freeladdrs(struct sockaddr *addrs)
128{
129	free(addrs);
130	return 0;
131
132} /* sctp_freeladdrs() */
133
134int
135sctp_getaddrlen(sa_family_t family)
136{
137	/* We could call into the kernel to see what it thinks the size should
138	 * be, but hardcoding the address families here is: (a) faster,
139	 * (b) easier, and (c) probably good enough for forseeable future.
140	 */
141	switch(family) {
142	case AF_INET:
143		return sizeof(struct sockaddr_in);
144	case AF_INET6:
145		return sizeof(struct sockaddr_in6);
146	default:
147		/* Currently there is no defined error handling in
148		 * draft-ietf-tsvwg-sctpsocket-13.txt.
149		 * -1 might cause the application to overwrite buffer
150		 * or misinterpret data. 0 is more likely to cause
151		 * an endless loop.
152		 */
153		return 0;
154	}
155}
156