root/net/core/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. skb_copy_datagram_iovec
  5. datagram_select

   1 /*
   2  *      SUCS NET3:
   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  *              Alan Cox        :       Added support for SOCK_SEQPACKET. IPX can no longer use the SO_TYPE hack but
  15  *                                      AX.25 now works right, and SPX is feasible.
  16  *              Alan Cox        :       Fixed write select of non IP protocol crash.
  17  *              Florian  La Roche:      Changed for my new skbuff handling.
  18  *              Darryl Miles    :       Fixed non-blocking SOCK_SEQPACKET.
  19  *              Linus Torvalds  :       BSD semantic fixes.
  20  *              Alan Cox        :       Datagram iovec handling
  21  *
  22  *      Note:
  23  *              A lot of this will change when the protocol/socket separation
  24  *      occurs. Using this will make things reasonably clean.
  25  */
  26 
  27 #include <linux/types.h>
  28 #include <linux/kernel.h>
  29 #include <asm/segment.h>
  30 #include <asm/system.h>
  31 #include <linux/mm.h>
  32 #include <linux/interrupt.h>
  33 #include <linux/in.h>
  34 #include <linux/errno.h>
  35 #include <linux/sched.h>
  36 #include <linux/inet.h>
  37 #include <linux/netdevice.h>
  38 #include <net/ip.h>
  39 #include <net/protocol.h>
  40 #include <net/route.h>
  41 #include <net/tcp.h>
  42 #include <net/udp.h>
  43 #include <linux/skbuff.h>
  44 #include <net/sock.h>
  45 
  46 
  47 /*
  48  *      Get a datagram skbuff, understands the peeking, nonblocking wakeups and possible
  49  *      races. This replaces identical code in packet,raw and udp, as well as the IPX
  50  *      AX.25 and Appletalk. It also finally fixes the long standing peek and read
  51  *      race for datagram sockets. If you alter this routine remember it must be
  52  *      re-entrant.
  53  */
  54 
  55 struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, int noblock, int *err)
     /* [previous][next][first][last][top][bottom][index][help] */
  56 {
  57         struct sk_buff *skb;
  58         unsigned long intflags;
  59 
  60         /* Socket is inuse - so the timer doesn't attack it */
  61         save_flags(intflags);
  62 restart:
  63         sk->inuse = 1;
  64         while(skb_peek(&sk->receive_queue) == NULL)     /* No data */
  65         {
  66                 /* If we are shutdown then no more data is going to appear. We are done */
  67                 if (sk->shutdown & RCV_SHUTDOWN)
  68                 {
  69                         release_sock(sk);
  70                         *err=0;
  71                         return NULL;
  72                 }
  73 
  74                 if(sk->err)
  75                 {
  76                         release_sock(sk);
  77                         cli();
  78                         *err=-sk->err;
  79                         sk->err=0;
  80                         restore_flags(intflags);
  81                         return NULL;
  82                 }
  83 
  84                 /* Sequenced packets can come disconnected. If so we report the problem */
  85                 if(sk->type==SOCK_SEQPACKET && sk->state!=TCP_ESTABLISHED)
  86                 {
  87                         release_sock(sk);
  88                         *err=-ENOTCONN;
  89                         return NULL;
  90                 }
  91 
  92                 /* User doesn't want to wait */
  93                 if (noblock)
  94                 {
  95                         release_sock(sk);
  96                         *err=-EAGAIN;
  97                         return NULL;
  98                 }
  99                 release_sock(sk);
 100 
 101                 /* Interrupts off so that no packet arrives before we begin sleeping.
 102                    Otherwise we might miss our wake up */
 103                 cli();
 104                 if (skb_peek(&sk->receive_queue) == NULL)
 105                 {
 106                         interruptible_sleep_on(sk->sleep);
 107                         /* Signals may need a restart of the syscall */
 108                         if (current->signal & ~current->blocked)
 109                         {
 110                                 restore_flags(intflags);;
 111                                 *err=-ERESTARTSYS;
 112                                 return(NULL);
 113                         }
 114                         if(sk->err != 0)        /* Error while waiting for packet
 115                                                    eg an icmp sent earlier by the
 116                                                    peer has finally turned up now */
 117                         {
 118                                 *err = -sk->err;
 119                                 sk->err=0;
 120                                 restore_flags(intflags);
 121                                 return NULL;
 122                         }
 123                 }
 124                 sk->inuse = 1;
 125                 restore_flags(intflags);
 126           }
 127           /* Again only user level code calls this function, so nothing interrupt level
 128              will suddenly eat the receive_queue */
 129           if (!(flags & MSG_PEEK))
 130           {
 131                 skb=skb_dequeue(&sk->receive_queue);
 132                 if(skb!=NULL)
 133                         skb->users++;
 134                 else
 135                         goto restart;   /* Avoid race if someone beats us to the data */
 136           }
 137           else
 138           {
 139                 cli();
 140                 skb=skb_peek(&sk->receive_queue);
 141                 if(skb!=NULL)
 142                         skb->users++;
 143                 restore_flags(intflags);
 144                 if(skb==NULL)   /* shouldn't happen but .. */
 145                         *err=-EAGAIN;
 146           }
 147           return skb;
 148 }
 149 
 150 void skb_free_datagram(struct sk_buff *skb)
     /* [previous][next][first][last][top][bottom][index][help] */
 151 {
 152         unsigned long flags;
 153 
 154         save_flags(flags);
 155         cli();
 156         skb->users--;
 157         if(skb->users>0)
 158         {
 159                 restore_flags(flags);
 160                 return;
 161         }
 162         /* See if it needs destroying */
 163         if(!skb->next && !skb->prev)    /* Been dequeued by someone - ie it's read */
 164                 kfree_skb(skb,FREE_READ);
 165         restore_flags(flags);
 166 }
 167 
 168 /*
 169  *      Copy a datagram to a linear buffer.
 170  */
 171 
 172 void skb_copy_datagram(struct sk_buff *skb, int offset, char *to, int size)
     /* [previous][next][first][last][top][bottom][index][help] */
 173 {
 174         memcpy_tofs(to,skb->h.raw+offset,size);
 175 }
 176 
 177 
 178 /*
 179  *      Copy a datagram to an iovec.
 180  */
 181  
 182 void skb_copy_datagram_iovec(struct sk_buff *skb, int offset, struct iovec *to, int size)
     /* [previous][next][first][last][top][bottom][index][help] */
 183 {
 184         memcpy_toiovec(to,skb->h.raw+offset,size);
 185 }
 186 
 187 /*
 188  *      Datagram select: Again totally generic. Moved from udp.c
 189  *      Now does seqpacket.
 190  */
 191 
 192 int datagram_select(struct sock *sk, int sel_type, select_table *wait)
     /* [previous][next][first][last][top][bottom][index][help] */
 193 {
 194         select_wait(sk->sleep, wait);
 195         switch(sel_type)
 196         {
 197                 case SEL_IN:
 198                         if (sk->err)
 199                                 return 1;
 200                         if (sk->shutdown & RCV_SHUTDOWN)
 201                                 return 1;
 202                         if (sk->type==SOCK_SEQPACKET && sk->state==TCP_CLOSE)
 203                         {
 204                                 /* Connection closed: Wake up */
 205                                 return(1);
 206                         }
 207                         if (skb_peek(&sk->receive_queue) != NULL)
 208                         {       /* This appears to be consistent
 209                                    with other stacks */
 210                                 return(1);
 211                         }
 212                         return(0);
 213 
 214                 case SEL_OUT:
 215                         if (sk->err)
 216                                 return 1;
 217                         if (sk->shutdown & SEND_SHUTDOWN)
 218                                 return 1;
 219                         if (sk->type==SOCK_SEQPACKET && sk->state==TCP_SYN_SENT)
 220                         {
 221                                 /* Connection still in progress */
 222                                 break;
 223                         }
 224                         if (sk->prot && sk->prot->wspace(sk) >= MIN_WRITE_SPACE)
 225                         {
 226                                 return(1);
 227                         }
 228                         if (sk->prot==NULL && sk->sndbuf-sk->wmem_alloc >= MIN_WRITE_SPACE)
 229                         {
 230                                 return(1);
 231                         }
 232                         return(0);
 233 
 234                 case SEL_EX:
 235                         if (sk->err)
 236                                 return(1); /* Socket has gone into error state (eg icmp error) */
 237                         return(0);
 238         }
 239         return(0);
 240 }

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