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 * Wait for a packet..
46 *
47 * Interrupts off so that no packet arrives before we begin sleeping.
48 * Otherwise we might miss our wake up
49 */
50 static inline void wait_for_packet(struct sock * sk)
/* ![[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)
*/
51 {
52 unsigned long flags;
53
54 release_sock(sk);
55 save_flags(flags);
56 cli();
57 if (skb_peek(&sk->receive_queue) == NULL)
58 interruptible_sleep_on(sk->sleep);
59 restore_flags(flags);
60 lock_sock(sk);
61 }
62
63
64 /*
65 * Get a datagram skbuff, understands the peeking, nonblocking wakeups and possible
66 * races. This replaces identical code in packet,raw and udp, as well as the IPX
67 * AX.25 and Appletalk. It also finally fixes the long standing peek and read
68 * race for datagram sockets. If you alter this routine remember it must be
69 * re-entrant.
70 *
71 * This function will lock the socket if a skb is returned, so the caller
72 * needs to unlock the socket in that case (usually by calling skb_free_datagram)
73 */
74
75 struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, int noblock, int *err)
/* ![[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)
*/
76 {
77 int error;
78 struct sk_buff *skb;
79
80 lock_sock(sk);
81 restart:
82 while(skb_queue_empty(&sk->receive_queue)) /* No data */
83 {
84 /* Socket errors? */
85 error = sock_error(sk);
86 if (error)
87 goto no_packet;
88
89 /* Socket shut down? */
90 if (sk->shutdown & RCV_SHUTDOWN)
91 goto no_packet;
92
93 /* Sequenced packets can come disconnected. If so we report the problem */
94 error = -ENOTCONN;
95 if(sk->type==SOCK_SEQPACKET && sk->state!=TCP_ESTABLISHED)
96 goto no_packet;
97
98 /* User doesn't want to wait */
99 error = -EAGAIN;
100 if (noblock)
101 goto no_packet;
102
103 /* handle signals */
104 error = -ERESTARTSYS;
105 if (current->signal & ~current->blocked)
106 goto no_packet;
107
108 wait_for_packet(sk);
109 }
110
111 /* Again only user level code calls this function, so nothing interrupt level
112 will suddenly eat the receive_queue */
113 if (flags & MSG_PEEK)
114 {
115 unsigned long flags;
116 save_flags(flags);
117 cli();
118 skb=skb_peek(&sk->receive_queue);
119 if(skb!=NULL)
120 skb->users++;
121 restore_flags(flags);
122 if(skb==NULL) /* shouldn't happen but .. */
123 goto restart;
124 return skb;
125 }
126 skb = skb_dequeue(&sk->receive_queue);
127 if (!skb) /* Avoid race if someone beats us to the data */
128 goto restart;
129 skb->users++;
130 return skb;
131
132 no_packet:
133 release_sock(sk);
134 *err = error;
135 return NULL;
136 }
137
138 void skb_free_datagram(struct sock * sk, 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)
*/
139 {
140 unsigned long flags;
141
142 save_flags(flags);
143 cli();
144 skb->users--;
145 if(skb->users <= 0) {
146 /* See if it needs destroying */
147 /* Been dequeued by someone - ie it's read */
148 if(!skb->next && !skb->prev)
149 kfree_skb(skb,FREE_READ);
150 }
151 restore_flags(flags);
152 release_sock(sk);
153 }
154
155 /*
156 * Copy a datagram to a linear buffer.
157 */
158
159 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)
*/
160 {
161 memcpy_tofs(to,skb->h.raw+offset,size);
162 }
163
164
165 /*
166 * Copy a datagram to an iovec.
167 */
168
169 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)
*/
170 {
171 memcpy_toiovec(to,skb->h.raw+offset,size);
172 }
173
174 /*
175 * Datagram select: Again totally generic. Moved from udp.c
176 * Now does seqpacket.
177 */
178
179 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)
*/
180 {
181 select_wait(sk->sleep, wait);
182 switch(sel_type)
183 {
184 case SEL_IN:
185 if (sk->err)
186 return 1;
187 if (sk->shutdown & RCV_SHUTDOWN)
188 return 1;
189 if (sk->type==SOCK_SEQPACKET && sk->state==TCP_CLOSE)
190 {
191 /* Connection closed: Wake up */
192 return(1);
193 }
194 if (skb_peek(&sk->receive_queue) != NULL)
195 { /* This appears to be consistent
196 with other stacks */
197 return(1);
198 }
199 return(0);
200
201 case SEL_OUT:
202 if (sk->err)
203 return 1;
204 if (sk->shutdown & SEND_SHUTDOWN)
205 return 1;
206 if (sk->type==SOCK_SEQPACKET && sk->state==TCP_SYN_SENT)
207 {
208 /* Connection still in progress */
209 break;
210 }
211 if (sk->prot && sock_wspace(sk) >= MIN_WRITE_SPACE)
212 {
213 return(1);
214 }
215 if (sk->prot==NULL && sk->sndbuf-sk->wmem_alloc >= MIN_WRITE_SPACE)
216 {
217 return(1);
218 }
219 return(0);
220
221 case SEL_EX:
222 if (sk->err)
223 return(1); /* Socket has gone into error state (eg icmp error) */
224 return(0);
225 }
226 return(0);
227 }