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_err
  3. udp_check
  4. udp_send_check
  5. udp_send
  6. udp_sendto
  7. udp_write
  8. udp_ioctl
  9. udp_recvfrom
  10. udp_read
  11. udp_connect
  12. udp_close
  13. 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  * Fixes:
  14  *              Alan Cox        :       verify_area() calls
  15  *              Alan Cox        :       stopped close while in use off icmp
  16  *                                      messages. Not a fix but a botch that
  17  *                                      for udp at least is 'valid'.
  18  *              Alan Cox        :       Fixed icmp handling properly
  19  *              Alan Cox        :       Correct error for oversized datagrams
  20  *              Alan Cox        :       Tidied select() semantics. 
  21  *              Alan Cox        :       udp_err() fixed properly, also now 
  22  *                                      select and read wake correctly on errors
  23  *              Alan Cox        :       udp_send verify_area moved to avoid mem leak
  24  *              Alan Cox        :       UDP can count its memory
  25  *              Alan Cox        :       send to an uknown connection causes
  26  *                                      an ECONNREFUSED off the icmp, but
  27  *                                      does NOT close.
  28  *              Alan Cox        :       Switched to new sk_buff handlers. No more backlog!
  29  *              Alan Cox        :       Using generic datagram code. Even smaller and the PEEK
  30  *                                      bug no longer crashes it.
  31  *              Fred Van Kempen :       Net2e support for sk->broadcast.
  32  *              Alan Cox        :       Uses skb_free_datagram
  33  *
  34  * To Do:
  35  *              Verify all the error codes from UDP operations match the
  36  *              BSD behaviour, since thats effectively the formal spec.
  37  *
  38  *              This program is free software; you can redistribute it and/or
  39  *              modify it under the terms of the GNU General Public License
  40  *              as published by the Free Software Foundation; either version
  41  *              2 of the License, or (at your option) any later version.
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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  * This routine is called by the ICMP module when it gets some
  86  * sort of error condition.  If err < 0 then the socket should
  87  * be closed and the error returned to the user.  If err > 0
  88  * it's just the icmp type << 8 | icmp code.  
  89  * Header points to the ip header of the error packet. We move
  90  * on past this. Then (as it used to claim before adjustment)
  91  * header points to the first 8 bytes of the udp header.  We need
  92  * to find the appropriate port.
  93  */
  94 void
  95 udp_err(int err, unsigned char *header, unsigned long daddr,
     /* [previous][next][first][last][top][bottom][index][help] */
  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; /* No socket for error */
 113         
 114   if (err < 0)          /* As per the calling spec */
 115   {
 116         sk->err = -err;
 117         wake_up(sk->sleep);     /* User process wakes to see error */
 118         return;
 119   }
 120   
 121   if (err & 0xff00 ==(ICMP_SOURCE_QUENCH << 8)) {       /* Slow down! */
 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   /* It's only fatal if we have connected to them. */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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   /* Convert from 32 bits to 16 bits. */
 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   /* Check for an extra word. */
 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   /* Now check for the extra byte. */
 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   /* We only want the bottom 16 bits, but we never cleared the top 16. */
 198   return((~sum) & 0xffff);
 199 }
 200 
 201 
 202 static void
 203 udp_send_check(struct udphdr *uh, unsigned long saddr, 
     /* [previous][next][first][last][top][bottom][index][help] */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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   /* Allocate a copy of the packet. */
 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; /* to avoid changing sk->saddr */
 242   skb->free     = 1;
 243   skb->arp      = 0;
 244 
 245   /* Now build the IP and MAC header. */
 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;   /* So memory is freed correctly */
 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; /* len + UDP + IP + MAC */
 264   skb->dev = dev;
 265 #ifdef OLD
 266   /*
 267    * This code used to hack in some form of fragmentation.
 268    * I removed that, since it didn't work anyway, and it made the
 269    * code a bad thing to read and understand. -FvK
 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   /* Fill in the UDP header. */
 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   /* Copy the user data. */
 289   memcpy_fromfs(buff, from, len);
 290 
 291   /* Set up the UDP checksum. */
 292   udp_send_check(uh, saddr, sin->sin_addr.s_addr, skb->len - tmp, sk);
 293 
 294   /* Send the datagram to the interface. */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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   /* Check the flags. */
 312   if (flags) 
 313         return(-EINVAL);
 314   if (len < 0) 
 315         return(-EINVAL);
 316   if (len == 0) 
 317         return(0);
 318 
 319   /* Get and verify the address. */
 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;            /* Must turn broadcast on first */
 339   sk->inuse = 1;
 340 
 341   /* Send the packet. */
 342   tmp = udp_send(sk, &sin, from, len);
 343 
 344   /* The datagram has been sent off.  Release the socket. */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)/*/2*/;
 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                                  * We will only return the amount
 409                                  * of this packet since that is all
 410                                  * that will be read.
 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  * This should be easy, if there is something there we\
 431  * return it, otherwise we block.
 432  */
 433 int
 434 udp_recvfrom(struct sock *sk, unsigned char *to, int len,
     /* [previous][next][first][last][top][bottom][index][help] */
 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    * This will pick up errors that occured while the program
 445    * was doing something else.
 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   /* FIXME : should use udp header size info value */
 481   skb_copy_datagram(skb,sizeof(struct udphdr),to,copied);
 482 
 483   /* Copy the address. */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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;            /* Must turn broadcast on first */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 /* All we need to do is get the socket, and then do a checksum. */
 545 int
 546 udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
     /* [previous][next][first][last][top][bottom][index][help] */
 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          * Hmm.  We got an UDP broadcast to a port to which we
 563          * don't wanna listen.  The only thing we can do now is
 564          * to ignore the packet... -FvK
 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 /* These are supposed to be switched. */
 583   skb->daddr = saddr;
 584   skb->saddr = daddr;
 585 
 586 
 587   /* Charge it to the socket. */
 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   /* At this point we should print the thing out. */
 598   DPRINTF((DBG_UDP, "<< \n"));
 599   print_udp(uh);
 600 
 601   /* Now add it to the data chain and wake things up. */
 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 };

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