This source file includes following definitions.
- udp_err
- udp_check
- udp_send_check
- udp_send
- udp_sendto
- udp_write
- udp_ioctl
- udp_recvfrom
- udp_read
- udp_connect
- udp_close
- udp_rcv
- udp_deliver
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51 #include <asm/system.h>
52 #include <asm/segment.h>
53 #include <linux/types.h>
54 #include <linux/sched.h>
55 #include <linux/fcntl.h>
56 #include <linux/socket.h>
57 #include <linux/sockios.h>
58 #include <linux/in.h>
59 #include <linux/errno.h>
60 #include <linux/timer.h>
61 #include <linux/termios.h>
62 #include <linux/mm.h>
63 #include <linux/inet.h>
64 #include <linux/netdevice.h>
65 #include "snmp.h"
66 #include "ip.h"
67 #include "protocol.h"
68 #include "tcp.h"
69 #include <linux/skbuff.h>
70 #include "sock.h"
71 #include "udp.h"
72 #include "icmp.h"
73
74
75
76
77
78 struct udp_mib udp_statistics;
79
80
81 static int udp_deliver(struct sock *sk, struct udphdr *uh, struct sk_buff *skb, struct device *dev, long saddr, long daddr, int len);
82
83 #define min(a,b) ((a)<(b)?(a):(b))
84
85
86
87
88
89
90
91
92
93
94
95
96
97 void udp_err(int err, unsigned char *header, unsigned long daddr,
98 unsigned long saddr, struct inet_protocol *protocol)
99 {
100 struct udphdr *th;
101 struct sock *sk;
102 struct iphdr *ip=(struct iphdr *)header;
103
104 header += 4*ip->ihl;
105
106
107
108
109
110 th = (struct udphdr *)header;
111
112 sk = get_sock(&udp_prot, th->source, daddr, th->dest, saddr);
113
114 if (sk == NULL)
115 return;
116
117 if (err & 0xff00 ==(ICMP_SOURCE_QUENCH << 8))
118 {
119 if (sk->cong_window > 1)
120 sk->cong_window = sk->cong_window/2;
121 return;
122 }
123
124
125
126
127
128
129
130
131
132 #ifdef CONFIG_I_AM_A_BROKEN_BSD_WEENIE
133
134
135
136
137
138 if (icmp_err_convert[err & 0xff].fatal && sk->state == TCP_ESTABLISHED)
139 {
140 sk->err = icmp_err_convert[err & 0xff].errno;
141 sk->error_report(sk);
142 }
143 #else
144 if (icmp_err_convert[err & 0xff].fatal)
145 {
146 sk->err = icmp_err_convert[err & 0xff].errno;
147 sk->error_report(sk);
148 }
149 #endif
150 }
151
152
153 static unsigned short udp_check(struct udphdr *uh, int len, unsigned long saddr, unsigned long daddr)
154 {
155 unsigned long sum;
156
157 __asm__( "\t addl %%ecx,%%ebx\n"
158 "\t adcl %%edx,%%ebx\n"
159 "\t adcl $0, %%ebx\n"
160 : "=b"(sum)
161 : "0"(daddr), "c"(saddr), "d"((ntohs(len) << 16) + IPPROTO_UDP*256)
162 : "cx","bx","dx" );
163
164 if (len > 3)
165 {
166 __asm__("\tclc\n"
167 "1:\n"
168 "\t lodsl\n"
169 "\t adcl %%eax, %%ebx\n"
170 "\t loop 1b\n"
171 "\t adcl $0, %%ebx\n"
172 : "=b"(sum) , "=S"(uh)
173 : "0"(sum), "c"(len/4) ,"1"(uh)
174 : "ax", "cx", "bx", "si" );
175 }
176
177
178
179
180
181 __asm__("\t movl %%ebx, %%ecx\n"
182 "\t shrl $16,%%ecx\n"
183 "\t addw %%cx, %%bx\n"
184 "\t adcw $0, %%bx\n"
185 : "=b"(sum)
186 : "0"(sum)
187 : "bx", "cx");
188
189
190
191
192
193 if ((len & 2) != 0)
194 {
195 __asm__("\t lodsw\n"
196 "\t addw %%ax,%%bx\n"
197 "\t adcw $0, %%bx\n"
198 : "=b"(sum), "=S"(uh)
199 : "0"(sum) ,"1"(uh)
200 : "si", "ax", "bx");
201 }
202
203
204
205
206
207 if ((len & 1) != 0)
208 {
209 __asm__("\t lodsb\n"
210 "\t movb $0,%%ah\n"
211 "\t addw %%ax,%%bx\n"
212 "\t adcw $0, %%bx\n"
213 : "=b"(sum)
214 : "0"(sum) ,"S"(uh)
215 : "si", "ax", "bx");
216 }
217
218
219
220
221
222 return((~sum) & 0xffff);
223 }
224
225
226
227
228
229
230
231 static void udp_send_check(struct udphdr *uh, unsigned long saddr,
232 unsigned long daddr, int len, struct sock *sk)
233 {
234 uh->check = 0;
235 if (sk && sk->no_check)
236 return;
237 uh->check = udp_check(uh, len, saddr, daddr);
238
239
240
241
242
243
244 if (uh->check == 0)
245 uh->check = 0xffff;
246 }
247
248
249 static int udp_send(struct sock *sk, struct sockaddr_in *sin,
250 unsigned char *from, int len, int rt)
251 {
252 struct sk_buff *skb;
253 struct device *dev;
254 struct udphdr *uh;
255 unsigned char *buff;
256 unsigned long saddr;
257 int size, tmp;
258 int ttl;
259
260
261
262
263
264 size = sk->prot->max_header + len;
265 skb = sock_alloc_send_skb(sk, size, 0, &tmp);
266
267
268 if (skb == NULL)
269 return tmp;
270
271 skb->sk = NULL;
272 skb->free = 1;
273 skb->localroute = sk->localroute|(rt&MSG_DONTROUTE);
274
275
276
277
278
279 buff = skb->data;
280 saddr = sk->saddr;
281 dev = NULL;
282 ttl = sk->ip_ttl;
283 #ifdef CONFIG_IP_MULTICAST
284 if (MULTICAST(sin->sin_addr.s_addr))
285 ttl = sk->ip_mc_ttl;
286 #endif
287 tmp = sk->prot->build_header(skb, saddr, sin->sin_addr.s_addr,
288 &dev, IPPROTO_UDP, sk->opt, skb->mem_len,sk->ip_tos,ttl);
289
290 skb->sk=sk;
291
292
293
294
295
296 if (tmp < 0 )
297 {
298 sk->prot->wfree(sk, skb->mem_addr, skb->mem_len);
299 return(tmp);
300 }
301
302 buff += tmp;
303 saddr = skb->saddr;
304 skb->len = tmp + sizeof(struct udphdr) + len;
305 skb->dev = dev;
306
307
308
309
310
311 uh = (struct udphdr *) buff;
312 uh->len = htons(len + sizeof(struct udphdr));
313 uh->source = sk->dummy_th.source;
314 uh->dest = sin->sin_port;
315 buff = (unsigned char *) (uh + 1);
316
317
318
319
320
321 memcpy_fromfs(buff, from, len);
322
323
324
325
326
327 udp_send_check(uh, saddr, sin->sin_addr.s_addr, skb->len - tmp, sk);
328
329
330
331
332
333 udp_statistics.UdpOutDatagrams++;
334
335 sk->prot->queue_xmit(sk, dev, skb, 1);
336 return(len);
337 }
338
339
340 static int udp_sendto(struct sock *sk, unsigned char *from, int len, int noblock,
341 unsigned flags, struct sockaddr_in *usin, int addr_len)
342 {
343 struct sockaddr_in sin;
344 int tmp;
345
346
347
348
349 if (flags&~MSG_DONTROUTE)
350 return(-EINVAL);
351
352
353
354
355 if (usin)
356 {
357 if (addr_len < sizeof(sin))
358 return(-EINVAL);
359 memcpy(&sin,usin,sizeof(sin));
360 if (sin.sin_family && sin.sin_family != AF_INET)
361 return(-EINVAL);
362 if (sin.sin_port == 0)
363 return(-EINVAL);
364 }
365 else
366 {
367 if (sk->state != TCP_ESTABLISHED)
368 return(-EINVAL);
369 sin.sin_family = AF_INET;
370 sin.sin_port = sk->dummy_th.dest;
371 sin.sin_addr.s_addr = sk->daddr;
372 }
373
374
375
376
377
378
379 if(sin.sin_addr.s_addr==INADDR_ANY)
380 sin.sin_addr.s_addr=ip_my_addr();
381
382 if(!sk->broadcast && ip_chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
383 return -EACCES;
384
385 sk->inuse = 1;
386
387
388 tmp = udp_send(sk, &sin, from, len, flags);
389
390
391 release_sock(sk);
392 return(tmp);
393 }
394
395
396
397
398
399 static int udp_write(struct sock *sk, unsigned char *buff, int len, int noblock,
400 unsigned flags)
401 {
402 return(udp_sendto(sk, buff, len, noblock, flags, NULL, 0));
403 }
404
405
406
407
408
409
410 int udp_ioctl(struct sock *sk, int cmd, unsigned long arg)
411 {
412 int err;
413 switch(cmd)
414 {
415 case TIOCOUTQ:
416 {
417 unsigned long amount;
418
419 if (sk->state == TCP_LISTEN) return(-EINVAL);
420 amount = sk->prot->wspace(sk);
421 err=verify_area(VERIFY_WRITE,(void *)arg,
422 sizeof(unsigned long));
423 if(err)
424 return(err);
425 put_fs_long(amount,(unsigned long *)arg);
426 return(0);
427 }
428
429 case TIOCINQ:
430 {
431 struct sk_buff *skb;
432 unsigned long amount;
433
434 if (sk->state == TCP_LISTEN) return(-EINVAL);
435 amount = 0;
436 skb = skb_peek(&sk->receive_queue);
437 if (skb != NULL) {
438
439
440
441
442
443 amount = skb->len;
444 }
445 err=verify_area(VERIFY_WRITE,(void *)arg,
446 sizeof(unsigned long));
447 if(err)
448 return(err);
449 put_fs_long(amount,(unsigned long *)arg);
450 return(0);
451 }
452
453 default:
454 return(-EINVAL);
455 }
456 return(0);
457 }
458
459
460
461
462
463
464
465 int udp_recvfrom(struct sock *sk, unsigned char *to, int len,
466 int noblock, unsigned flags, struct sockaddr_in *sin,
467 int *addr_len)
468 {
469 int copied = 0;
470 int truesize;
471 struct sk_buff *skb;
472 int er;
473
474
475
476
477
478 if (addr_len)
479 *addr_len=sizeof(*sin);
480
481
482
483
484
485
486 skb=skb_recv_datagram(sk,flags,noblock,&er);
487 if(skb==NULL)
488 return er;
489
490 truesize = skb->len;
491 copied = min(len, truesize);
492
493
494
495
496
497 skb_copy_datagram(skb,sizeof(struct udphdr),to,copied);
498 sk->stamp=skb->stamp;
499
500
501 if (sin)
502 {
503 sin->sin_family = AF_INET;
504 sin->sin_port = skb->h.uh->source;
505 sin->sin_addr.s_addr = skb->daddr;
506 }
507
508 skb_free_datagram(skb);
509 release_sock(sk);
510 return(truesize);
511 }
512
513
514
515
516
517 int udp_read(struct sock *sk, unsigned char *buff, int len, int noblock,
518 unsigned flags)
519 {
520 return(udp_recvfrom(sk, buff, len, noblock, flags, NULL, NULL));
521 }
522
523
524 int udp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
525 {
526 if (addr_len < sizeof(*usin))
527 return(-EINVAL);
528
529 if (usin->sin_family && usin->sin_family != AF_INET)
530 return(-EAFNOSUPPORT);
531 if (usin->sin_addr.s_addr==INADDR_ANY)
532 usin->sin_addr.s_addr=ip_my_addr();
533
534 if(!sk->broadcast && ip_chk_addr(usin->sin_addr.s_addr)==IS_BROADCAST)
535 return -EACCES;
536
537 sk->daddr = usin->sin_addr.s_addr;
538 sk->dummy_th.dest = usin->sin_port;
539 sk->state = TCP_ESTABLISHED;
540 return(0);
541 }
542
543
544 static void udp_close(struct sock *sk, int timeout)
545 {
546 sk->inuse = 1;
547 sk->state = TCP_CLOSE;
548 if (sk->dead)
549 destroy_sock(sk);
550 else
551 release_sock(sk);
552 }
553
554
555
556
557
558
559 int udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
560 unsigned long daddr, unsigned short len,
561 unsigned long saddr, int redo, struct inet_protocol *protocol)
562 {
563 struct sock *sk;
564 struct udphdr *uh;
565 unsigned short ulen;
566 int addr_type = IS_MYADDR;
567
568 if(!dev || dev->pa_addr!=daddr)
569 addr_type=ip_chk_addr(daddr);
570
571
572
573
574 uh = (struct udphdr *) skb->h.uh;
575
576 ip_statistics.IpInDelivers++;
577
578
579
580
581
582 ulen = ntohs(uh->len);
583
584 if (ulen > len || len < sizeof(*uh) || ulen < sizeof(*uh))
585 {
586 printk("UDP: short packet: %d/%d\n", ulen, len);
587 udp_statistics.UdpInErrors++;
588 kfree_skb(skb, FREE_WRITE);
589 return(0);
590 }
591
592 if (uh->check && udp_check(uh, len, saddr, daddr))
593 {
594 printk("UDP: bad checksum.\n");
595 udp_statistics.UdpInErrors++;
596 kfree_skb(skb, FREE_WRITE);
597 return(0);
598 }
599
600
601 len=ulen;
602
603 #ifdef CONFIG_IP_MULTICAST
604 if (addr_type!=IS_MYADDR)
605 {
606
607
608
609 struct sock *sknext=NULL;
610 sk=get_sock_mcast(udp_prot.sock_array[ntohs(uh->dest)&(SOCK_ARRAY_SIZE-1)], uh->dest,
611 saddr, uh->source, daddr);
612 if(sk)
613 {
614 do
615 {
616 struct sk_buff *skb1;
617
618 sknext=get_sock_mcast(sk->next, uh->dest, saddr, uh->source, daddr);
619 if(sknext)
620 skb1=skb_clone(skb,GFP_ATOMIC);
621 else
622 skb1=skb;
623 if(skb1)
624 udp_deliver(sk, uh, skb1, dev,saddr,daddr,len);
625 sk=sknext;
626 }
627 while(sknext!=NULL);
628 }
629 else
630 kfree_skb(skb, FREE_READ);
631 return 0;
632 }
633 #endif
634 sk = get_sock(&udp_prot, uh->dest, saddr, uh->source, daddr);
635 if (sk == NULL)
636 {
637 udp_statistics.UdpNoPorts++;
638 if (addr_type == IS_MYADDR)
639 {
640 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, dev);
641 }
642
643
644
645
646 skb->sk = NULL;
647 kfree_skb(skb, FREE_WRITE);
648 return(0);
649 }
650
651 return udp_deliver(sk,uh,skb,dev, saddr, daddr, len);
652 }
653
654 static int udp_deliver(struct sock *sk, struct udphdr *uh, struct sk_buff *skb, struct device *dev, long saddr, long daddr, int len)
655 {
656 skb->sk = sk;
657 skb->dev = dev;
658 skb->len = len;
659
660
661
662
663
664 skb->daddr = saddr;
665 skb->saddr = daddr;
666
667
668
669
670
671
672 skb->len = len - sizeof(*uh);
673
674 if (sock_queue_rcv_skb(sk,skb)<0)
675 {
676 udp_statistics.UdpInErrors++;
677 ip_statistics.IpInDiscards++;
678 ip_statistics.IpInDelivers--;
679 skb->sk = NULL;
680 kfree_skb(skb, FREE_WRITE);
681 release_sock(sk);
682 return(0);
683 }
684 udp_statistics.UdpInDatagrams++;
685 release_sock(sk);
686 return(0);
687 }
688
689
690 struct proto udp_prot = {
691 sock_wmalloc,
692 sock_rmalloc,
693 sock_wfree,
694 sock_rfree,
695 sock_rspace,
696 sock_wspace,
697 udp_close,
698 udp_read,
699 udp_write,
700 udp_sendto,
701 udp_recvfrom,
702 ip_build_header,
703 udp_connect,
704 NULL,
705 ip_queue_xmit,
706 ip_retransmit,
707 NULL,
708 NULL,
709 udp_rcv,
710 datagram_select,
711 udp_ioctl,
712 NULL,
713 NULL,
714 ip_setsockopt,
715 ip_getsockopt,
716 128,
717 0,
718 {NULL,},
719 "UDP"
720 };
721