OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [net/] [sctp/] [bind_addr.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/* SCTP kernel reference Implementation
2
 * (C) Copyright IBM Corp. 2001, 2003
3
 * Copyright (c) Cisco 1999,2000
4
 * Copyright (c) Motorola 1999,2000,2001
5
 * Copyright (c) La Monte H.P. Yarroll 2001
6
 *
7
 * This file is part of the SCTP kernel reference implementation.
8
 *
9
 * A collection class to handle the storage of transport addresses.
10
 *
11
 * The SCTP reference implementation is free software;
12
 * you can redistribute it and/or modify it under the terms of
13
 * the GNU General Public License as published by
14
 * the Free Software Foundation; either version 2, or (at your option)
15
 * any later version.
16
 *
17
 * The SCTP reference implementation is distributed in the hope that it
18
 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
19
 *                 ************************
20
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
21
 * See the GNU General Public License for more details.
22
 *
23
 * You should have received a copy of the GNU General Public License
24
 * along with GNU CC; see the file COPYING.  If not, write to
25
 * the Free Software Foundation, 59 Temple Place - Suite 330,
26
 * Boston, MA 02111-1307, USA.
27
 *
28
 * Please send any bug reports or fixes you make to the
29
 * email address(es):
30
 *    lksctp developers <lksctp-developers@lists.sourceforge.net>
31
 *
32
 * Or submit a bug report through the following website:
33
 *    http://www.sf.net/projects/lksctp
34
 *
35
 * Written or modified by:
36
 *    La Monte H.P. Yarroll <piggy@acm.org>
37
 *    Karl Knutson          <karl@athena.chicago.il.us>
38
 *    Jon Grimm             <jgrimm@us.ibm.com>
39
 *    Daisy Chang           <daisyc@us.ibm.com>
40
 *
41
 * Any bugs reported given to us we will try to fix... any fixes shared will
42
 * be incorporated into the next SCTP release.
43
 */
44
 
45
#include <linux/types.h>
46
#include <linux/sched.h>
47
#include <linux/in.h>
48
#include <net/sock.h>
49
#include <net/ipv6.h>
50
#include <net/if_inet6.h>
51
#include <net/sctp/sctp.h>
52
#include <net/sctp/sm.h>
53
 
54
/* Forward declarations for internal helpers. */
55
static int sctp_copy_one_addr(struct sctp_bind_addr *, union sctp_addr *,
56
                              sctp_scope_t scope, int gfp, int flags);
57
static void sctp_bind_addr_clean(struct sctp_bind_addr *);
58
 
59
/* First Level Abstractions. */
60
 
61
/* Copy 'src' to 'dest' taking 'scope' into account.  Omit addresses
62
 * in 'src' which have a broader scope than 'scope'.
63
 */
64
int sctp_bind_addr_copy(struct sctp_bind_addr *dest,
65
                        const struct sctp_bind_addr *src,
66
                        sctp_scope_t scope, int gfp, int flags)
67
{
68
        struct sctp_sockaddr_entry *addr;
69
        struct list_head *pos;
70
        int error = 0;
71
 
72
        /* All addresses share the same port.  */
73
        dest->port = src->port;
74
 
75
        /* Extract the addresses which are relevant for this scope.  */
76
        list_for_each(pos, &src->address_list) {
77
                addr = list_entry(pos, struct sctp_sockaddr_entry, list);
78
                error = sctp_copy_one_addr(dest, &addr->a, scope,
79
                                           gfp, flags);
80
                if (error < 0)
81
                        goto out;
82
        }
83
 
84
        /* If there are no addresses matching the scope and
85
         * this is global scope, try to get a link scope address, with
86
         * the assumption that we must be sitting behind a NAT.
87
         */
88
        if (list_empty(&dest->address_list) && (SCTP_SCOPE_GLOBAL == scope)) {
89
                list_for_each(pos, &src->address_list) {
90
                        addr = list_entry(pos, struct sctp_sockaddr_entry,
91
                                          list);
92
                        error = sctp_copy_one_addr(dest, &addr->a,
93
                                                   SCTP_SCOPE_LINK, gfp,
94
                                                   flags);
95
                        if (error < 0)
96
                                goto out;
97
                }
98
        }
99
 
100
out:
101
        if (error)
102
                sctp_bind_addr_clean(dest);
103
 
104
        return error;
105
}
106
 
107
/* Create a new SCTP_bind_addr from nothing.  */
108
struct sctp_bind_addr *sctp_bind_addr_new(int gfp)
109
{
110
        struct sctp_bind_addr *retval;
111
 
112
        retval = t_new(struct sctp_bind_addr, gfp);
113
        if (!retval)
114
                goto nomem;
115
 
116
        sctp_bind_addr_init(retval, 0);
117
        retval->malloced = 1;
118
        SCTP_DBG_OBJCNT_INC(bind_addr);
119
 
120
nomem:
121
        return retval;
122
}
123
 
124
/* Initialize the SCTP_bind_addr structure for either an endpoint or
125
 * an association.
126
 */
127
void sctp_bind_addr_init(struct sctp_bind_addr *bp, __u16 port)
128
{
129
        bp->malloced = 0;
130
 
131
        INIT_LIST_HEAD(&bp->address_list);
132
        bp->port = port;
133
}
134
 
135
/* Dispose of the address list. */
136
static void sctp_bind_addr_clean(struct sctp_bind_addr *bp)
137
{
138
        struct sctp_sockaddr_entry *addr;
139
        struct list_head *pos, *temp;
140
 
141
        /* Empty the bind address list. */
142
        list_for_each_safe(pos, temp, &bp->address_list) {
143
                addr = list_entry(pos, struct sctp_sockaddr_entry, list);
144
                list_del(pos);
145
                kfree(addr);
146
                SCTP_DBG_OBJCNT_DEC(addr);
147
        }
148
}
149
 
150
/* Dispose of an SCTP_bind_addr structure  */
151
void sctp_bind_addr_free(struct sctp_bind_addr *bp)
152
{
153
        /* Empty the bind address list. */
154
        sctp_bind_addr_clean(bp);
155
 
156
        if (bp->malloced) {
157
                kfree(bp);
158
                SCTP_DBG_OBJCNT_DEC(bind_addr);
159
        }
160
}
161
 
162
/* Add an address to the bind address list in the SCTP_bind_addr structure. */
163
int sctp_add_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *new,
164
                       int gfp)
