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

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