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