root/net/inet/datagram.c

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

DEFINITIONS

This source file includes following definitions.
  1. skb_recv_datagram
  2. skb_free_datagram
  3. skb_copy_datagram
  4. datagram_select

   1 /*
   2  *      SUCS    NET2 Debugged.
   3  *
   4  *      Generic datagram handling routines. These are generic for all protocols. Possibly a generic IP version on top
   5  *      of these would make sense. Not tonight however 8-). 
   6  *      This is used because UDP, RAW, PACKET and the to be released IPX layer all have identical select code and mostly
   7  *      identical recvfrom() code. So we share it here. The select was shared before but buried in udp.c so I moved it.
   8  *
   9  *      Authors:        Alan Cox <iiitac@pyr.swan.ac.uk>. (datagram_select() from old udp.c code)
  10  *
  11  *      Fixes:
  12  *              Alan Cox        :       NULL return from skb_peek_copy() understood
  13  *              Alan Cox        :       Rewrote skb_read_datagram to avoid the skb_peek_copy stuff.
  14  */
  15 
  16 #include <linux/config.h>
  17 #include <linux/types.h>
  18 #include <linux/kernel.h>
  19 #include <asm/segment.h>
  20 #include <asm/system.h>
  21 #include <linux/mm.h>
  22 #include <linux/interrupt.h>
  23 #include <linux/in.h>
  24 #include <linux/errno.h>
  25 #include <linux/sched.h>
  26 #include "inet.h"
  27 #include "dev.h"
  28 #include "ip.h"
  29 #include "protocol.h"
  30 #include "arp.h"
  31 #include "route.h"
  32 #include "tcp.h"
  33 #include "udp.h"
  34 #include "skbuff.h"
  35 #include "sock.h"
  36  
  37 
  38 /*
  39  *      Get a datagram skbuff, understands the peeking, nonblocking wakeups and possible
  40  *      races. This replaces identical code in packet,raw and udp, as well as the yet to
  41  *      be released IPX support. It also finally fixes the long standing peek and read
  42  *      race for datagram sockets. If you alter this routine remember it must be
  43  *      re-entrant.
  44  */
  45 
  46 struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, int noblock, int *err)
     /* [previous][next][first][last][top][bottom][index][help] */
  47 {  
  48         struct sk_buff *skb;
  49         
  50         /* Socket is inuse - so the timer doesn't attack it */
  51 restart:
  52         sk->inuse = 1;
  53         while(sk->rqueue == NULL)       /* No data */
  54         {
  55                 /* If we are shutdown then no more data is going to appear. We are done */
  56                 if (sk->shutdown & RCV_SHUTDOWN) 
  57                 {
  58                         release_sock(sk);
  59                         *err=0;
  60                         return NULL;
  61                 }
  62 
  63                 /* User doesn't want to wait */
  64                 if (noblock) 
  65                 {
  66                         release_sock(sk);
  67                         *err=-EAGAIN;
  68                         return NULL;
  69                 }
  70                 release_sock(sk);
  71                 
  72                 /* Interrupts off so that no packet arrives before we begin sleeping. 
  73                    Otherwise we might miss our wake up */
  74                 cli();
  75                 if (sk->rqueue == NULL) 
  76                 {
  77                         interruptible_sleep_on(sk->sleep);
  78                         /* Signals may need a restart of the syscall */
  79                         if (current->signal & ~current->blocked) 
  80                         {
  81                                 sti();
  82                                 *err=-ERESTARTSYS;
  83                                 return(NULL);
  84                         }
  85                         if(sk->err != 0)        /* Error while waiting for packet
  86                                                    eg an icmp sent earlier by the
  87                                                    peer has finaly turned up now */
  88                         {
  89                                 *err = -sk->err;
  90                                 sti();
  91                                 sk->err=0;
  92                                 return NULL;
  93                         }
  94                 }
  95                 sk->inuse = 1;
  96                 sti();
  97           }
  98           /* Again only user level code calls this function, so nothing interrupt level
  99              will suddenely eat the rqueue */
 100           if (!(flags & MSG_PEEK)) 
 101           {
 102                 skb=skb_dequeue(&sk->rqueue);
 103                 if(skb!=NULL)
 104                         skb->users++;
 105                 else
 106                         goto restart;   /* Avoid race if someone beats us to the data */
 107           }
 108           else
 109           {
 110                 cli();
 111                 skb=skb_peek(&sk->rqueue);
 112                 if(skb!=NULL)
 113                         skb->users++;
 114                 sti();
 115                 if(skb==NULL)   /* shouldn't happen but .. */
 116                         *err=-EAGAIN;
 117           }
 118           return skb;
 119 }       
 120 
 121 void skb_free_datagram(struct sk_buff *skb)
     /* [previous][next][first][last][top][bottom][index][help] */
 122 {
 123         unsigned long flags;
 124 
 125         save_flags(flags);
 126         cli();
 127         skb->users--;
 128         if(skb->users>0)
 129         {
 130                 restore_flags(flags);
 131                 return;
 132         }
 133         /* See if it needs destroying */
 134         if(skb->list == NULL)   /* Been dequeued by someone - ie its read */
 135                 kfree_skb(skb,FREE_READ);
 136         restore_flags(flags);
 137 }
 138 
 139 void skb_copy_datagram(struct sk_buff *skb, int offset, char *to, int size)
     /* [previous][next][first][last][top][bottom][index][help] */
 140 {
 141         /* We will know all about the fraglist options to allow >4K receives 
 142            but not this release */
 143         memcpy_tofs(to,skb->h.raw+offset,size);
 144 }
 145 
 146 /*
 147  *      Datagram select: Again totally generic. Moved from udp.c
 148  */
 149  
 150 int datagram_select(struct sock *sk, int sel_type, select_table *wait)
     /* [previous][next][first][last][top][bottom][index][help] */
 151 {
 152         select_wait(sk->sleep, wait);
 153         switch(sel_type) 
 154         {
 155                 case SEL_IN:
 156                         if (sk->rqueue != NULL || sk->err != 0) 
 157                         {       /* This appears to be consistent
 158                                    with other stacks */
 159                                 return(1);
 160                         }
 161                         return(0);
 162 
 163                 case SEL_OUT:
 164                         if (sk->prot->wspace(sk) >= MIN_WRITE_SPACE) 
 165                         {
 166                                 return(1);
 167                         }
 168                         return(0);
 169         
 170                 case SEL_EX:
 171                         if (sk->err) 
 172                                 return(1); /* Socket has gone into error state (eg icmp error) */
 173                         return(0);
 174         }
 175         return(0);
 176 }

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