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

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