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, DDP, IPX, AX.25 and NetROM layer all have identical select code and mostly
7 * identical recvmsg() 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 <alan@cymru.net>. (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 */
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 <net/ip.h>
36 #include <net/protocol.h>
37 #include <net/route.h>
38 #include <net/tcp.h>
39 #include <net/udp.h>
40 #include <linux/skbuff.h>
41 #include <net/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 IPX
47 * AX.25 and Appletalk. 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 struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, int noblock, int *err)
/* ![[previous]](../icons/n_left.png)
![[next]](../icons/right.png)
![[first]](../icons/n_first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
53 {
54 struct sk_buff *skb;
55 unsigned long intflags;
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 return NULL;
69 }
70
71 if(sk->err)
72 {
73 release_sock(sk);
74 *err=sock_error(sk);
75 restore_flags(intflags);
76 return NULL;
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 return NULL;
85 }
86
87 /* User doesn't want to wait */
88 if (noblock)
89 {
90 release_sock(sk);
91 *err=-EAGAIN;
92 return NULL;
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 = sock_error(sk);
114 restore_flags(intflags);
115 return NULL;
116 }
117 }
118 sk->inuse = 1;
119 restore_flags(intflags);
120 }
121 /* Again only user level code calls this function, so nothing interrupt level
122 will suddenly eat the receive_queue */
123 if (!(flags & MSG_PEEK))
124 {
125 skb=skb_dequeue(&sk->receive_queue);
126 if(skb!=NULL)
127 skb->users++;
128 else
129 goto restart; /* Avoid race if someone beats us to the data */
130 }
131 else
132 {
133 cli();
134 skb=skb_peek(&sk->receive_queue);
135 if(skb!=NULL)
136 skb->users++;
137 restore_flags(intflags);
138 if(skb==NULL) /* shouldn't happen but .. */
139 *err=-EAGAIN;
140 }
141 return skb;
142 }
143
144 void skb_free_datagram(struct sk_buff *skb)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
145 {
146 unsigned long flags;
147
148 save_flags(flags);
149 cli();
150 skb->users--;
151 if(skb->users>0)
152 {
153 restore_flags(flags);
154 return;
155 }
156 /* See if it needs destroying */
157 if(!skb->next && !skb->prev) /* Been dequeued by someone - ie it's read */
158 kfree_skb(skb,FREE_READ);
159 restore_flags(flags);
160 }
161
162 /*
163 * Copy a datagram to a linear buffer.
164 */
165
166 void skb_copy_datagram(struct sk_buff *skb, int offset, char *to, int size)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
167 {
168 memcpy_tofs(to,skb->h.raw+offset,size);
169 }
170
171
172 /*
173 * Copy a datagram to an iovec.
174 */
175
176 void skb_copy_datagram_iovec(struct sk_buff *skb, int offset, struct iovec *to, int size)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
177 {
178 memcpy_toiovec(to,skb->h.raw+offset,size);
179 }
180
181 /*
182 * Datagram select: Again totally generic. Moved from udp.c
183 * Now does seqpacket.
184 */
185
186 int datagram_select(struct sock *sk, int sel_type, select_table *wait)
/* ![[previous]](../icons/left.png)
![[next]](../icons/n_right.png)
![[first]](../icons/first.png)
![[last]](../icons/n_last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
187 {
188 select_wait(sk->sleep, wait);
189 switch(sel_type)
190 {
191 case SEL_IN:
192 if (sk->err)
193 return 1;
194 if (sk->shutdown & RCV_SHUTDOWN)
195 return 1;
196 if (sk->type==SOCK_SEQPACKET && sk->state==TCP_CLOSE)
197 {
198 /* Connection closed: Wake up */
199 return(1);
200 }
201 if (skb_peek(&sk->receive_queue) != NULL)
202 { /* This appears to be consistent
203 with other stacks */
204 return(1);
205 }
206 return(0);
207
208 case SEL_OUT:
209 if (sk->err)
210 return 1;
211 if (sk->shutdown & SEND_SHUTDOWN)
212 return 1;
213 if (sk->type==SOCK_SEQPACKET && sk->state==TCP_SYN_SENT)
214 {
215 /* Connection still in progress */
216 break;
217 }
218 if (sk->prot && sock_wspace(sk) >= MIN_WRITE_SPACE)
219 {
220 return(1);
221 }
222 if (sk->prot==NULL && sk->sndbuf-sk->wmem_alloc >= MIN_WRITE_SPACE)
223 {
224 return(1);
225 }
226 return(0);
227
228 case SEL_EX:
229 if (sk->err)
230 return(1); /* Socket has gone into error state (eg icmp error) */
231 return(0);
232 }
233 return(0);
234 }