165
{
166
        struct sctp_sockaddr_entry *addr;
167
 
168
        /* Add the address to the bind address list.  */
169
        addr = t_new(struct sctp_sockaddr_entry, gfp);
170
        if (!addr)
171
                return -ENOMEM;
172
 
173
        memcpy(&addr->a, new, sizeof(*new));
174
 
175
        /* Fix up the port if it has not yet been set.
176
         * Both v4 and v6 have the port at the same offset.
177
         */
178
        if (!addr->a.v4.sin_port)
179
                addr->a.v4.sin_port = bp->port;
180
 
181
        INIT_LIST_HEAD(&addr->list);
182
        list_add_tail(&addr->list, &bp->address_list);
183
        SCTP_DBG_OBJCNT_INC(addr);
184
 
185
        return 0;
186
}
187
 
188
/* Delete an address from the bind address list in the SCTP_bind_addr
189
 * structure.
190
 */
191
int sctp_del_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *del_addr)
192
{
193
        struct list_head *pos, *temp;
194
        struct sctp_sockaddr_entry *addr;
195
 
196
        list_for_each_safe(pos, temp, &bp->address_list) {
197
                addr = list_entry(pos, struct sctp_sockaddr_entry, list);
198
                if (sctp_cmp_addr_exact(&addr->a, del_addr)) {
199
                        /* Found the exact match. */
200
                        list_del(pos);
201
                        kfree(addr);
202
                        SCTP_DBG_OBJCNT_DEC(addr);
203
 
204
                        return 0;
205
                }
206
        }
207
 
208
        return -EINVAL;
209
}
210
 
