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 <net/ip.h>
37 #include <net/protocol.h>
38 #include <net/route.h>
39 #include <net/tcp.h>
40 #include <net/udp.h>
41 #include <linux/skbuff.h>
42 #include <net/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 IPX 48 * AX.25 and Appletalk. 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 structsk_buff *skb_recv_datagram(structsock *sk, unsignedflags, intnoblock, int *err)
/* */ 54 { 55 structsk_buff *skb;
56 unsignedlongintflags;
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 returnNULL;
70 } 71
72 if(sk->err)
73 { 74 release_sock(sk);
75 cli();
76 *err=-sk->err;
77 sk->err=0;
78 restore_flags(intflags);
79 returnNULL;
80 } 81
82 /* Sequenced packets can come disconnected. If so we report the problem */ 83 if(sk->type==SOCK_SEQPACKET && sk->state!=TCP_ESTABLISHED)
84 { 85 release_sock(sk);
86 *err=-ENOTCONN;
87 returnNULL;
88 } 89
90 /* User doesn't want to wait */ 91 if (noblock)
92 { 93 release_sock(sk);
94 *err=-EAGAIN;
95 returnNULL;
96 } 97 release_sock(sk);
98
99 /* Interrupts off so that no packet arrives before we begin sleeping. 100 Otherwise we might miss our wake up */ 101 cli();
102 if (skb_peek(&sk->receive_queue) == NULL)
103 { 104 interruptible_sleep_on(sk->sleep);
105 /* Signals may need a restart of the syscall */ 106 if (current->signal & ~current->blocked)
107 { 108 restore_flags(intflags);;
109 *err=-ERESTARTSYS;
110 return(NULL);
111 } 112 if(sk->err != 0) /* Error while waiting for packet 113 eg an icmp sent earlier by the 114 peer has finally turned up now */ 115 { 116 *err = -sk->err;
117 sk->err=0;
118 restore_flags(intflags);
119 returnNULL;
120 } 121 } 122 sk->inuse = 1;
123 restore_flags(intflags);
124 } 125 /* Again only user level code calls this function, so nothing interrupt level 126 will suddenly eat the receive_queue */ 127 if (!(flags & MSG_PEEK))
128 { 129 skb=skb_dequeue(&sk->receive_queue);
130 if(skb!=NULL)
131 skb->users++;
132 else 133 gotorestart; /* Avoid race if someone beats us to the data */ 134 } 135 else 136 { 137 cli();
138 skb=skb_peek(&sk->receive_queue);
139 if(skb!=NULL)
140 skb->users++;
141 restore_flags(intflags);
142 if(skb==NULL) /* shouldn't happen but .. */ 143 *err=-EAGAIN;
144 } 145 returnskb;
146 } 147
148 voidskb_free_datagram(structsk_buff *skb)
/* */ 149 { 150 unsignedlongflags;
151
152 save_flags(flags);
153 cli();
154 skb->users--;
155 if(skb->users>0)
156 { 157 restore_flags(flags);
158 return;
159 } 160 /* See if it needs destroying */ 161 if(!skb->next && !skb->prev) /* Been dequeued by someone - ie it's read */ 162 kfree_skb(skb,FREE_READ);
163 restore_flags(flags);
164 } 165
166 voidskb_copy_datagram(structsk_buff *skb, intoffset, char *to, intsize)
/* */ 167 { 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 intdatagram_select(structsock *sk, intsel_type, select_table *wait)
/* */ 177 { 178 select_wait(sk->sleep, wait);
179 switch(sel_type)
180 { 181 caseSEL_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 caseSEL_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 caseSEL_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 }