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

Subversion Repositories or1k

[/] [or1k/] [tags/] [before_ORP/] [uclinux/] [uClinux-2.0.x/] [net/] [core/] [sock.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 200 simons
/*
2
 * INET         An implementation of the TCP/IP protocol suite for the LINUX
3
 *              operating system.  INET is implemented using the  BSD Socket
4
 *              interface as the means of communication with the user level.
5
 *
6
 *              Generic socket support routines. Memory allocators, socket lock/release
7
 *              handler for protocols to use and generic option handler.
8
 *
9
 *
10
 * Version:     @(#)sock.c      1.0.17  06/02/93
11
 *
12
 * Authors:     Ross Biro, <bir7@leland.Stanford.Edu>
13
 *              Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
14
 *              Florian La Roche, <flla@stud.uni-sb.de>
15
 *              Alan Cox, <A.Cox@swansea.ac.uk>
16
 *
17
 * Fixes:
18
 *              Alan Cox        :       Numerous verify_area() problems
19
 *              Alan Cox        :       Connecting on a connecting socket
20
 *                                      now returns an error for tcp.
21
 *              Alan Cox        :       sock->protocol is set correctly.
22
 *                                      and is not sometimes left as 0.
23
 *              Alan Cox        :       connect handles icmp errors on a
24
 *                                      connect properly. Unfortunately there
25
 *                                      is a restart syscall nasty there. I
26
 *                                      can't match BSD without hacking the C
27
 *                                      library. Ideas urgently sought!
28
 *              Alan Cox        :       Disallow bind() to addresses that are
29
 *                                      not ours - especially broadcast ones!!
30
 *              Alan Cox        :       Socket 1024 _IS_ ok for users. (fencepost)
31
 *              Alan Cox        :       sock_wfree/sock_rfree don't destroy sockets,
32
 *                                      instead they leave that for the DESTROY timer.
33
 *              Alan Cox        :       Clean up error flag in accept
34
 *              Alan Cox        :       TCP ack handling is buggy, the DESTROY timer
35
 *                                      was buggy. Put a remove_sock() in the handler
36
 *                                      for memory when we hit 0. Also altered the timer
37
 *                                      code. The ACK stuff can wait and needs major
38
 *                                      TCP layer surgery.
39
 *              Alan Cox        :       Fixed TCP ack bug, removed remove sock
40
 *                                      and fixed timer/inet_bh race.
41
 *              Alan Cox        :       Added zapped flag for TCP
42
 *              Alan Cox        :       Move kfree_skb into skbuff.c and tidied up surplus code
43
 *              Alan Cox        :       for new sk_buff allocations wmalloc/rmalloc now call alloc_skb
44
 *              Alan Cox        :       kfree_s calls now are kfree_skbmem so we can track skb resources
45
 *              Alan Cox        :       Supports socket option broadcast now as does udp. Packet and raw need fixing.
46
 *              Alan Cox        :       Added RCVBUF,SNDBUF size setting. It suddenly occurred to me how easy it was so...
47
 *              Rick Sladkey    :       Relaxed UDP rules for matching packets.
48
 *              C.E.Hawkins     :       IFF_PROMISC/SIOCGHWADDR support
49
 *      Pauline Middelink       :       identd support
50
 *              Alan Cox        :       Fixed connect() taking signals I think.
51
 *              Alan Cox        :       SO_LINGER supported
52
 *              Alan Cox        :       Error reporting fixes
53
 *              Anonymous       :       inet_create tidied up (sk->reuse setting)
54
 *              Alan Cox        :       inet sockets don't set sk->type!
55
 *              Alan Cox        :       Split socket option code
56
 *              Alan Cox        :       Callbacks
57
 *              Alan Cox        :       Nagle flag for Charles & Johannes stuff
58
 *              Alex            :       Removed restriction on inet fioctl
59
 *              Alan Cox        :       Splitting INET from NET core
60
 *              Alan Cox        :       Fixed bogus SO_TYPE handling in getsockopt()
61
 *              Adam Caldwell   :       Missing return in SO_DONTROUTE/SO_DEBUG code
62
 *              Alan Cox        :       Split IP from generic code
63
 *              Alan Cox        :       New kfree_skbmem()
64
 *              Alan Cox        :       Make SO_DEBUG superuser only.
65
 *              Alan Cox        :       Allow anyone to clear SO_DEBUG
66
 *                                      (compatibility fix)
67
 *              Alan Cox        :       Added optimistic memory grabbing for AF_UNIX throughput.
68
 *              Alan Cox        :       Allocator for a socket is settable.
69
 *              Alan Cox        :       SO_ERROR includes soft errors.
70
 *              Alan Cox        :       Allow NULL arguments on some SO_ opts
71
 *              Alan Cox        :       Generic socket allocation to make hooks
72
 *                                      easier (suggested by Craig Metz).
73
 *              Michael Pall    :       SO_ERROR returns positive errno again
74
 *              Elliot Poger    :       Added support for SO_BINDTODEVICE.
75
 *              Russell King    :       Add #ifdef CONFIG_INET to SO_BINDTODEVICE
76
 *
77
 * To Fix:
78
 *
79
 *
80
 *              This program is free software; you can redistribute it and/or
81
 *              modify it under the terms of the GNU General Public License
82
 *              as published by the Free Software Foundation; either version
83
 *              2 of the License, or (at your option) any later version.
84
 */
85
 
86
#include <linux/config.h>
87
#include <linux/errno.h>
88
#include <linux/types.h>
89
#include <linux/socket.h>
90
#include <linux/in.h>
91
#include <linux/kernel.h>
92
#include <linux/major.h>
93
#include <linux/sched.h>
94
#include <linux/timer.h>
95
#include <linux/string.h>
96
#include <linux/sockios.h>
97
#include <linux/net.h>
98
#include <linux/fcntl.h>
99
#include <linux/mm.h>
100
#include <linux/interrupt.h>
101
 
102
#include <asm/segment.h>
103
#include <asm/system.h>
104
 
105
#include <linux/inet.h>
106
#include <linux/netdevice.h>
107
#include <net/ip.h>
108
#include <net/protocol.h>
109
#include <net/arp.h>
110
#include <net/rarp.h>
111
#include <net/route.h>
112
#include <net/tcp.h>
113
#include <net/udp.h>
114
#include <linux/skbuff.h>
115
#include <net/sock.h>
116
#include <net/raw.h>
117
#include <net/icmp.h>
118
 
119
#define min(a,b)        ((a)<(b)?(a):(b))
120
 
121
/*
122
 *      This is meant for all protocols to use and covers goings on
123
 *      at the socket level. Everything here is generic.
124
 */
125
 
126
int sock_setsockopt(struct sock *sk, int level, int optname,
127
                char *optval, int optlen)
128
{
129
        int val;
130
        int valbool;
131
        int err;
132
        struct linger ling;
133
        struct ifreq req;
134
 
135
        /*
136
         *      Options without arguments
137
         */
138
 
139
#ifdef SO_DONTLINGER            /* Compatibility item... */
140
        switch(optname)
141
        {
142
                case SO_DONTLINGER:
143
                        sk->linger=0;
144
                        return 0;
145
        }
146
#endif  
147
 
148
        if (optval == NULL)
149
                return(-EINVAL);
150
 
151
        err=verify_area(VERIFY_READ, optval, sizeof(int));
152
        if(err)
153
                return err;
154
 
155
        val = get_user((int *)optval);
156
        valbool = val?1:0;
157
 
158
        switch(optname)
159
        {
160
                case SO_DEBUG:
161
                        if(val && !suser())
162
                                return(-EPERM);
163
                        sk->debug=valbool;
164
                        return 0;
165
                case SO_REUSEADDR:
166
                        sk->reuse = valbool;
167
                        return(0);
168
                case SO_TYPE:
169
                case SO_ERROR:
170
                        return(-ENOPROTOOPT);
171
                case SO_DONTROUTE:
172
                        sk->localroute=valbool;
173
                        return 0;
174
                case SO_BROADCAST:
175
                        sk->broadcast=valbool;
176
                        return 0;
177
                case SO_SNDBUF:
178
                        if(val > SK_WMEM_MAX*2)
179
                                val = SK_WMEM_MAX*2;
180
                        if(val < 256)
181
                                val = 256;
182
                        if(val > 65535)
183
                                val = 65535;
184
                        sk->sndbuf = val;
185
                        return 0;
186
 
187
                case SO_RCVBUF:
188
                        if(val > SK_RMEM_MAX*2)
189
                                val = SK_RMEM_MAX*2;
190
                        if(val < 256)
191
                                val = 256;
192
                        if(val > 65535)
193
                                val = 65535;
194
                        sk->rcvbuf = val;
195
                        return(0);
196
 
197
                case SO_KEEPALIVE:
198
                        sk->keepopen = valbool;
199
                        return(0);
200
 
201
                case SO_OOBINLINE:
202
                        sk->urginline = valbool;
203
                        return(0);
204
 
205
                case SO_NO_CHECK:
206
                        sk->no_check = valbool;
207
                        return(0);
208
 
209
                case SO_PRIORITY:
210
                        if (val >= 0 && val < DEV_NUMBUFFS)
211
                        {
212
                                sk->priority = val;
213
                        }
214
                        else
215
                        {
216
                                return(-EINVAL);
217
                        }
218
                        return(0);
219
 
220
 
221
                case SO_LINGER:
222
                        err=verify_area(VERIFY_READ,optval,sizeof(ling));
223
                        if(err)
224
                                return err;
225
                        memcpy_fromfs(&ling,optval,sizeof(ling));
226
                        if(ling.l_onoff==0)
227
                                sk->linger=0;
228
                        else
229
                        {
230
                                sk->lingertime=ling.l_linger;
231
                                sk->linger=1;
232
                        }
233
                        return 0;
234
 
235
                case SO_BSDCOMPAT:
236
                        sk->bsdism = valbool;
237
                        return 0;
238
 
239
#ifdef CONFIG_NET       
240
                case SO_BINDTODEVICE:
241
                        /* Bind this socket to a particular device like "eth0",
242
                         * as specified in an ifreq structure.  If the device
243
                         * is "", socket is NOT bound to a device. */
244
 
245
                        if(!suser())
246
                                return -EPERM;
247
 
248
                        if (!valbool) {
249
                                sk->bound_device = NULL;
250
                        } else {
251
                                err=verify_area(VERIFY_READ,optval,sizeof(req));
252
                                if(err)
253
                                        return err;
254
                                memcpy_fromfs(&req,optval,sizeof(req));
255
#ifdef CONFIG_INET
256
                                /* Remove any cached route for this socket. */
257
                                if (sk->ip_route_cache) {
258
                                        ip_rt_put(sk->ip_route_cache);
259
                                        sk->ip_route_cache=NULL;
260
                                }
261
#endif
262
                                if (*(req.ifr_name) == '\0') {
263
                                        sk->bound_device = NULL;
264
                                } else {
265
                                        sk->bound_device = dev_get(req.ifr_name);
266
                                        if (sk->bound_device == NULL)
267
                                                return -EINVAL;
268
                                }
269
                        }
270
                        return 0;
271
#endif
272
 
273
                default:
274
                        return(-ENOPROTOOPT);
275
        }
276
}
277
 
278
 
279
int sock_getsockopt(struct sock *sk, int level, int optname,
280
                   char *optval, int *optlen)
281
{
282
        int val;
283
        int err;
284
        struct linger ling;
285
 
286
        switch(optname)
287
        {
288
                case SO_DEBUG:
289
                        val = sk->debug;
290
                        break;
291
 
292
                case SO_DONTROUTE:
293
                        val = sk->localroute;
294
                        break;
295
 
296
                case SO_BROADCAST:
297
                        val= sk->broadcast;
298
                        break;
299
 
300
                case SO_SNDBUF:
301
                        val=sk->sndbuf;
302
                        break;
303
 
304
                case SO_RCVBUF:
305
                        val =sk->rcvbuf;
306
                        break;
307
 
308
                case SO_REUSEADDR:
309
                        val = sk->reuse;
310
                        break;
311
 
312
                case SO_KEEPALIVE:
313
                        val = sk->keepopen;
314
                        break;
315
 
316
                case SO_TYPE:
317
                        val = sk->type;
318
                        break;
319
 
320
                case SO_ERROR:
321
                        val = -sock_error(sk);
322
                        if(val==0)
323
                                val=xchg(&sk->err_soft,0);
324
                        break;
325
 
326
                case SO_OOBINLINE:
327
                        val = sk->urginline;
328
                        break;
329
 
330
                case SO_NO_CHECK:
331
                        val = sk->no_check;
332
                        break;
333
 
334
                case SO_PRIORITY:
335
                        val = sk->priority;
336
                        break;
337
 
338
                case SO_LINGER:
339
                        err=verify_area(VERIFY_WRITE,optval,sizeof(ling));
340
                        if(err)
341
                                return err;
342
                        err=verify_area(VERIFY_WRITE,optlen,sizeof(int));
343
                        if(err)
344
                                return err;
345
                        put_fs_long(sizeof(ling),(unsigned long *)optlen);
346
                        ling.l_onoff=sk->linger;
347
                        ling.l_linger=sk->lingertime;
348
                        memcpy_tofs(optval,&ling,sizeof(ling));
349
                        return 0;
350
 
351
                case SO_BSDCOMPAT:
352
                        val = sk->bsdism;
353
                        break;
354
 
355
#ifdef CONFIG_NET
356
                case SO_BINDTODEVICE:
357
                {
358
                        struct ifreq req;
359
 
360
                        /* Return the bound device (if any) */
361
                        err=verify_area(VERIFY_WRITE,optval,sizeof(req));
362
                        if(err)
363
                                return err;
364
 
365
                        memset((char *) &req, 0, sizeof(req));
366
 
367
                        if (sk->bound_device) {
368
                            strncpy(req.ifr_name, sk->bound_device->name, sizeof(req.ifr_name));
369
                            (*(struct sockaddr_in *) &req.ifr_addr).sin_family = sk->bound_device->family;
370
                            (*(struct sockaddr_in *) &req.ifr_addr).sin_addr.s_addr = sk->bound_device->pa_addr;
371
                        }
372
                        memcpy_tofs(optval, &req, sizeof(req));
373
                        return 0;
374
                }
375
#endif
376
 
377
                default:
378
                        return(-ENOPROTOOPT);
379
        }
380
        err=verify_area(VERIFY_WRITE, optlen, sizeof(int));
381
        if(err)
382
                return err;
383
        put_fs_long(sizeof(int),(unsigned long *) optlen);
384
 
385
        err=verify_area(VERIFY_WRITE, optval, sizeof(int));
386
        if(err)
387
                return err;
388
        put_fs_long(val,(unsigned long *)optval);
389
 
390
        return(0);
391
}
392
 
393
struct sock *sk_alloc(int priority)
394
{
395
        struct sock *sk=(struct sock *)kmalloc(sizeof(*sk), priority);
396
        if(!sk)
397
                return NULL;
398
        memset(sk, 0, sizeof(*sk));
399
        return sk;
400
}
401
 
402
void sk_free(struct sock *sk)
403
{
404
        kfree_s(sk,sizeof(*sk));
405
}
406
 
407
 
408
struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force, int priority)
409
{
410
        if (sk) {
411
                if (force || sk->wmem_alloc < sk->sndbuf) {
412
                        struct sk_buff * skb = alloc_skb(size, priority);
413
                        if (skb)
414
                                atomic_add(skb->truesize, &sk->wmem_alloc);
415
                        return skb;
416
                }
417
                return NULL;
418
        }
419
        return alloc_skb(size, priority);
420
}
421
 
