root/net/inet/sock.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sock_setsockopt
  2. sock_getsockopt
  3. sock_wmalloc
  4. sock_rmalloc
  5. sock_rspace
  6. sock_wspace
  7. sock_wfree
  8. sock_rfree
  9. release_sock

   1 /*
   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, sk->inuse/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 suddenely occured 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       :       Pidentd 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  *
  64  * To Fix:
  65  *
  66  *
  67  *              This program is free software; you can redistribute it and/or
  68  *              modify it under the terms of the GNU General Public License
  69  *              as published by the Free Software Foundation; either version
  70  *              2 of the License, or (at your option) any later version.
  71  */
  72 
  73 #include <linux/config.h>
  74 #include <linux/errno.h>
  75 #include <linux/types.h>
  76 #include <linux/socket.h>
  77 #include <linux/in.h>
  78 #include <linux/kernel.h>
  79 #include <linux/major.h>
  80 #include <linux/sched.h>
  81 #include <linux/timer.h>
  82 #include <linux/string.h>
  83 #include <linux/sockios.h>
  84 #include <linux/net.h>
  85 #include <linux/fcntl.h>
  86 #include <linux/mm.h>
  87 #include <linux/interrupt.h>
  88 
  89 #include <asm/segment.h>
  90 #include <asm/system.h>
  91 
  92 #include <linux/inet.h>
  93 #include <linux/netdevice.h>
  94 #include "ip.h"
  95 #include "protocol.h"
  96 #include "arp.h"
  97 #include "rarp.h"
  98 #include "route.h"
  99 #include "tcp.h"
 100 #include "udp.h"
 101 #include <linux/skbuff.h>
 102 #include "sock.h"
 103 #include "raw.h"
 104 #include "icmp.h"
 105 
 106 #define min(a,b)        ((a)<(b)?(a):(b))
 107 
 108 /*
 109  *      This is meant for all protocols to use and covers goings on
 110  *      at the socket level. Everything here is generic.
 111  */
 112 
 113 int sock_setsockopt(struct sock *sk, int level, int optname,
     /* [previous][next][first][last][top][bottom][index][help] */
 114                 char *optval, int optlen)
 115 {
 116         int val;
 117         int err;
 118         struct linger ling;
 119 
 120         if (optval == NULL) 
 121                 return(-EINVAL);
 122 
 123         err=verify_area(VERIFY_READ, optval, sizeof(int));
 124         if(err)
 125                 return err;
 126         
 127         val = get_fs_long((unsigned long *)optval);
 128         switch(optname) 
 129         {
 130                 case SO_TYPE:
 131                 case SO_ERROR:
 132                         return(-ENOPROTOOPT);
 133 
 134                 case SO_DEBUG:  
 135                         sk->debug=val?1:0;
 136                         return 0;
 137                 case SO_DONTROUTE:
 138                         sk->localroute=val?1:0;
 139                         return 0;
 140                 case SO_BROADCAST:
 141                         sk->broadcast=val?1:0;
 142                         return 0;
 143                 case SO_SNDBUF:
 144                         if(val>32767)
 145                                 val=32767;
 146                         if(val<256)
 147                                 val=256;
 148                         sk->sndbuf=val;
 149                         return 0;
 150                 case SO_LINGER:
 151                         err=verify_area(VERIFY_READ,optval,sizeof(ling));
 152                         if(err)
 153                                 return err;
 154                         memcpy_fromfs(&ling,optval,sizeof(ling));
 155                         if(ling.l_onoff==0)
 156                                 sk->linger=0;
 157                         else
 158                         {
 159                                 sk->lingertime=ling.l_linger;
 160                                 sk->linger=1;
 161                         }
 162                         return 0;
 163                 case SO_RCVBUF:
 164                         if(val>32767)
 165                                 val=32767;
 166                         if(val<256)
 167                                 val=256;
 168                         sk->rcvbuf=val;
 169                         return(0);
 170 
 171                 case SO_REUSEADDR:
 172                         if (val) 
 173                                 sk->reuse = 1;
 174                         else 
 175                                 sk->reuse = 0;
 176                         return(0);
 177 
 178                 case SO_KEEPALIVE:
 179                         if (val)
 180                                 sk->keepopen = 1;
 181                         else 
 182                                 sk->keepopen = 0;
 183                         return(0);
 184 
 185                 case SO_OOBINLINE:
 186                         if (val) 
 187                                 sk->urginline = 1;
 188                         else 
 189                                 sk->urginline = 0;
 190                         return(0);
 191 
 192                 case SO_NO_CHECK:
 193                         if (val) 
 194                                 sk->no_check = 1;
 195                         else 
 196                                 sk->no_check = 0;
 197                         return(0);
 198 
 199                  case SO_PRIORITY:
 200                         if (val >= 0 && val < DEV_NUMBUFFS) 
 201                         {
 202                                 sk->priority = val;
 203                         } 
 204                         else 
 205                         {
 206                                 return(-EINVAL);
 207                         }
 208                         return(0);
 209 
 210                 default:
 211                         return(-ENOPROTOOPT);
 212         }
 213 }
 214 
 215 
 216 int sock_getsockopt(struct sock *sk, int level, int optname,
     /* [previous][next][first][last][top][bottom][index][help] */
 217                    char *optval, int *optlen)
 218 {               
 219         int val;
 220         int err;
 221         struct linger ling;
 222 
 223         switch(optname) 
 224         {
 225                 case SO_DEBUG:          
 226                         val = sk->debug;
 227                         break;
 228                 
 229                 case SO_DONTROUTE:
 230                         val = sk->localroute;
 231                         break;
 232                 
 233                 case SO_BROADCAST:
 234                         val= sk->broadcast;
 235                         break;
 236                 
 237                 case SO_LINGER: 
 238                         err=verify_area(VERIFY_WRITE,optval,sizeof(ling));
 239                         if(err)
 240                                 return err;
 241                         err=verify_area(VERIFY_WRITE,optlen,sizeof(int));
 242                         if(err)
 243                                 return err;
 244                         put_fs_long(sizeof(ling),(unsigned long *)optlen);
 245                         ling.l_onoff=sk->linger;
 246                         ling.l_linger=sk->lingertime;
 247                         memcpy_tofs(optval,&ling,sizeof(ling));
 248                         return 0;
 249                 
 250                 case SO_SNDBUF:
 251                         val=sk->sndbuf;
 252                         break;
 253                 
 254                 case SO_RCVBUF:
 255                         val =sk->rcvbuf;
 256                         break;
 257 
 258                 case SO_REUSEADDR:
 259                         val = sk->reuse;
 260                         break;
 261 
 262                 case SO_KEEPALIVE:
 263                         val = sk->keepopen;
 264                         break;
 265 
 266                 case SO_TYPE:
 267 #if 0           
 268                         if (sk->prot == &tcp_prot) 
 269                                 val = SOCK_STREAM;
 270                         else 
 271                                 val = SOCK_DGRAM;
 272 #endif
 273                         val = sk->type;                         
 274                         break;
 275 
 276                 case SO_ERROR:
 277                         val = sk->err;
 278                         sk->err = 0;
 279                         break;
 280 
 281                 case SO_OOBINLINE:
 282                         val = sk->urginline;
 283                         break;
 284         
 285                 case SO_NO_CHECK:
 286                         val = sk->no_check;
 287                         break;
 288 
 289                 case SO_PRIORITY:
 290                         val = sk->priority;
 291                         break;
 292 
 293                 default:
 294                         return(-ENOPROTOOPT);
 295         }
 296         err=verify_area(VERIFY_WRITE, optlen, sizeof(int));
 297         if(err)
 298                 return err;
 299         put_fs_long(sizeof(int),(unsigned long *) optlen);
 300 
 301         err=verify_area(VERIFY_WRITE, optval, sizeof(int));
 302         if(err)
 303                 return err;
 304         put_fs_long(val,(unsigned long *)optval);
 305 
 306         return(0);
 307 }
 308 
 309 
 310 struct sk_buff *
 311 sock_wmalloc(struct sock *sk, unsigned long size, int force,
     /* [previous][next][first][last][top][bottom][index][help] */
 312              int priority)
 313 {
 314   if (sk) {
 315         if (sk->wmem_alloc + size < sk->sndbuf || force) {
 316                 struct sk_buff * c = alloc_skb(size, priority);
 317                 if (c) {
 318                         cli();
 319                         sk->wmem_alloc+= c->mem_len;
 320                         sti();
 321                 }
 322                 return c;
 323         }
 324         return(NULL);
 325   }
 326   return(alloc_skb(size, priority));
 327 }
 328 
 329 
 330 struct sk_buff *
 331 sock_rmalloc(struct sock *sk, unsigned long size, int force, int priority)
     /* [previous][next][first][last][top][bottom][index][help] */
 332 {
 333   if (sk) {
 334         if (sk->rmem_alloc + size < sk->rcvbuf || force) {
 335                 struct sk_buff *c = alloc_skb(size, priority);
 336                 if (c) {
 337                         cli();
 338                         sk->rmem_alloc += c->mem_len;
 339                         sti();
 340                 }
 341                 return(c);
 342         }
 343         return(NULL);
 344   }
 345   return(alloc_skb(size, priority));
 346 }
 347 
 348 
 349 unsigned long
 350 sock_rspace(struct sock *sk)
     /* [previous][next][first][last][top][bottom][index][help] */
 351 {
 352   int amt;
 353 
 354   if (sk != NULL) {
 355         if (sk->rmem_alloc >= sk->rcvbuf-2*MIN_WINDOW) return(0);
 356         amt = min((sk->rcvbuf-sk->rmem_alloc)/2-MIN_WINDOW, MAX_WINDOW);
 357         if (amt < 0) return(0);
 358         return(amt);
 359   }
 360   return(0);
 361 }
 362 
 363 
 364 unsigned long
 365 sock_wspace(struct sock *sk)
     /* [previous][next][first][last][top][bottom][index][help] */
 366 {
 367   if (sk != NULL) {
 368         if (sk->shutdown & SEND_SHUTDOWN) return(0);
 369         if (sk->wmem_alloc >= sk->sndbuf) return(0);
 370         return(sk->sndbuf-sk->wmem_alloc );
 371   }
 372   return(0);
 373 }
 374 
 375 
 376 void
 377 sock_wfree(struct sock *sk, void *mem, unsigned long size)
     /* [previous][next][first][last][top][bottom][index][help] */
 378 {
 379   IS_SKB(mem);
 380   kfree_skbmem(mem, size);
 381   if (sk) {
 382         sk->wmem_alloc -= size;
 383 
 384         /* In case it might be waiting for more memory. */
 385         if (!sk->dead) sk->write_space(sk);
 386         return;
 387   }
 388 }
 389 
 390 
 391 void
 392 sock_rfree(struct sock *sk, void *mem, unsigned long size)
     /* [previous][next][first][last][top][bottom][index][help] */
 393 {
 394   IS_SKB(mem);
 395   kfree_skbmem(mem, size);
 396   if (sk) {
 397         sk->rmem_alloc -= size;
 398   }
 399 }
 400 
 401 
 402 void release_sock(struct sock *sk)
     /* [previous][next][first][last][top][bottom][index][help] */
 403 {
 404   struct sk_buff *skb;
 405 
 406   if (!sk->prot)
 407         return;
 408 
 409   if (sk->blog) return;
 410 #ifdef CONFIG_INET
 411   /* See if we have any packets built up. */
 412   sk->inuse = 1;
 413   while((skb = skb_dequeue(&sk->back_log)) != NULL) {
 414         sk->blog = 1;
 415         if (sk->prot->rcv) sk->prot->rcv(skb, skb->dev, sk->opt,
 416                                          skb->saddr, skb->len, skb->daddr, 1,
 417                                         /* Only used for/by raw sockets. */
 418                                         (struct inet_protocol *)sk->pair); 
 419   }
 420 #endif  
 421   sk->blog = 0;
 422   sk->inuse = 0;
 423 #ifdef CONFIG_INET  
 424   if (sk->dead && sk->state == TCP_CLOSE) {
 425         /* Should be about 2 rtt's */
 426         reset_timer(sk, TIME_DONE, min(sk->rtt * 2, TCP_DONE_TIME));
 427   }
 428 #endif  
 429 }
 430 
 431 

/* [previous][next][first][last][top][bottom][index][help] */