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