422
struct sk_buff *sock_rmalloc(struct sock *sk, unsigned long size, int force, int priority)
423
{
424
        if (sk) {
425
                if (force || sk->rmem_alloc < sk->rcvbuf) {
426
                        struct sk_buff *skb = alloc_skb(size, priority);
427
                        if (skb)
428
                                atomic_add(skb->truesize, &sk->rmem_alloc);
429
                        return skb;
430
                }
431
                return NULL;
432
        }
433
        return alloc_skb(size, priority);
434
}
435
 
436
 
437
unsigned long sock_rspace(struct sock *sk)
438
{
439
        int amt;
440
 
441
        if (sk != NULL)
442
        {
443
                if (sk->rmem_alloc >= sk->rcvbuf-2*MIN_WINDOW)
444
                        return(0);
445
                amt = min((sk->rcvbuf-sk->rmem_alloc)/2-MIN_WINDOW, MAX_WINDOW);
446
                if (amt < 0)
447
                        return(0);
448
                return(amt);
449
        }
450
        return(0);
451
}
452
 
453
 
454
unsigned long sock_wspace(struct sock *sk)
455
{
456
        if (sk != NULL)
457
        {
458
                if (sk->shutdown & SEND_SHUTDOWN)
459
                        return(0);
460
                if (sk->wmem_alloc >= sk->sndbuf)
461
                        return(0);
462
                return sk->sndbuf - sk->wmem_alloc;
463
        }
464
        return(0);
465
}
466
 
