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