root/net/core/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. sock_alloc_send_skb
  10. 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 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  *
  68  * To Fix:
  69  *
  70  *
  71  *              This program is free software; you can redistribute it and/or
  72  *              modify it under the terms of the GNU General Public License
  73  *              as published by the Free Software Foundation; either version
  74  *              2 of the License, or (at your option) any later version.
  75  */
  76 
  77 #include <linux/config.h>
  78 #include <linux/errno.h>
  79 #include <linux/types.h>
  80 #include <linux/socket.h>
  81 #include <linux/in.h>
  82 #include <linux/kernel.h>
  83 #include <linux/major.h>
  84 #include <linux/sched.h>
  85 #include <linux/timer.h>
  86 #include <linux/string.h>
  87 #include <linux/sockios.h>
  88 #include <linux/net.h>
  89 #include <linux/fcntl.h>
  90 #include <linux/mm.h>
  91 #include <linux/interrupt.h>
  92 
  93 #include <asm/segment.h>
  94 #include <asm/system.h>
  95 
  96 #include <linux/inet.h>
  97 #include <linux/netdevice.h>
  98 #include <net/ip.h>
  99 #include <net/protocol.h>
 100 #include <net/arp.h>
 101 #include <net/rarp.h>
 102 #include <net/route.h>
 103 #include <net/tcp.h>
 104 #include <net/udp.h>
 105 #include <linux/skbuff.h>
 106 #include <net/sock.h>
 107 #include <net/raw.h>
 108 #include <net/icmp.h>
 109 
 110 #define min(a,b)        ((a)<(b)?(a):(b))
 111 
 112 /*
 113  *      This is meant for all protocols to use and covers goings on
 114  *      at the socket level. Everything here is generic.
 115  */
 116 
 117 int sock_setsockopt(struct sock *sk, int level, int optname,
     /* [previous][next][first][last][top][bottom][index][help] */
 118                 char *optval, int optlen)
 119 {
 120         int val;
 121         int valbool;
 122         int err;
 123         struct linger ling;
 124 
 125         if (optval == NULL) 
 126                 return(-EINVAL);
 127 
 128         err=verify_area(VERIFY_READ, optval, sizeof(int));
 129         if(err)
 130                 return err;
 131         
 132         val = get_fs_long((unsigned long *)optval);
 133         valbool = val?1:0;
 134         
 135         switch(optname) 
 136         {
 137                 case SO_DEBUG:  
 138                         if(val && !suser())
 139                                 return(-EPERM);
 140                         sk->debug=valbool;
 141                         return 0;
 142                 case SO_REUSEADDR:
 143                         sk->reuse = valbool;
 144                         return(0);
 145                 case SO_TYPE:
 146                 case SO_ERROR:
 147                         return(-ENOPROTOOPT);
 148                 case SO_DONTROUTE:
 149                         sk->localroute=valbool;
 150                         return 0;
 151                 case SO_BROADCAST:
 152                         sk->broadcast=valbool;
 153                         return 0;
 154                 case SO_SNDBUF:
 155                         if(val>32767)
 156                                 val=32767;
 157                         if(val<256)
 158                                 val=256;
 159                         sk->sndbuf=val;
 160                         return 0;
 161 
 162                 case SO_RCVBUF:
 163                         if(val>32767)
 164                                 val=32767;
 165                         if(val<256)
 166                                 val=256;
 167                         sk->rcvbuf=val;
 168                         return(0);
 169 
 170                 case SO_KEEPALIVE:
 171                         sk->keepopen = valbool;
 172                         return(0);
 173 
 174                 case SO_OOBINLINE:
 175                         sk->urginline = valbool;
 176                         return(0);
 177 
 178                 case SO_NO_CHECK:
 179                         sk->no_check = valbool;
 180                         return(0);
 181 
 182                 case SO_PRIORITY:
 183                         if (val >= 0 && val < DEV_NUMBUFFS) 
 184                         {
 185                                 sk->priority = val;
 186                         } 
 187                         else 
 188                         {
 189                                 return(-EINVAL);
 190                         }
 191                         return(0);
 192 
 193 
 194                 case SO_LINGER:
 195                         err=verify_area(VERIFY_READ,optval,sizeof(ling));
 196                         if(err)
 197                                 return err;
 198                         memcpy_fromfs(&ling,optval,sizeof(ling));
 199                         if(ling.l_onoff==0)
 200                                 sk->linger=0;
 201                         else
 202                         {
 203                                 sk->lingertime=ling.l_linger;
 204                                 sk->linger=1;
 205                         }
 206                         return 0;
 207 
 208 
 209                 default:
 210                         return(-ENOPROTOOPT);
 211         }
 212 }
 213 
 214 
 215 int sock_getsockopt(struct sock *sk, int level, int optname,
     /* [previous][next][first][last][top][bottom][index][help] */
 216                    char *optval, int *optlen)
 217 {               
 218         int val;
 219         int err;
 220         struct linger ling;
 221 
 222         switch(optname) 
 223         {
 224                 case SO_DEBUG:          
 225                         val = sk->debug;
 226                         break;
 227                 
 228                 case SO_DONTROUTE:
 229                         val = sk->localroute;
 230                         break;
 231                 
 232                 case SO_BROADCAST:
 233                         val= sk->broadcast;
 234                         break;
 235 
 236                 case SO_SNDBUF:
 237                         val=sk->sndbuf;
 238                         break;
 239                 
 240                 case SO_RCVBUF:
 241                         val =sk->rcvbuf;
 242                         break;
 243 
 244                 case SO_REUSEADDR:
 245                         val = sk->reuse;
 246                         break;
 247 
 248                 case SO_KEEPALIVE:
 249                         val = sk->keepopen;
 250                         break;
 251 
 252                 case SO_TYPE:
 253                         val = sk->type;                         
 254                         break;
 255 
 256                 case SO_ERROR:
 257                         val = sk->err;
 258                         sk->err = 0;
 259                         break;
 260 
 261                 case SO_OOBINLINE:
 262                         val = sk->urginline;
 263                         break;
 264         
 265                 case SO_NO_CHECK:
 266                         val = sk->no_check;
 267                         break;
 268 
 269                 case SO_PRIORITY:
 270                         val = sk->priority;
 271                         break;
 272                 
 273                 case SO_LINGER: 
 274                         err=verify_area(VERIFY_WRITE,optval,sizeof(ling));
 275                         if(err)
 276                                 return err;
 277                         err=verify_area(VERIFY_WRITE,optlen,sizeof(int));
 278                         if(err)
 279                                 return err;
 280                         put_fs_long(sizeof(ling),(unsigned long *)optlen);
 281                         ling.l_onoff=sk->linger;
 282                         ling.l_linger=sk->lingertime;
 283                         memcpy_tofs(optval,&ling,sizeof(ling));
 284                         return 0;
 285                 
 286 
 287 
 288                 default:
 289                         return(-ENOPROTOOPT);
 290         }
 291         err=verify_area(VERIFY_WRITE, optlen, sizeof(int));
 292         if(err)
 293                 return err;
 294         put_fs_long(sizeof(int),(unsigned long *) optlen);
 295 
 296         err=verify_area(VERIFY_WRITE, optval, sizeof(int));
 297         if(err)
 298                 return err;
 299         put_fs_long(val,(unsigned long *)optval);
 300 
 301         return(0);
 302 }
 303 
 304 
 305 struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force, int priority)
     /* [previous][next][first][last][top][bottom][index][help] */
 306 {
 307         if (sk) 
 308         {
 309                 if (sk->wmem_alloc + size < sk->sndbuf || force) 
 310                 {
 311                         struct sk_buff * c = alloc_skb(size, priority);
 312                         if (c) 
 313                         {
 314                                 unsigned long flags;
 315                                 save_flags(flags);
 316                                 cli();
 317                                 sk->wmem_alloc+= c->mem_len;
 318                                 restore_flags(flags); /* was sti(); */
 319                         }
 320                         return c;
 321                 }
 322                 return(NULL);
 323         }
 324         return(alloc_skb(size, priority));
 325 }
 326 
 327 
 328 struct sk_buff *sock_rmalloc(struct sock *sk, unsigned long size, int force, int priority)
     /* [previous][next][first][last][top][bottom][index][help] */
 329 {
 330         if (sk) 
 331         {
 332                 if (sk->rmem_alloc + size < sk->rcvbuf || force) 
 333                 {
 334                         struct sk_buff *c = alloc_skb(size, priority);
 335                         if (c) 
 336                         {
 337                                 unsigned long flags;
 338                                 save_flags(flags);
 339                                 cli();
 340                                 sk->rmem_alloc += c->mem_len;
 341                                 restore_flags(flags); /* was sti(); */
 342                         }
 343                         return(c);
 344                 }
 345                 return(NULL);
 346         }
 347         return(alloc_skb(size, priority));
 348 }
 349 
 350 
 351 unsigned long sock_rspace(struct sock *sk)
     /* [previous][next][first][last][top][bottom][index][help] */
 352 {
 353         int amt;
 354 
 355         if (sk != NULL) 
 356         {
 357                 if (sk->rmem_alloc >= sk->rcvbuf-2*MIN_WINDOW) 
 358                         return(0);
 359                 amt = min((sk->rcvbuf-sk->rmem_alloc)/2-MIN_WINDOW, MAX_WINDOW);
 360                 if (amt < 0) 
 361                         return(0);
 362                 return(amt);
 363         }
 364         return(0);
 365 }
 366 
 367 
 368 unsigned long sock_wspace(struct sock *sk)
     /* [previous][next][first][last][top][bottom][index][help] */
 369 {
 370         if (sk != NULL) 
 371         {
 372                 if (sk->shutdown & SEND_SHUTDOWN)
 373                         return(0);
 374                 if (sk->wmem_alloc >= sk->sndbuf)
 375                         return(0);
 376                 return(sk->sndbuf-sk->wmem_alloc );
 377         }
 378         return(0);
 379 }
 380 
 381 
 382 void sock_wfree(struct sock *sk, struct sk_buff *skb, unsigned long size)
     /* [previous][next][first][last][top][bottom][index][help] */
 383 {
 384 #ifdef CONFIG_SKB_CHECK
 385         IS_SKB(skb);
 386 #endif
 387         kfree_skbmem(skb, size);
 388         if (sk) 
 389         {
 390                 unsigned long flags;
 391                 save_flags(flags);
 392                 cli();
 393                 sk->wmem_alloc -= size;
 394                 restore_flags(flags);
 395                 /* In case it might be waiting for more memory. */
 396                 sk->write_space(sk);
 397                 return;
 398         }
 399 }
 400 
 401 
 402 void sock_rfree(struct sock *sk, struct sk_buff *skb, unsigned long size)
     /* [previous][next][first][last][top][bottom][index][help] */
 403 {
 404 #ifdef CONFIG_SKB_CHECK
 405         IS_SKB(skb);
 406 #endif  
 407         kfree_skbmem(skb, size);
 408         if (sk) 
 409         {
 410                 unsigned long flags;
 411                 save_flags(flags);
 412                 cli();
 413                 sk->rmem_alloc -= size;
 414                 restore_flags(flags);
 415         }
 416 }
 417 
 418 /*
 419  *      Generic send/receive buffer handlers
 420  */
 421 
 422 struct sk_buff *sock_alloc_send_skb(struct sock *sk, unsigned long size, int noblock, int *errcode)
     /* [previous][next][first][last][top][bottom][index][help] */
 423 {
 424         struct sk_buff *skb;
 425         int err;
 426 
 427         sk->inuse=1;
 428                 
 429         do
 430         {
 431                 if(sk->err!=0)
 432                 {
 433                         cli();
 434                         err= -sk->err;
 435                         sk->err=0;
 436                         sti();
 437                         *errcode=err;
 438                         return NULL;
 439                 }
 440                 
 441                 if(sk->shutdown&SEND_SHUTDOWN)
 442                 {
 443                         *errcode=-EPIPE;
 444                         return NULL;
 445                 }
 446                 
 447                 skb = sock_wmalloc(sk, size, 0, GFP_KERNEL);
 448                 
 449                 if(skb==NULL)
 450                 {
 451                         unsigned long tmp;
 452 
 453                         sk->socket->flags |= SO_NOSPACE;
 454                         if(noblock)
 455                         {
 456                                 *errcode=-EAGAIN;
 457                                 return NULL;
 458                         }
 459                         if(sk->shutdown&SEND_SHUTDOWN)
 460                         {
 461                                 *errcode=-EPIPE;
 462                                 return NULL;
 463                         }
 464                         tmp = sk->wmem_alloc;
 465                         cli();
 466                         if(sk->shutdown&SEND_SHUTDOWN)
 467                         {
 468                                 sti();
 469                                 *errcode=-EPIPE;
 470                                 return NULL;
 471                         }
 472                         
 473                         if( tmp <= sk->wmem_alloc)
 474                         {
 475                                 sk->socket->flags &= ~SO_NOSPACE;
 476                                 interruptible_sleep_on(sk->sleep);
 477                                 if (current->signal & ~current->blocked) 
 478                                 {
 479                                         sti();
 480                                         *errcode = -ERESTARTSYS;
 481                                         return NULL;
 482                                 }
 483                         }
 484                         sti();
 485                 }
 486         }
 487         while(skb==NULL);
 488                 
 489         return skb;
 490 }
 491 
 492 
 493 void release_sock(struct sock *sk)
     /* [previous][next][first][last][top][bottom][index][help] */
 494 {
 495         unsigned long flags;
 496 #ifdef CONFIG_INET
 497         struct sk_buff *skb;
 498 #endif
 499 
 500         if (!sk->prot)
 501                 return;
 502         /*
 503          *      Make the backlog atomic. If we don't do this there is a tiny
 504          *      window where a packet may arrive between the sk->blog being 
 505          *      tested and then set with sk->inuse still 0 causing an extra 
 506          *      unwanted re-entry into release_sock().
 507          */
 508 
 509         save_flags(flags);
 510         cli();
 511         if (sk->blog) 
 512         {
 513                 restore_flags(flags);
 514                 return;
 515         }
 516         sk->blog=1;
 517         sk->inuse = 1;
 518         restore_flags(flags);
 519 #ifdef CONFIG_INET
 520         /* See if we have any packets built up. */
 521         while((skb = skb_dequeue(&sk->back_log)) != NULL) 
 522         {
 523                 sk->blog = 1;
 524                 if (sk->prot->rcv) 
 525                         sk->prot->rcv(skb, skb->dev, sk->opt,
 526                                  skb->saddr, skb->len, skb->daddr, 1,
 527                                 /* Only used for/by raw sockets. */
 528                                 (struct inet_protocol *)sk->pair); 
 529         }
 530 #endif  
 531         sk->blog = 0;
 532         sk->inuse = 0;
 533 #ifdef CONFIG_INET  
 534         if (sk->dead && sk->state == TCP_CLOSE) 
 535         {
 536                 /* Should be about 2 rtt's */
 537                 reset_timer(sk, TIME_DONE, min(sk->rtt * 2, TCP_DONE_TIME));
 538         }
 539 #endif  
 540 }
 541 
 542 

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