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