root/net/inet/udp.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. print_udp
  2. udp_select
  3. udp_err
  4. udp_check
  5. udp_send_check
  6. udp_send
  7. udp_sendto
  8. udp_write
  9. udp_ioctl
  10. udp_recvfrom
  11. udp_read
  12. udp_connect
  13. udp_close
  14. udp_rcv

   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  *              The User Datagram Protocol (UDP).
   7  *
   8  * Version:     @(#)udp.c       1.0.13  06/02/93
   9  *
  10  * Authors:     Ross Biro, <bir7@leland.Stanford.Edu>
  11  *              Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  12  *
  13  *              This program is free software; you can redistribute it and/or
  14  *              modify it under the terms of the GNU General Public License
  15  *              as published by the Free Software Foundation; either version
  16  *              2 of the License, or (at your option) any later version.
  17  */
  18 #include <asm/system.h>
  19 #include <asm/segment.h>
  20 #include <linux/types.h>
  21 #include <linux/sched.h>
  22 #include <linux/fcntl.h>
  23 #include <linux/socket.h>
  24 #include <linux/sockios.h>
  25 #include <linux/in.h>
  26 #include <linux/errno.h>
  27 #include <linux/timer.h>
  28 #include <linux/termios.h>
  29 #include <linux/mm.h>
  30 #include "inet.h"
  31 #include "dev.h"
  32 #include "ip.h"
  33 #include "protocol.h"
  34 #include "tcp.h"
  35 #include "skbuff.h"
  36 #include "sock.h"
  37 #include "udp.h"
  38 #include "icmp.h"
  39 
  40 
  41 #define min(a,b)        ((a)<(b)?(a):(b))
  42 
  43 
  44 static void
  45 print_udp(struct udphdr *uh)
     /* [previous][next][first][last][top][bottom][index][help] */
  46 {
  47   if (inet_debug != DBG_UDP) return;
  48 
  49   if (uh == NULL) {
  50         printk("(NULL)\n");
  51         return;
  52   }
  53   printk("UDP: source = %d, dest = %d\n", ntohs(uh->source), ntohs(uh->dest));
  54   printk("     len = %d, check = %d\n", ntohs(uh->len), ntohs(uh->check));
  55 }
  56 
  57 
  58 int
  59 udp_select(struct sock *sk, int sel_type, select_table *wait)
     /* [previous][next][first][last][top][bottom][index][help] */
  60 {
  61   select_wait(sk->sleep, wait);
  62   switch(sel_type) {
  63         case SEL_IN:
  64                 if (sk->rqueue != NULL) {
  65                         return(1);
  66                 }
  67                 return(0);
  68 
  69         case SEL_OUT:
  70                 if (sk->prot->wspace(sk) >= MIN_WRITE_SPACE) {
  71                         return(1);
  72                 }
  73                 return(0);
  74         
  75         case SEL_EX:
  76                 if (sk->err) return(1); /* can this ever happen? */
  77                 return(0);
  78   }
  79   return(0);
  80 }
  81 
  82 
  83 /*
  84  * This routine is called by the ICMP module when it gets some
  85  * sort of error condition.  If err < 0 then the socket should
  86  * be closed and the error returned to the user.  If err > 0
  87  * it's just the icmp type << 8 | icmp code.  
  88  * header points to the first 8 bytes of the tcp header.  We need
  89  * to find the appropriate port.
  90  */
  91 void
  92 udp_err(int err, unsigned char *header, unsigned long daddr,
     /* [previous][next][first][last][top][bottom][index][help] */
  93         unsigned long saddr, struct inet_protocol *protocol)
  94 {
  95   struct udphdr *th;
  96   struct sock *sk;
  97    
  98   DPRINTF((DBG_UDP,
  99         "UDP: err(err=%d, header=%X, daddr=%X, saddr=%X, protocl=%X)\n",
 100                                         err, header, daddr, saddr, protocol));
 101 
 102   th = (struct udphdr *)header;
 103   sk = get_sock(&udp_prot, th->dest, saddr, th->source, daddr);
 104 
 105   if (sk == NULL) return;
 106   if (err & 0xff00 ==(ICMP_SOURCE_QUENCH << 8)) {
 107         if (sk->cong_window > 1) sk->cong_window = sk->cong_window/2;
 108         return;
 109   }
 110 
 111   sk->err = icmp_err_convert[err & 0xff].errno;
 112 
 113   /* It's only fatal if we have connected to them. */
 114   if (icmp_err_convert[err & 0xff].fatal && sk->state == TCP_ESTABLISHED) {
 115         sk->prot->close(sk, 0);
 116   }
 117 }
 118 
 119 
 120 static unsigned short
 121 udp_check(struct udphdr *uh, int len,
     /* [previous][next][first][last][top][bottom][index][help] */
 122           unsigned long saddr, unsigned long daddr)
 123 {
 124   unsigned long sum;
 125 
 126   DPRINTF((DBG_UDP, "UDP: check(uh=%X, len = %d, saddr = %X, daddr = %X)\n",
 127                                                         uh, len, saddr, daddr));
 128 
 129   print_udp(uh);
 130 
 131   __asm__("\t addl %%ecx,%%ebx\n"
 132           "\t adcl %%edx,%%ebx\n"
 133           "\t adcl $0, %%ebx\n"
 134           : "=b"(sum)
 135           : "0"(daddr), "c"(saddr), "d"((ntohs(len) << 16) + IPPROTO_UDP*256)
 136           : "cx","bx","dx" );
 137 
 138   if (len > 3) {
 139         __asm__("\tclc\n"
 140                 "1:\n"
 141                 "\t lodsl\n"
 142                 "\t adcl %%eax, %%ebx\n"
 143                 "\t loop 1b\n"
 144                 "\t adcl $0, %%ebx\n"
 145                 : "=b"(sum) , "=S"(uh)
 146                 : "0"(sum), "c"(len/4) ,"1"(uh)
 147                 : "ax", "cx", "bx", "si" );
 148   }
 149 
 150   /* Convert from 32 bits to 16 bits. */
 151   __asm__("\t movl %%ebx, %%ecx\n"
 152           "\t shrl $16,%%ecx\n"
 153           "\t addw %%cx, %%bx\n"
 154           "\t adcw $0, %%bx\n"
 155           : "=b"(sum)
 156           : "0"(sum)
 157           : "bx", "cx");
 158 
 159   /* Check for an extra word. */
 160   if ((len & 2) != 0) {
 161         __asm__("\t lodsw\n"
 162                 "\t addw %%ax,%%bx\n"
 163                 "\t adcw $0, %%bx\n"
 164                 : "=b"(sum), "=S"(uh)
 165                 : "0"(sum) ,"1"(uh)
 166                 : "si", "ax", "bx");
 167   }
 168 
 169   /* Now check for the extra byte. */
 170   if ((len & 1) != 0) {
 171         __asm__("\t lodsb\n"
 172                 "\t movb $0,%%ah\n"
 173                 "\t addw %%ax,%%bx\n"
 174                 "\t adcw $0, %%bx\n"
 175                 : "=b"(sum)
 176                 : "0"(sum) ,"S"(uh)
 177                 : "si", "ax", "bx");
 178   }
 179 
 180   /* We only want the bottom 16 bits, but we never cleared the top 16. */
 181   return((~sum) & 0xffff);
 182 }
 183 
 184 
 185 static void
 186 udp_send_check(struct udphdr *uh, unsigned long saddr, 
     /* [previous][next][first][last][top][bottom][index][help] */
 187                unsigned long daddr, int len, struct sock *sk)
 188 {
 189   uh->check = 0;
 190   if (sk && sk->no_check) return;
 191   uh->check = udp_check(uh, len, saddr, daddr);
 192 }
 193 
 194 
 195 static int
 196 udp_send(struct sock *sk, struct sockaddr_in *sin,
     /* [previous][next][first][last][top][bottom][index][help] */
 197          unsigned char *from, int len)
 198 {
 199   struct sk_buff *skb;
 200   struct device *dev;
 201   struct udphdr *uh;
 202   unsigned char *buff;
 203   unsigned long saddr;
 204   int size, tmp;
 205   int err;
 206   
 207   DPRINTF((DBG_UDP, "UDP: send(dst=%s:%d buff=%X len=%d)\n",
 208                 in_ntoa(sin->sin_addr.s_addr), ntohs(sin->sin_port),
 209                 from, len));
 210 
 211   /* Allocate a copy of the packet. */
 212   size = sizeof(struct sk_buff) + sk->prot->max_header + len;
 213   skb = (struct sk_buff *) sk->prot->wmalloc(sk, size, 0, GFP_KERNEL);
 214   if (skb == NULL) return(-ENOMEM);
 215 
 216   skb->lock     = 0;
 217   skb->mem_addr = skb;
 218   skb->mem_len  = size;
 219   skb->sk       = NULL;
 220   skb->free     = 1;
 221   skb->arp      = 0;
 222 
 223   /* Now build the IP and MAC header. */
 224   buff = (unsigned char *) (skb+1);
 225   saddr = 0;
 226   dev = NULL;
 227   DPRINTF((DBG_UDP, "UDP: >> IP_Header: %X -> %X dev=%X prot=%X len=%d\n",
 228                         saddr, sin->sin_addr.s_addr, dev, IPPROTO_UDP, skb->mem_len));
 229   tmp = sk->prot->build_header(skb, saddr, sin->sin_addr.s_addr,
 230                                &dev, IPPROTO_UDP, sk->opt, skb->mem_len);
 231   if (tmp < 0 ) {
 232         sk->prot->wfree(sk, skb->mem_addr, skb->mem_len);
 233         return(tmp);
 234   }
 235   buff += tmp;
 236   saddr = dev->pa_addr;
 237   DPRINTF((DBG_UDP, "UDP: >> MAC+IP len=%d\n", tmp));
 238 
 239   skb->len = tmp + sizeof(struct udphdr) + len; /* len + UDP + IP + MAC */
 240   skb->dev = dev;
 241 
 242   /*
 243    * This code used to hack in some form of fragmentation.
 244    * I removed that, since it didn't work anyway, and it made the
 245    * code a bad thing to read and understand. -FvK
 246    */
 247   if (len > dev->mtu) {
 248         printk("UDP: send: length %d > mtu %d (ignored)\n", len, dev->mtu);
 249         sk->prot->wfree(sk, skb->mem_addr, skb->mem_len);
 250         return(-EINVAL);
 251   }
 252 
 253   /* Fill in the UDP header. */
 254   uh = (struct udphdr *) buff;
 255   uh->len = htons(len + sizeof(struct udphdr));
 256   uh->source = sk->dummy_th.source;
 257   uh->dest = sin->sin_port;
 258   buff = (unsigned char *) (uh + 1);
 259 
 260   /* Copy the user data. */
 261   err=verify_area(VERIFY_READ, from, len);
 262   if(err)
 263         return(err);
 264   memcpy_fromfs(buff, from, len);
 265 
 266   /* Set up the UDP checksum. */
 267   udp_send_check(uh, saddr, sin->sin_addr.s_addr, skb->len - tmp, sk);
 268 
 269   /* Send the datagram to the interface. */
 270   sk->prot->queue_xmit(sk, dev, skb, 1);
 271 
 272   return(len);
 273 }
 274 
 275 
 276 static int
 277 udp_sendto(struct sock *sk, unsigned char *from, int len, int noblock,
     /* [previous][next][first][last][top][bottom][index][help] */
 278            unsigned flags, struct sockaddr_in *usin, int addr_len)
 279 {
 280   struct sockaddr_in sin;
 281   int tmp;
 282   int err;
 283 
 284   DPRINTF((DBG_UDP, "UDP: sendto(len=%d, flags=%X)\n", len, flags));
 285 
 286   /* Check the flags. */
 287   if (flags) return(-EINVAL);
 288   if (len < 0) return(-EINVAL);
 289   if (len == 0) return(0);
 290 
 291   /* Get and verify the address. */
 292   if (usin) {
 293         if (addr_len < sizeof(sin)) return(-EINVAL);
 294         err=verify_area(VERIFY_READ, usin, sizeof(sin));
 295         if(err)
 296                 return err;
 297         memcpy_fromfs(&sin, usin, sizeof(sin));
 298         if (sin.sin_family && sin.sin_family != AF_INET) return(-EINVAL);
 299         if (sin.sin_port == 0) return(-EINVAL);
 300   } else {
 301         if (sk->state != TCP_ESTABLISHED) return(-EINVAL);
 302         sin.sin_family = AF_INET;
 303         sin.sin_port = sk->dummy_th.dest;
 304         sin.sin_addr.s_addr = sk->daddr;
 305   }
 306   sk->inuse = 1;
 307 
 308   /* Send the packet. */
 309   tmp = udp_send(sk, &sin, from, len);
 310 
 311   /* The datagram has been sent off.  Release the socket. */
 312   release_sock(sk);
 313   return(tmp);
 314 }
 315 
 316 
 317 static int
 318 udp_write(struct sock *sk, unsigned char *buff, int len, int noblock,
     /* [previous][next][first][last][top][bottom][index][help] */
 319           unsigned flags)
 320 {
 321   return(udp_sendto(sk, buff, len, noblock, flags, NULL, 0));
 322 }
 323 
 324 
 325 int
 326 udp_ioctl(struct sock *sk, int cmd, unsigned long arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 327 {
 328   int err;
 329   switch(cmd) {
 330         case DDIOCSDBG:
 331                 {
 332                         int val;
 333 
 334                         if (!suser()) return(-EPERM);
 335                         err=verify_area(VERIFY_READ, (void *)arg, sizeof(int));
 336                         if(err)
 337                                 return err;
 338                         val = get_fs_long((int *)arg);
 339                         switch(val) {
 340                                 case 0:
 341                                         inet_debug = 0;
 342                                         break;
 343                                 case 1:
 344                                         inet_debug = DBG_UDP;
 345                                         break;
 346                                 default:
 347                                         return(-EINVAL);
 348                         }
 349                 }
 350                 break;
 351         case TIOCOUTQ:
 352                 {
 353                         unsigned long amount;
 354 
 355                         if (sk->state == TCP_LISTEN) return(-EINVAL);
 356                         amount = sk->prot->wspace(sk)/2;
 357                         err=verify_area(VERIFY_WRITE,(void *)arg,
 358                                         sizeof(unsigned long));
 359                         if(err)
 360                                 return(err);
 361                         put_fs_long(amount,(unsigned long *)arg);
 362                         return(0);
 363                 }
 364 
 365         case TIOCINQ:
 366 #if 0   /* FIXME: */
 367         case FIONREAD:
 368 #endif
 369                 {
 370                         struct sk_buff *skb;
 371                         unsigned long amount;
 372 
 373                         if (sk->state == TCP_LISTEN) return(-EINVAL);
 374                         amount = 0;
 375                         skb = sk->rqueue;
 376                         if (skb != NULL) {
 377                                 /*
 378                                  * We will only return the amount
 379                                  * of this packet since that is all
 380                                  * that will be read.
 381                                  */
 382                                 amount = skb->len;
 383                         }
 384                         err=verify_area(VERIFY_WRITE,(void *)arg,
 385                                                 sizeof(unsigned long));
 386                         if(err)
 387                                 return(err);
 388                         put_fs_long(amount,(unsigned long *)arg);
 389                         return(0);
 390                 }
 391 
 392         default:
 393                 return(-EINVAL);
 394   }
 395   return(0);
 396 }
 397 
 398 
 399 /*
 400  * This should be easy, if there is something there we\
 401  * return it, otherwise we block.
 402  */
 403 int
 404 udp_recvfrom(struct sock *sk, unsigned char *to, int len,
     /* [previous][next][first][last][top][bottom][index][help] */
 405              int noblock, unsigned flags, struct sockaddr_in *sin,
 406              int *addr_len)
 407 {
 408   int copied = 0;
 409   struct sk_buff *skb;
 410   int er;
 411 
 412   if (len == 0) return(0);
 413   if (len < 0) return(-EINVAL);
 414 
 415   /*
 416    * This will pick up errors that occured while the program
 417    * was doing something else.
 418    */
 419   if (sk->err) {
 420         int err;
 421 
 422         err = -sk->err;
 423         sk->err = 0;
 424         return(err);
 425   }
 426   if (addr_len) {
 427         er=verify_area(VERIFY_WRITE, addr_len, sizeof(*addr_len));
 428         if(er)
 429                 return(er);
 430         put_fs_long(sizeof(*sin), addr_len);
 431   }
 432   if(sin)
 433   {
 434         er=verify_area(VERIFY_WRITE, sin, sizeof(*sin));
 435         if(er)
 436                 return(er);
 437   }
 438   er=verify_area(VERIFY_WRITE,to,len);
 439   if(er)
 440         return er;
 441   sk->inuse = 1;
 442   while(sk->rqueue == NULL) {
 443         if (sk->shutdown & RCV_SHUTDOWN) {
 444                 return(0);
 445         }
 446 
 447         if (noblock) {
 448                 release_sock(sk);
 449                 return(-EAGAIN);
 450         }
 451         release_sock(sk);
 452         cli();
 453         if (sk->rqueue == NULL) {
 454                 interruptible_sleep_on(sk->sleep);
 455                 if (current->signal & ~current->blocked) {
 456                         return(-ERESTARTSYS);
 457                 }
 458         }
 459         sk->inuse = 1;
 460         sti();
 461   }
 462   skb = sk->rqueue;
 463 
 464   if (!(flags & MSG_PEEK)) {
 465         if (skb->next == skb) {
 466                 sk->rqueue = NULL;
 467         } else {
 468                 sk->rqueue =(struct sk_buff *)sk->rqueue ->next;
 469                 skb->prev->next = skb->next;
 470                 skb->next->prev = skb->prev;
 471         }
 472   }
 473   copied = min(len, skb->len);
 474   /* This was checked in the wrong place
 475   verify_area(VERIFY_WRITE, to, copied);
 476   */
 477   memcpy_tofs(to, skb->h.raw + sizeof(struct udphdr), copied);
 478 
 479   /* Copy the address. */
 480   if (sin) {
 481         struct sockaddr_in addr;
 482 
 483         addr.sin_family = AF_INET;
 484         addr.sin_port = skb->h.uh->source;
 485         addr.sin_addr.s_addr = skb->daddr;
 486         /* Also in the wrong place, jumping out here will lose
 487            a packet for good and leave the socket in use
 488            now tested above
 489         verify_area(VERIFY_WRITE, sin, sizeof(*sin));*/
 490         memcpy_tofs(sin, &addr, sizeof(*sin));
 491   }
 492 
 493   if (!(flags & MSG_PEEK)) {
 494         kfree_skb(skb, FREE_READ);
 495   }
 496   release_sock(sk);
 497   return(copied);
 498 }
 499 
 500 
 501 int
 502 udp_read(struct sock *sk, unsigned char *buff, int len, int noblock,
     /* [previous][next][first][last][top][bottom][index][help] */
 503          unsigned flags)
 504 {
 505   return(udp_recvfrom(sk, buff, len, noblock, flags, NULL, NULL));
 506 }
 507 
 508 
 509 int
 510 udp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
     /* [previous][next][first][last][top][bottom][index][help] */
 511 {
 512   struct sockaddr_in sin;
 513   int er;
 514   
 515   if (addr_len < sizeof(sin)) return(-EINVAL);
 516 
 517   er=verify_area(VERIFY_READ, usin, sizeof(sin));
 518   if(er)
 519         return er;
 520 
 521   memcpy_fromfs(&sin, usin, sizeof(sin));
 522   if (sin.sin_family && sin.sin_family != AF_INET) return(-EAFNOSUPPORT);
 523   sk->daddr = sin.sin_addr.s_addr;
 524   sk->dummy_th.dest = sin.sin_port;
 525   sk->state = TCP_ESTABLISHED;
 526   return(0);
 527 }
 528 
 529 
 530 static void
 531 udp_close(struct sock *sk, int timeout)
     /* [previous][next][first][last][top][bottom][index][help] */
 532 {
 533   sk->inuse = 1;
 534   sk->state = TCP_CLOSE;
 535   if (sk->dead) destroy_sock(sk);
 536     else release_sock(sk);
 537 }
 538 
 539 
 540 /* All we need to do is get the socket, and then do a checksum. */
 541 int
 542 udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
     /* [previous][next][first][last][top][bottom][index][help] */
 543         unsigned long daddr, unsigned short len,
 544         unsigned long saddr, int redo, struct inet_protocol *protocol)
 545 {
 546   struct sock *sk;
 547   struct udphdr *uh;
 548 
 549   uh = (struct udphdr *) skb->h.uh;
 550   sk = get_sock(&udp_prot, uh->dest, saddr, uh->source, daddr);
 551   if (sk == NULL) {
 552         if (chk_addr(daddr) == IS_MYADDR) 
 553                 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, dev);
 554 
 555         /*
 556          * Hmm.  We got an UDP broadcast to a port to which we
 557          * don't wanna listen.  The only thing we can do now is
 558          * to ignore the packet... -FvK
 559          */
 560         skb->sk = NULL;
 561         kfree_skb(skb, FREE_WRITE);
 562         return(0);
 563   }
 564 
 565   if (!redo) {
 566         if (uh->check && udp_check(uh, len, saddr, daddr)) {
 567                 DPRINTF((DBG_UDP, "UDP: bad checksum\n"));
 568                 skb->sk = NULL;
 569                 kfree_skb(skb, FREE_WRITE);
 570                 return(0);
 571         }
 572 
 573         skb->sk = sk;
 574         skb->dev = dev;
 575         skb->len = len;
 576 
 577         /* These are supposed to be switched. */
 578         skb->daddr = saddr;
 579         skb->saddr = daddr;
 580 
 581         /* Now deal with the in use. */
 582         cli();
 583         if (sk->inuse) {
 584                 if (sk->back_log == NULL) {
 585                         sk->back_log = skb;
 586                         skb->next = skb;
 587                         skb->prev = skb;
 588                 } else {
 589                         skb->next = sk->back_log;
 590                         skb->prev = sk->back_log->prev;
 591                         skb->prev->next = skb;
 592                         skb->next->prev = skb;
 593                 }
 594                 sti();
 595                 return(0);
 596         }
 597         sk->inuse = 1;
 598         sti();
 599   }
 600 
 601   /* Charge it to the socket. */
 602   if (sk->rmem_alloc + skb->mem_len >= SK_RMEM_MAX) {
 603         skb->sk = NULL;
 604         kfree_skb(skb, FREE_WRITE);
 605         release_sock(sk);
 606         return(0);
 607   }
 608   sk->rmem_alloc += skb->mem_len;
 609 
 610   /* At this point we should print the thing out. */
 611   DPRINTF((DBG_UDP, "<< \n"));
 612   print_udp(uh);
 613 
 614   /* Now add it to the data chain and wake things up. */
 615   if (sk->rqueue == NULL) {
 616         sk->rqueue = skb;
 617         skb->next = skb;
 618         skb->prev = skb;
 619   } else {
 620         skb->next = sk->rqueue;
 621         skb->prev = sk->rqueue->prev;
 622         skb->prev->next = skb;
 623         skb->next->prev = skb;
 624   }
 625   skb->len = len - sizeof(*uh);
 626 
 627   if (!sk->dead) wake_up(sk->sleep);
 628 
 629   release_sock(sk);
 630   return(0);
 631 }
 632 
 633 
 634 struct proto udp_prot = {
 635   sock_wmalloc,
 636   sock_rmalloc,
 637   sock_wfree,
 638   sock_rfree,
 639   sock_rspace,
 640   sock_wspace,
 641   udp_close,
 642   udp_read,
 643   udp_write,
 644   udp_sendto,
 645   udp_recvfrom,
 646   ip_build_header,
 647   udp_connect,
 648   NULL,
 649   ip_queue_xmit,
 650   ip_retransmit,
 651   NULL,
 652   NULL,
 653   udp_rcv,
 654   udp_select,
 655   udp_ioctl,
 656   NULL,
 657   NULL,
 658   128,
 659   0,
 660   {NULL,},
 661   "UDP"
 662 };

/* [previous][next][first][last][top][bottom][index][help] */