211
/* Create a network byte-order representation of all the addresses
212
 * formated as SCTP parameters.
213
 *
214
 * The second argument is the return value for the length.
215
 */
216
union sctp_params sctp_bind_addrs_to_raw(const struct sctp_bind_addr *bp,
217
                                         int *addrs_len, int gfp)
218
{
219
        union sctp_params addrparms;
220
        union sctp_params retval;
221
        int addrparms_len;
222
        union sctp_addr_param rawaddr;
223
        int len;
224
        struct sctp_sockaddr_entry *addr;
225
        struct list_head *pos;
226
        struct sctp_af *af;
227
 
228
        addrparms_len = 0;
229
        len = 0;
230
 
231
        /* Allocate enough memory at once. */
232
        list_for_each(pos, &bp->address_list) {
233
                len += sizeof(union sctp_addr_param);
234
        }
235
 
236
        /* Don't even bother embedding an address if there
237
         * is only one.
238
         */
239
        if (len == sizeof(union sctp_addr_param)) {
240
                retval.v = NULL;
241
                goto end_raw;
242
        }
243
 
244
        retval.v = kmalloc(len, gfp);
245
        if (!retval.v)
246
                goto end_raw;
247
 
248
        addrparms = retval;
249
 
250
        list_for_each(pos, &bp->address_list) {
251
                addr = list_entry(pos, struct sctp_sockaddr_entry, list);
252
                af = sctp_get_af_specific(addr->a.v4.sin_family);
253
                len = af->to_addr_param(&addr->a, &rawaddr);
254
                memcpy(addrparms.v, &rawaddr, len);
255
                addrparms.v += len;
256
                addrparms_len += len;
257
        }
258
 
259
end_raw:
260
        *addrs_len = addrparms_len;
261
        return retval;
262
}
263
 
264
/*
265
 * Create an address list out of the raw address list format (IPv4 and IPv6
266
 * address parameters).
267
 */
268
int sctp_raw_to_bind_addrs(struct sctp_bind_addr *bp, __u8 *raw_addr_list,
269
                           int addrs_len, __u16 port, int gfp)
270
{
271
        union sctp_addr_param *rawaddr;
272
        struct sctp_paramhdr *param;
273
        union sctp_addr addr;
274
        int retval = 0;
275
        int len;
276
        struct sctp_af *af;
277
 
278
        /* Convert the raw address to standard address format */
279
        while (addrs_len) {
280
                param = (struct sctp_paramhdr *)raw_addr_list;
281
                rawaddr = (union sctp_addr_param *)raw_addr_list;
282
 
283
                af = sctp_get_af_specific(param_type2af(param->type));
284
                if (unlikely(!af)) {
285
                        retval = -EINVAL;
286
                        sctp_bind_addr_clean(bp);
287
                        break;
288
                }
289
 
290
                af->from_addr_param(&addr, rawaddr, port, 0);
291
                retval = sctp_add_bind_addr(bp, &addr, gfp);
292
                if (retval) {
293
                        /* Can't finish building the list, clean up. */
294
                        sctp_bind_addr_clean(bp);
295
                        break;;
296
                }
297
 
298
                len = ntohs(param->length);
299
                addrs_len -= len;
300
                raw_addr_list += len;
301
        }
302
 
303
        return retval;
304
}
305
 
306
/********************************************************************
307
 * 2nd Level Abstractions
308
 ********************************************************************/
309
 
310
/* Does this contain a specified address?  Allow wildcarding. */
311
int sctp_bind_addr_match(struct sctp_bind_addr *bp,
312
                         const union sctp_addr *addr,
313
                         struct sctp_opt *opt)
314
{
315
        struct sctp_sockaddr_entry *laddr;
316
        struct list_head *pos;
317
 
318
        list_for_each(pos, &bp->address_list) {
319
                laddr = list_entry(pos, struct sctp_sockaddr_entry, list);
320
                if (opt->pf->cmp_addr(&laddr->a, addr, opt))
321
                        return 1;
322
        }
323
 
324
        return 0;
325
}
326
 