467
 
468
void sock_wfree(struct sock *sk, struct sk_buff *skb)
469
{
470
        int s=skb->truesize;
471
#if CONFIG_SKB_CHECK
472
        IS_SKB(skb);
473
#endif
474
        kfree_skbmem(skb);
475
        if (sk)
476
        {
477
                /* In case it might be waiting for more memory. */
478
                sk->write_space(sk);
479
                atomic_sub(s, &sk->wmem_alloc);
480
        }
481
}
482
 
483
 
484
void sock_rfree(struct sock *sk, struct sk_buff *skb)
485
{
486
        int s=skb->truesize;
487
#if CONFIG_SKB_CHECK
488
        IS_SKB(skb);
489
#endif  
490
        kfree_skbmem(skb);
491
        if (sk)
492
        {
493
                atomic_sub(s, &sk->rmem_alloc);
494
        }
495
}
496
 
497
/*
498
 *      Generic send/receive buffer handlers
499
 */
500
 
501
struct sk_buff *sock_alloc_send_skb(struct sock *sk, unsigned long size, unsigned long fallback, int noblock, int *errcode)
502
{
503
        struct sk_buff *skb;
504
        int err;
505
        unsigned long mem;
506
        do
507
        {
508
                if(sk->err!=0)
509
                {
510
                        cli();
511
                        err= -sk->err;
512
                        sk->err=0;
513
                        sti();
514
                        *errcode=err;
515
                        return NULL;
516
                }
517
 
518
                if(sk->shutdown&SEND_SHUTDOWN)
519
                {
520
                        *errcode=-EPIPE;
521
                        return NULL;
522
                }
523
 
524
 
525
                mem=sk->wmem_alloc;
526
 
527
                if(!fallback)
528
                        skb = sock_wmalloc(sk, size, 0, sk->allocation);
529
                else
530
                {
531
                        /* The buffer get won't block, or use the atomic queue. It does
532
                           produce annoying no free page messages still.... */
533
                        skb = sock_wmalloc(sk, size, 0 , GFP_IO);
534
                        if(!skb)
535
                                skb=sock_wmalloc(sk, fallback, 0, GFP_KERNEL);
536
                }
537
 
538
                /*
539
                 *      This means we have too many buffers for this socket already.
540
                 */
541
 
542
                if(skb==NULL)
543
                {
544
                        sk->socket->flags |= SO_NOSPACE;
545
                        if(noblock)
546
                        {
547
                                *errcode=-EAGAIN;
548
                                return NULL;
549
                        }
550
                        if(sk->shutdown&SEND_SHUTDOWN)
551
                        {
552
                                *errcode=-EPIPE;
553
                                return NULL;
554
                        }
555
                        cli();
556
                        if(sk->shutdown&SEND_SHUTDOWN)
557
                        {
558
                                sti();
559
                                *errcode=-EPIPE;
560
                                return NULL;
561
                        }
562
 
563
                        if (sk->wmem_alloc==mem)
564
                        {
565
                                sk->socket->flags &= ~SO_NOSPACE;
566
                                interruptible_sleep_on(sk->sleep);
567
                                if (current->signal & ~current->blocked)
568
                                {
569
                                        sti();
570
                                        *errcode = -ERESTARTSYS;
571
                                        return NULL;
572
                                }
573
                        }
574
                        sti();
575
                }
576
        }
577
        while(skb==NULL);
578
 
579
        return skb;
580
}
581
 
582
 
583
void __release_sock(struct sock *sk)
584
{
585
#ifdef CONFIG_INET
586
        if (!sk->prot || !sk->prot->rcv)
587
                return;
588
 
589
        /* See if we have any packets built up. */
590
        start_bh_atomic();
591
        while (!skb_queue_empty(&sk->back_log)) {
592
                struct sk_buff * skb = sk->back_log.next;
593
                __skb_unlink(skb, &sk->back_log);
594
                sk->prot->rcv(skb, skb->dev, (struct options*)skb->proto_priv,
595
                              skb->saddr, skb->len, skb->daddr, 1,
596
                              /* Only used for/by raw sockets. */
597
                              (struct inet_protocol *)sk->pair);
598
        }
599
        end_bh_atomic();
600
#endif  
601
}

powered by: WebSVN 2.1.0

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