1 /*
2 * INET An implementation of the TCP/IP protocol suite for the LINUX
3 * operating system. INET is implemented using the BSD Socket
4 * interface as the means of communication with the user level.
5 *
6 * Generic socket support routines. Memory allocators, sk->inuse/release
7 * handler for protocols to use and generic option handler.
8 *
9 *
10 * Version: @(#)sock.c 1.0.17 06/02/93
11 *
12 * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
13 * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
14 * Florian La Roche, <flla@stud.uni-sb.de>
15 * Alan Cox, <A.Cox@swansea.ac.uk>
16 *
17 * Fixes:
18 * Alan Cox : Numerous verify_area() problems
19 * Alan Cox : Connecting on a connecting socket
20 * now returns an error for tcp.
21 * Alan Cox : sock->protocol is set correctly.
22 * and is not sometimes left as 0.
23 * Alan Cox : connect handles icmp errors on a
24 * connect properly. Unfortunately there
25 * is a restart syscall nasty there. I
26 * can't match BSD without hacking the C
27 * library. Ideas urgently sought!
28 * Alan Cox : Disallow bind() to addresses that are
29 * not ours - especially broadcast ones!!
30 * Alan Cox : Socket 1024 _IS_ ok for users. (fencepost)
31 * Alan Cox : sock_wfree/sock_rfree don't destroy sockets,
32 * instead they leave that for the DESTROY timer.
33 * Alan Cox : Clean up error flag in accept
34 * Alan Cox : TCP ack handling is buggy, the DESTROY timer
35 * was buggy. Put a remove_sock() in the handler
36 * for memory when we hit 0. Also altered the timer
37 * code. The ACK stuff can wait and needs major
38 * TCP layer surgery.
39 * Alan Cox : Fixed TCP ack bug, removed remove sock
40 * and fixed timer/inet_bh race.
41 * Alan Cox : Added zapped flag for TCP
42 * Alan Cox : Move kfree_skb into skbuff.c and tidied up surplus code
43 * Alan Cox : for new sk_buff allocations wmalloc/rmalloc now call alloc_skb
44 * Alan Cox : kfree_s calls now are kfree_skbmem so we can track skb resources
45 * Alan Cox : Supports socket option broadcast now as does udp. Packet and raw need fixing.
46 * Alan Cox : Added RCVBUF,SNDBUF size setting. It suddenly occurred to me how easy it was so...
47 * Rick Sladkey : Relaxed UDP rules for matching packets.
48 * C.E.Hawkins : IFF_PROMISC/SIOCGHWADDR support
49 * Pauline Middelink : identd support
50 * Alan Cox : Fixed connect() taking signals I think.
51 * Alan Cox : SO_LINGER supported
52 * Alan Cox : Error reporting fixes
53 * Anonymous : inet_create tidied up (sk->reuse setting)
54 * Alan Cox : inet sockets don't set sk->type!
55 * Alan Cox : Split socket option code
56 * Alan Cox : Callbacks
57 * Alan Cox : Nagle flag for Charles & Johannes stuff
58 * Alex : Removed restriction on inet fioctl
59 * Alan Cox : Splitting INET from NET core
60 * Alan Cox : Fixed bogus SO_TYPE handling in getsockopt()
61 * Adam Caldwell : Missing return in SO_DONTROUTE/SO_DEBUG code
62 * Alan Cox : Split IP from generic code
63 * Alan Cox : New kfree_skbmem()
64 * Alan Cox : Make SO_DEBUG superuser only.
65 * Alan Cox : Allow anyone to clear SO_DEBUG
66 * (compatibility fix)
67 *
68 * To Fix:
69 *
70 *
71 * This program is free software; you can redistribute it and/or
72 * modify it under the terms of the GNU General Public License
73 * as published by the Free Software Foundation; either version
74 * 2 of the License, or (at your option) any later version.
75 */
76
77 #include <linux/config.h>
78 #include <linux/errno.h>
79 #include <linux/types.h>
80 #include <linux/socket.h>
81 #include <linux/in.h>
82 #include <linux/kernel.h>
83 #include <linux/major.h>
84 #include <linux/sched.h>
85 #include <linux/timer.h>
86 #include <linux/string.h>
87 #include <linux/sockios.h>
88 #include <linux/net.h>
89 #include <linux/fcntl.h>
90 #include <linux/mm.h>
91 #include <linux/interrupt.h>
92
93 #include <asm/segment.h>
94 #include <asm/system.h>
95
96 #include <linux/inet.h>
97 #include <linux/netdevice.h>
98 #include <net/ip.h>
99 #include <net/protocol.h>
100 #include <net/arp.h>
101 #include <net/rarp.h>
102 #include <net/route.h>
103 #include <net/tcp.h>
104 #include <net/udp.h>
105 #include <linux/skbuff.h>
106 #include <net/sock.h>
107 #include <net/raw.h>
108 #include <net/icmp.h>
109
110 #define min(a,b) ((a)<(b)?(a):(b))
111
112 /*
113 * This is meant for all protocols to use and covers goings on
114 * at the socket level. Everything here is generic.
115 */
116
117 int sock_setsockopt(struct sock *sk, int level, int optname,
/* ![[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)
*/
118 char *optval, int optlen)
119 {
120 int val;
121 int valbool;
122 int err;
123 struct linger ling;
124
125 if (optval == NULL)
126 return(-EINVAL);
127
128 err=verify_area(VERIFY_READ, optval, sizeof(int));
129 if(err)
130 return err;
131
132 val = get_user((int *)optval);
133 valbool = val?1:0;
134
135 switch(optname)
136 {
137 case SO_DEBUG:
138 if(val && !suser())
139 return(-EPERM);
140 sk->debug=valbool;
141 return 0;
142 case SO_REUSEADDR:
143 sk->reuse = valbool;
144 return(0);
145 case SO_TYPE:
146 case SO_ERROR:
147 return(-ENOPROTOOPT);
148 case SO_DONTROUTE:
149 sk->localroute=valbool;
150 return 0;
151 case SO_BROADCAST:
152 sk->broadcast=valbool;
153 return 0;
154 case SO_SNDBUF:
155 if(val>32767)
156 val=32767;
157 if(val<256)
158 val=256;
159 sk->sndbuf=val;
160 return 0;
161
162 case SO_RCVBUF:
163 if(val>32767)
164 val=32767;
165 if(val<256)
166 val=256;
167 sk->rcvbuf=val;
168 return(0);
169
170 case SO_KEEPALIVE:
171 sk->keepopen = valbool;
172 return(0);
173
174 case SO_OOBINLINE:
175 sk->urginline = valbool;
176 return(0);
177
178 case SO_NO_CHECK:
179 sk->no_check = valbool;
180 return(0);
181
182 case SO_PRIORITY:
183 if (val >= 0 && val < DEV_NUMBUFFS)
184 {
185 sk->priority = val;
186 }
187 else
188 {
189 return(-EINVAL);
190 }
191 return(0);
192
193
194 case SO_LINGER:
195 err=verify_area(VERIFY_READ,optval,sizeof(ling));
196 if(err)
197 return err;
198 memcpy_fromfs(&ling,optval,sizeof(ling));
199 if(ling.l_onoff==0)
200 sk->linger=0;
201 else
202 {
203 sk->lingertime=ling.l_linger;
204 sk->linger=1;
205 }
206 return 0;
207
208
209 default:
210 return(-ENOPROTOOPT);
211 }
212 }
213
214
215 int sock_getsockopt(struct sock *sk, int level, int optname,
/* ![[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)
*/
216 char *optval, int *optlen)
217 {
218 int val;
219 int err;
220 struct linger ling;
221
222 switch(optname)
223 {
224 case SO_DEBUG:
225 val = sk->debug;
226 break;
227
228 case SO_DONTROUTE:
229 val = sk->localroute;
230 break;
231
232 case SO_BROADCAST:
233 val= sk->broadcast;
234 break;
235
236 case SO_SNDBUF:
237 val=sk->sndbuf;
238 break;
239
240 case SO_RCVBUF:
241 val =sk->rcvbuf;
242 break;
243
244 case SO_REUSEADDR:
245 val = sk->reuse;
246 break;
247
248 case SO_KEEPALIVE:
249 val = sk->keepopen;
250 break;
251
252 case SO_TYPE:
253 val = sk->type;
254 break;
255
256 case SO_ERROR:
257 val = sk->err;
258 sk->err = 0;
259 break;
260
261 case SO_OOBINLINE:
262 val = sk->urginline;
263 break;
264
265 case SO_NO_CHECK:
266 val = sk->no_check;
267 break;
268
269 case SO_PRIORITY:
270 val = sk->priority;
271 break;
272
273 case SO_LINGER:
274 err=verify_area(VERIFY_WRITE,optval,sizeof(ling));
275 if(err)
276 return err;
277 err=verify_area(VERIFY_WRITE,optlen,sizeof(int));
278 if(err)
279 return err;
280 put_fs_long(sizeof(ling),(unsigned long *)optlen);
281 ling.l_onoff=sk->linger;
282 ling.l_linger=sk->lingertime;
283 memcpy_tofs(optval,&ling,sizeof(ling));
284 return 0;
285
286
287
288 default:
289 return(-ENOPROTOOPT);
290 }
291 err=verify_area(VERIFY_WRITE, optlen, sizeof(int));
292 if(err)
293 return err;
294 put_fs_long(sizeof(int),(unsigned long *) optlen);
295
296 err=verify_area(VERIFY_WRITE, optval, sizeof(int));
297 if(err)
298 return err;
299 put_fs_long(val,(unsigned long *)optval);
300
301 return(0);
302 }
303
304
305 struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force, int priority)
/* ![[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)
*/
306 {
307 if (sk)
308 {
309 if (sk->wmem_alloc + size < sk->sndbuf || force)
310 {
311 struct sk_buff * c = alloc_skb(size, priority);
312 if (c)
313 {
314 unsigned long flags;
315 save_flags(flags);
316 cli();
317 sk->wmem_alloc+= c->truesize;
318 restore_flags(flags); /* was sti(); */
319 }
320 return c;
321 }
322 return(NULL);
323 }
324 return(alloc_skb(size, priority));
325 }
326
327
328 struct sk_buff *sock_rmalloc(struct sock *sk, unsigned long size, int force, int priority)
/* ![[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)
*/
329 {
330 if (sk)
331 {
332 if (sk->rmem_alloc + size < sk->rcvbuf || force)
333 {
334 struct sk_buff *c = alloc_skb(size, priority);
335 if (c)
336 {
337 unsigned long flags;
338 save_flags(flags);
339 cli();
340 sk->rmem_alloc += c->truesize;
341 restore_flags(flags); /* was sti(); */
342 }
343 return(c);
344 }
345 return(NULL);
346 }
347 return(alloc_skb(size, priority));
348 }
349
350
351 unsigned long sock_rspace(struct sock *sk)
/* ![[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)
*/
352 {
353 int amt;
354
355 if (sk != NULL)
356 {
357 if (sk->rmem_alloc >= sk->rcvbuf-2*MIN_WINDOW)
358 return(0);
359 amt = min((sk->rcvbuf-sk->rmem_alloc)/2-MIN_WINDOW, MAX_WINDOW);
360 if (amt < 0)
361 return(0);
362 return(amt);
363 }
364 return(0);
365 }
366
367
368 unsigned long sock_wspace(struct sock *sk)
/* ![[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)
*/
369 {
370 if (sk != NULL)
371 {
372 if (sk->shutdown & SEND_SHUTDOWN)
373 return(0);
374 if (sk->wmem_alloc >= sk->sndbuf)
375 return(0);
376 return(sk->sndbuf-sk->wmem_alloc );
377 }
378 return(0);
379 }
380
381
382 void sock_wfree(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)
*/
383 {
384 int s=skb->truesize;
385 #if CONFIG_SKB_CHECK
386 IS_SKB(skb);
387 #endif
388 kfree_skbmem(skb);
389 if (sk)
390 {
391 unsigned long flags;
392 save_flags(flags);
393 cli();
394 sk->wmem_alloc -= s;
395 restore_flags(flags);
396 /* In case it might be waiting for more memory. */
397 sk->write_space(sk);
398 return;
399 }
400 }
401
402
403 void sock_rfree(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)
*/
404 {
405 int s=skb->truesize;
406 #if CONFIG_SKB_CHECK
407 IS_SKB(skb);
408 #endif
409 kfree_skbmem(skb);
410 if (sk)
411 {
412 unsigned long flags;
413 save_flags(flags);
414 cli();
415 sk->rmem_alloc -= s;
416 restore_flags(flags);
417 }
418 }
419
420 /*
421 * Generic send/receive buffer handlers
422 */
423
424 struct sk_buff *sock_alloc_send_skb(struct sock *sk, unsigned long size, int noblock, int *errcode)
/* ![[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)
*/
425 {
426 struct sk_buff *skb;
427 int err;
428
429 sk->inuse=1;
430
431 do
432 {
433 if(sk->err!=0)
434 {
435 cli();
436 err= -sk->err;
437 sk->err=0;
438 sti();
439 *errcode=err;
440 return NULL;
441 }
442
443 if(sk->shutdown&SEND_SHUTDOWN)
444 {
445 *errcode=-EPIPE;
446 return NULL;
447 }
448
449 skb = sock_wmalloc(sk, size, 0, GFP_KERNEL);
450
451 if(skb==NULL)
452 {
453 unsigned long tmp;
454
455 sk->socket->flags |= SO_NOSPACE;
456 if(noblock)
457 {
458 *errcode=-EAGAIN;
459 return NULL;
460 }
461 if(sk->shutdown&SEND_SHUTDOWN)
462 {
463 *errcode=-EPIPE;
464 return NULL;
465 }
466 tmp = sk->wmem_alloc;
467 cli();
468 if(sk->shutdown&SEND_SHUTDOWN)
469 {
470 sti();
471 *errcode=-EPIPE;
472 return NULL;
473 }
474
475 if( tmp <= sk->wmem_alloc)
476 {
477 sk->socket->flags &= ~SO_NOSPACE;
478 interruptible_sleep_on(sk->sleep);
479 if (current->signal & ~current->blocked)
480 {
481 sti();
482 *errcode = -ERESTARTSYS;
483 return NULL;
484 }
485 }
486 sti();
487 }
488 }
489 while(skb==NULL);
490
491 return skb;
492 }
493
494
495 void release_sock(struct sock *sk)
/* ![[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)
*/
496 {
497 unsigned long flags;
498 #ifdef CONFIG_INET
499 struct sk_buff *skb;
500 #endif
501
502 if (!sk->prot)
503 return;
504 /*
505 * Make the backlog atomic. If we don't do this there is a tiny
506 * window where a packet may arrive between the sk->blog being
507 * tested and then set with sk->inuse still 0 causing an extra
508 * unwanted re-entry into release_sock().
509 */
510
511 save_flags(flags);
512 cli();
513 if (sk->blog)
514 {
515 restore_flags(flags);
516 return;
517 }
518 sk->blog=1;
519 sk->inuse = 1;
520 restore_flags(flags);
521 #ifdef CONFIG_INET
522 /* See if we have any packets built up. */
523 while((skb = skb_dequeue(&sk->back_log)) != NULL)
524 {
525 sk->blog = 1;
526 if (sk->prot->rcv)
527 sk->prot->rcv(skb, skb->dev, sk->opt,
528 skb->saddr, skb->len, skb->daddr, 1,
529 /* Only used for/by raw sockets. */
530 (struct inet_protocol *)sk->pair);
531 }
532 #endif
533 sk->blog = 0;
534 sk->inuse = 0;
535 #ifdef CONFIG_INET
536 if (sk->dead && sk->state == TCP_CLOSE)
537 {
538 /* Should be about 2 rtt's */
539 reset_timer(sk, TIME_DONE, min(sk->rtt * 2, TCP_DONE_TIME));
540 }
541 #endif
542 }
543
544