327
/* Find the first address in the bind address list that is not present in
328
 * the addrs packed array.
329
 */
330
union sctp_addr *sctp_find_unmatch_addr(struct sctp_bind_addr   *bp,
331
                                        const union sctp_addr   *addrs,
332
                                        int                     addrcnt,
333
                                        struct sctp_opt         *opt)
334
{
335
        struct sctp_sockaddr_entry      *laddr;
336
        union sctp_addr                 *addr;
337
        void                            *addr_buf;
338
        struct sctp_af                  *af;
339
        struct list_head                *pos;
340
        int                             i;
341
 
342
        list_for_each(pos, &bp->address_list) {
343
                laddr = list_entry(pos, struct sctp_sockaddr_entry, list);
344
 
345
                addr_buf = (union sctp_addr *)addrs;
346
                for (i = 0; i < addrcnt; i++) {
347
                        addr = (union sctp_addr *)addr_buf;
348
                        af = sctp_get_af_specific(addr->v4.sin_family);
349
                        if (!af)
350
                                return NULL;
351
 
352
                        if (opt->pf->cmp_addr(&laddr->a, addr, opt))
353
                                break;
354
 
355
                        addr_buf += af->sockaddr_len;
356
                }
357
                if (i == addrcnt)
358
                        return &laddr->a;
359
        }
360
 
361
        return NULL;
362
}
363
 
364
/* Copy out addresses from the global local address list. */
365
static int sctp_copy_one_addr(struct sctp_bind_addr *dest,
366
                              union sctp_addr *addr,
367
                              sctp_scope_t scope, int gfp, int flags)
368
{
369
        int error = 0;
370
 
371
        if (sctp_is_any(addr)) {
372
                error = sctp_copy_local_addr_list(dest, scope, gfp, flags);
373
        } else if (sctp_in_scope(addr, scope)) {
374
                /* Now that the address is in scope, check to see if
375
                 * the address type is supported by local sock as
376
                 * well as the remote peer.
377
                 */
378
                if ((((AF_INET == addr->sa.sa_family) &&
379
                      (flags & SCTP_ADDR4_PEERSUPP))) ||
380
                    (((AF_INET6 == addr->sa.sa_family) &&
381
                      (flags & SCTP_ADDR6_ALLOWED) &&
382
                      (flags & SCTP_ADDR6_PEERSUPP))))
383
                        error = sctp_add_bind_addr(dest, addr, gfp);
384
        }
385
 
386
        return error;
387
}
388
 
389
/* Is this a wildcard address?  */
390
int sctp_is_any(const union sctp_addr *addr)
391
{
392
        struct sctp_af *af = sctp_get_af_specific(addr->sa.sa_family);
393
        if (!af)
394
                return 0;
395
        return af->is_any(addr);
396
}
397
 
398
/* Is 'addr' valid for 'scope'?  */
399
int sctp_in_scope(const union sctp_addr *addr, sctp_scope_t scope)
400
{
401
        sctp_scope_t addr_scope = sctp_scope(addr);
402
 
403
        /* The unusable SCTP addresses will not be considered with
404
         * any defined scopes.
405
         */
406
        if (SCTP_SCOPE_UNUSABLE == addr_scope)
407
                return 0;
408
        /*
409
         * For INIT and INIT-ACK address list, let L be the level of
410
         * of requested destination address, sender and receiver
411
         * SHOULD include all of its addresses with level greater
412
         * than or equal to L.
413
         */
414
        if (addr_scope <= scope)
415
                return 1;
416
 
417
        return 0;
418
}
419
 
420
/********************************************************************
421
 * 3rd Level Abstractions
422
 ********************************************************************/
423
 
424
/* What is the scope of 'addr'?  */
425
sctp_scope_t sctp_scope(const union sctp_addr *addr)
426
{
427
        struct sctp_af *af;
428
 
429
        af = sctp_get_af_specific(addr->sa.sa_family);
430
        if (!af)
431
                return SCTP_SCOPE_UNUSABLE;
432
 
433
        return af->scope((union sctp_addr *)addr);
434
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.