root/net/inet/udp.c

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

DEFINITIONS

This source file includes following definitions.
  1. udp_err
  2. udp_check
  3. udp_send_check
  4. udp_send
  5. udp_sendto
  6. udp_write
  7. udp_ioctl
  8. udp_recvfrom
  9. udp_read
  10. udp_connect
  11. udp_close
  12. 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  *              Alan Cox        :       Added get/set sockopt support.
  34  *              Alan Cox        :       Broadcasting without option set returns EACCES.
  35  *              Alan Cox        :       No wakeup calls. Instead we now use the callbacks.
  36  *              Alan Cox        :       Use ip_tos and ip_ttl
  37  *              Alan Cox        :       SNMP Mibs
  38  *              Alan Cox        :       MSG_DONTROUTE, and 0.0.0.0 support.
  39  *              Matt Dillon     :       UDP length checks.
  40  *              Alan Cox        :       Smarter af_inet used properly.
  41  *
  42  *
  43  *              This program is free software; you can redistribute it and/or
  44  *              modify it under the terms of the GNU General Public License
  45  *              as published by the Free Software Foundation; either version
  46  *              2 of the License, or (at your option) any later version.
  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  *      SNMP MIB for the UDP layer
  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  * 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 
  95 void 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         /*
 105          *      Find the 8 bytes of post IP header ICMP included for usA
 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; /* No socket for error */
 113         
 114         if (err & 0xff00 ==(ICMP_SOURCE_QUENCH << 8)) 
 115         {       /* Slow down! */
 116                 if (sk->cong_window > 1) 
 117                         sk->cong_window = sk->cong_window/2;
 118                 return;
 119         }
 120 
 121         /*
 122          *      Various people wanted BSD UDP semantics. Well they've come 
 123          *      back out because they slow down response to stuff like dead
 124          *      or unreachable name servers and they screw term users something
 125          *      chronic. Oh and it violates RFC1122. So basically fix your 
 126          *      client code people.
 127          */
 128          
 129 #ifdef CONFIG_I_AM_A_BROKEN_BSD_WEENIE
 130         /*
 131          *      It's only fatal if we have connected to them. I'm not happy
 132          *      with this code. Some BSD comparisons need doing.
 133          */
 134          
 135         if (icmp_err_convert[err & 0xff].fatal && sk->state == TCP_ESTABLISHED) 
 136         {
 137                 sk->err = icmp_err_convert[err & 0xff].errno;
 138                 sk->error_report(sk);
 139         }
 140 #else
 141         if (icmp_err_convert[err & 0xff].fatal)
 142         {
 143                 sk->err = icmp_err_convert[err & 0xff].errno;
 144                 sk->error_report(sk);
 145         }
 146 #endif
 147 }
 148 
 149 
 150 static unsigned short udp_check(struct udphdr *uh, int len, unsigned long saddr, unsigned long daddr)
     /* [previous][next][first][last][top][bottom][index][help] */
 151 {
 152         unsigned long sum;
 153 
 154         __asm__(  "\t addl %%ecx,%%ebx\n"
 155                   "\t adcl %%edx,%%ebx\n"
 156                   "\t adcl $0, %%ebx\n"
 157                   : "=b"(sum)
 158                   : "0"(daddr), "c"(saddr), "d"((ntohs(len) << 16) + IPPROTO_UDP*256)
 159                   : "cx","bx","dx" );
 160 
 161         if (len > 3) 
 162         {
 163                 __asm__("\tclc\n"
 164                         "1:\n"
 165                         "\t lodsl\n"
 166                         "\t adcl %%eax, %%ebx\n"
 167                         "\t loop 1b\n"
 168                         "\t adcl $0, %%ebx\n"
 169                         : "=b"(sum) , "=S"(uh)
 170                         : "0"(sum), "c"(len/4) ,"1"(uh)
 171                         : "ax", "cx", "bx", "si" );
 172         }
 173 
 174         /*
 175          *      Convert from 32 bits to 16 bits. 
 176          */
 177 
 178         __asm__("\t movl %%ebx, %%ecx\n"
 179                 "\t shrl $16,%%ecx\n"
 180                 "\t addw %%cx, %%bx\n"
 181                 "\t adcw $0, %%bx\n"
 182                 : "=b"(sum)
 183                 : "0"(sum)
 184                 : "bx", "cx");
 185         
 186         /* 
 187          *      Check for an extra word. 
 188          */
 189          
 190         if ((len & 2) != 0) 
 191         {
 192                 __asm__("\t lodsw\n"
 193                         "\t addw %%ax,%%bx\n"
 194                         "\t adcw $0, %%bx\n"
 195                         : "=b"(sum), "=S"(uh)
 196                         : "0"(sum) ,"1"(uh)
 197                         : "si", "ax", "bx");
 198         }
 199 
 200         /*
 201          *      Now check for the extra byte. 
 202          */
 203          
 204         if ((len & 1) != 0) 
 205         {
 206                 __asm__("\t lodsb\n"
 207                         "\t movb $0,%%ah\n"
 208                         "\t addw %%ax,%%bx\n"
 209                         "\t adcw $0, %%bx\n"
 210                         : "=b"(sum)
 211                         : "0"(sum) ,"S"(uh)
 212                         : "si", "ax", "bx");
 213         }
 214 
 215         /* 
 216          *      We only want the bottom 16 bits, but we never cleared the top 16. 
 217          */
 218 
 219         return((~sum) & 0xffff);
 220 }
 221 
 222 /*
 223  *      Generate UDP checksums. These may be disabled, eg for fast NFS over ethernet
 224  *      We default them enabled.. if you turn them off you either know what you are
 225  *      doing or get burned...
 226  */
 227 
 228 static void udp_send_check(struct udphdr *uh, unsigned long saddr, 
     /* [previous][next][first][last][top][bottom][index][help] */
 229                unsigned long daddr, int len, struct sock *sk)
 230 {
 231         uh->check = 0;
 232         if (sk && sk->no_check) 
 233                 return;
 234         uh->check = udp_check(uh, len, saddr, daddr);
 235         
 236         /*
 237          *      FFFF and 0 are the same, pick the right one as 0 in the
 238          *      actual field means no checksum.
 239          */
 240          
 241         if (uh->check == 0)
 242                 uh->check = 0xffff;
 243 }
 244 
 245 
 246 static int udp_send(struct sock *sk, struct sockaddr_in *sin,
     /* [previous][next][first][last][top][bottom][index][help] */
 247          unsigned char *from, int len, int rt)
 248 {
 249         struct sk_buff *skb;
 250         struct device *dev;
 251         struct udphdr *uh;
 252         unsigned char *buff;
 253         unsigned long saddr;
 254         int size, tmp;
 255   
 256         /* 
 257          *      Allocate an sk_buff copy of the packet.
 258          */
 259          
 260         size = sk->prot->max_header + len;
 261         skb = sk->prot->wmalloc(sk, size, 0, GFP_KERNEL);
 262 
 263 
 264         if (skb == NULL) 
 265                 return(-ENOBUFS);
 266 
 267         skb->sk       = NULL;   /* to avoid changing sk->saddr */
 268         skb->free     = 1;
 269         skb->localroute = sk->localroute|(rt&MSG_DONTROUTE);
 270 
 271         /*
 272          *      Now build the IP and MAC header. 
 273          */
 274          
 275         buff = skb->data;
 276         saddr = 0;
 277         dev = NULL;
 278         tmp = sk->prot->build_header(skb, saddr, sin->sin_addr.s_addr,
 279                         &dev, IPPROTO_UDP, sk->opt, skb->mem_len,sk->ip_tos,sk->ip_ttl);
 280         skb->sk=sk;     /* So memory is freed correctly */
 281         
 282         /*
 283          *      Unable to put a header on the packet.
 284          */
 285                             
 286         if (tmp < 0 ) 
 287         {
 288                 sk->prot->wfree(sk, skb->mem_addr, skb->mem_len);
 289                 return(tmp);
 290         }
 291         
 292         buff += tmp;
 293         saddr = skb->saddr; /*dev->pa_addr;*/
 294         skb->len = tmp + sizeof(struct udphdr) + len;   /* len + UDP + IP + MAC */
 295         skb->dev = dev;
 296         
 297         /*
 298          *      Fill in the UDP header. 
 299          */
 300          
 301         uh = (struct udphdr *) buff;
 302         uh->len = htons(len + sizeof(struct udphdr));
 303         uh->source = sk->dummy_th.source;
 304         uh->dest = sin->sin_port;
 305         buff = (unsigned char *) (uh + 1);
 306 
 307         /*
 308          *      Copy the user data. 
 309          */
 310          
 311         memcpy_fromfs(buff, from, len);
 312 
 313         /*
 314          *      Set up the UDP checksum. 
 315          */
 316          
 317         udp_send_check(uh, saddr, sin->sin_addr.s_addr, skb->len - tmp, sk);
 318 
 319         /* 
 320          *      Send the datagram to the interface. 
 321          */
 322          
 323         udp_statistics.UdpOutDatagrams++;
 324          
 325         sk->prot->queue_xmit(sk, dev, skb, 1);
 326         return(len);
 327 }
 328 
 329 
 330 static int udp_sendto(struct sock *sk, unsigned char *from, int len, int noblock,
     /* [previous][next][first][last][top][bottom][index][help] */
 331            unsigned flags, struct sockaddr_in *usin, int addr_len)
 332 {
 333         struct sockaddr_in sin;
 334         int tmp;
 335         int err;
 336 
 337         /* 
 338          *      Check the flags. We support no flags for UDP sending
 339          */
 340         if (flags&~MSG_DONTROUTE) 
 341                 return(-EINVAL);
 342         /*
 343          *      Get and verify the address. 
 344          */
 345          
 346         if (usin) 
 347         {
 348                 if (addr_len < sizeof(sin)) 
 349                         return(-EINVAL);
 350                 err=verify_area(VERIFY_READ, usin, sizeof(sin));
 351                 if(err)
 352                         return err;
 353                 memcpy_fromfs(&sin, usin, sizeof(sin));
 354                 if (sin.sin_family && sin.sin_family != AF_INET) 
 355                         return(-EINVAL);
 356                 if (sin.sin_port == 0) 
 357                         return(-EINVAL);
 358         } 
 359         else 
 360         {
 361                 if (sk->state != TCP_ESTABLISHED) 
 362                         return(-EINVAL);
 363                 sin.sin_family = AF_INET;
 364                 sin.sin_port = sk->dummy_th.dest;
 365                 sin.sin_addr.s_addr = sk->daddr;
 366         }
 367   
 368         /*
 369          *      BSD socket semantics. You must set SO_BROADCAST to permit
 370          *      broadcasting of data.
 371          */
 372          
 373         if(sin.sin_addr.s_addr==INADDR_ANY)
 374                 sin.sin_addr.s_addr=ip_my_addr();
 375                 
 376         if(!sk->broadcast && ip_chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
 377                 return -EACCES;                 /* Must turn broadcast on first */
 378 
 379         sk->inuse = 1;
 380 
 381         /* Send the packet. */
 382         tmp = udp_send(sk, &sin, from, len, flags);
 383 
 384         /* The datagram has been sent off.  Release the socket. */
 385         release_sock(sk);
 386         return(tmp);
 387 }
 388 
 389 /*
 390  *      In BSD SOCK_DGRAM a write is just like a send.
 391  */
 392 
 393 static int udp_write(struct sock *sk, unsigned char *buff, int len, int noblock,
     /* [previous][next][first][last][top][bottom][index][help] */
 394           unsigned flags)
 395 {
 396         return(udp_sendto(sk, buff, len, noblock, flags, NULL, 0));
 397 }
 398 
 399 
 400 /*
 401  *      IOCTL requests applicable to the UDP protocol
 402  */
 403  
 404 int udp_ioctl(struct sock *sk, int cmd, unsigned long arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 405 {
 406         int err;
 407         switch(cmd) 
 408         {
 409                 case TIOCOUTQ:
 410                 {
 411                         unsigned long amount;
 412 
 413                         if (sk->state == TCP_LISTEN) return(-EINVAL);
 414                         amount = sk->prot->wspace(sk)/*/2*/;
 415                         err=verify_area(VERIFY_WRITE,(void *)arg,
 416                                         sizeof(unsigned long));
 417                         if(err)
 418                                 return(err);
 419                         put_fs_long(amount,(unsigned long *)arg);
 420                         return(0);
 421                 }
 422 
 423                 case TIOCINQ:
 424                 {
 425                         struct sk_buff *skb;
 426                         unsigned long amount;
 427 
 428                         if (sk->state == TCP_LISTEN) return(-EINVAL);
 429                         amount = 0;
 430                         skb = skb_peek(&sk->receive_queue);
 431                         if (skb != NULL) {
 432                                 /*
 433                                  * We will only return the amount
 434                                  * of this packet since that is all
 435                                  * that will be read.
 436                                  */
 437                                 amount = skb->len;
 438                         }
 439                         err=verify_area(VERIFY_WRITE,(void *)arg,
 440                                                 sizeof(unsigned long));
 441                         if(err)
 442                                 return(err);
 443                         put_fs_long(amount,(unsigned long *)arg);
 444                         return(0);
 445                 }
 446 
 447                 default:
 448                         return(-EINVAL);
 449         }
 450         return(0);
 451 }
 452 
 453 
 454 /*
 455  *      This should be easy, if there is something there we\
 456  *      return it, otherwise we block.
 457  */
 458 
 459 int udp_recvfrom(struct sock *sk, unsigned char *to, int len,
     /* [previous][next][first][last][top][bottom][index][help] */
 460              int noblock, unsigned flags, struct sockaddr_in *sin,
 461              int *addr_len)
 462 {
 463         int copied = 0;
 464         struct sk_buff *skb;
 465         int er;
 466 
 467         /*
 468          *      Check any passed addresses
 469          */
 470          
 471         if (addr_len) 
 472         {
 473                 er=verify_area(VERIFY_WRITE, addr_len, sizeof(*addr_len));
 474                 if(er)
 475                         return(er);
 476                 put_fs_long(sizeof(*sin), addr_len);
 477         }
 478   
 479         if(sin)
 480         {
 481                 er=verify_area(VERIFY_WRITE, sin, sizeof(*sin));
 482                 if(er)
 483                         return(er);
 484         }
 485         
 486         /*
 487          *      From here the generic datagram does a lot of the work. Come
 488          *      the finished NET3, it will do _ALL_ the work!
 489          */
 490                 
 491         skb=skb_recv_datagram(sk,flags,noblock,&er);
 492         if(skb==NULL)
 493                 return er;
 494   
 495         copied = min(len, skb->len);
 496 
 497         /*
 498          *      FIXME : should use udp header size info value 
 499          */
 500          
 501         skb_copy_datagram(skb,sizeof(struct udphdr),to,copied);
 502         sk->stamp=skb->stamp;
 503 
 504         /* Copy the address. */
 505         if (sin) 
 506         {
 507                 struct sockaddr_in addr;
 508 
 509                 addr.sin_family = AF_INET;
 510                 addr.sin_port = skb->h.uh->source;
 511                 addr.sin_addr.s_addr = skb->daddr;
 512                 memcpy_tofs(sin, &addr, sizeof(*sin));
 513         }
 514   
 515         skb_free_datagram(skb);
 516         release_sock(sk);
 517         return(copied);
 518 }
 519 
 520 /*
 521  *      Read has the same semantics as recv in SOCK_DGRAM
 522  */
 523 
 524 int udp_read(struct sock *sk, unsigned char *buff, int len, int noblock,
     /* [previous][next][first][last][top][bottom][index][help] */
 525          unsigned flags)
 526 {
 527         return(udp_recvfrom(sk, buff, len, noblock, flags, NULL, NULL));
 528 }
 529 
 530 
 531 int
 532 udp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
     /* [previous][next][first][last][top][bottom][index][help] */
 533 {
 534         struct sockaddr_in sin;
 535         int er;
 536   
 537         if (addr_len < sizeof(sin)) 
 538                 return(-EINVAL);
 539 
 540         er=verify_area(VERIFY_READ, usin, sizeof(sin));
 541         if(er)
 542                 return er;
 543 
 544         memcpy_fromfs(&sin, usin, sizeof(sin));
 545         if (sin.sin_family && sin.sin_family != AF_INET) 
 546                 return(-EAFNOSUPPORT);
 547         if (sin.sin_addr.s_addr==INADDR_ANY)
 548                 sin.sin_addr.s_addr=ip_my_addr();
 549 
 550         if(!sk->broadcast && ip_chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
 551                 return -EACCES;                 /* Must turn broadcast on first */
 552         
 553         sk->daddr = sin.sin_addr.s_addr;
 554         sk->dummy_th.dest = sin.sin_port;
 555         sk->state = TCP_ESTABLISHED;
 556         return(0);
 557 }
 558 
 559 
 560 static void
 561 udp_close(struct sock *sk, int timeout)
     /* [previous][next][first][last][top][bottom][index][help] */
 562 {
 563   sk->inuse = 1;
 564   sk->state = TCP_CLOSE;
 565   if (sk->dead) destroy_sock(sk);
 566     else release_sock(sk);
 567 }
 568 
 569 
 570 /*
 571  *      All we need to do is get the socket, and then do a checksum. 
 572  */
 573  
 574 int udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
     /* [previous][next][first][last][top][bottom][index][help] */
 575         unsigned long daddr, unsigned short len,
 576         unsigned long saddr, int redo, struct inet_protocol *protocol)
 577 {
 578         struct sock *sk;
 579         struct udphdr *uh;
 580         unsigned short ulen;
 581                 
 582         /*
 583          *      Get the header.
 584          */
 585         uh = (struct udphdr *) skb->h.uh;
 586         
 587         ip_statistics.IpInDelivers++;
 588 
 589         /*
 590          *      Validate the packet and the UDP length.
 591          */
 592          
 593         ulen = ntohs(uh->len);
 594 
 595         if (ulen > len || len < sizeof(*uh) || ulen < sizeof(*uh)) 
 596         {
 597                 printk("UDP: short packet: %d/%d\n", ulen, len);
 598                 udp_statistics.UdpInErrors++;
 599                 kfree_skb(skb, FREE_WRITE);
 600                 return(0);
 601         }
 602         len=ulen;
 603 
 604         sk = get_sock(&udp_prot, uh->dest, saddr, uh->source, daddr);
 605         if (sk == NULL) 
 606         {
 607                 udp_statistics.UdpNoPorts++;
 608                 if (ip_chk_addr(daddr) == IS_MYADDR) 
 609                 {
 610                         icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, dev);
 611                 }
 612                 /*
 613                  * Hmm.  We got an UDP broadcast to a port to which we
 614                  * don't wanna listen.  Ignore it.
 615                  */
 616                 skb->sk = NULL;
 617                 kfree_skb(skb, FREE_WRITE);
 618                 return(0);
 619         }
 620 
 621         if (uh->check && udp_check(uh, len, saddr, daddr)) 
 622         {
 623                 printk("UDP: bad checksum.\n");
 624                 udp_statistics.UdpInErrors++;
 625                 kfree_skb(skb, FREE_WRITE);
 626                 return(0);
 627         }
 628 
 629         skb->sk = sk;
 630         skb->dev = dev;
 631         skb->len = len;
 632 
 633         /*
 634          *      These are supposed to be switched. 
 635          */
 636          
 637         skb->daddr = saddr;
 638         skb->saddr = daddr;
 639 
 640 
 641         /*
 642          *      Charge it to the socket, dropping if the queue is full.
 643          */
 644          
 645         if (sk->rmem_alloc + skb->mem_len >= sk->rcvbuf) 
 646         {
 647                 udp_statistics.UdpInErrors++;
 648                 ip_statistics.IpInDiscards++;
 649                 ip_statistics.IpInDelivers--;
 650                 skb->sk = NULL;
 651                 kfree_skb(skb, FREE_WRITE);
 652                 release_sock(sk);
 653                 return(0);
 654         }
 655         sk->rmem_alloc += skb->mem_len;
 656         udp_statistics.UdpInDatagrams++;
 657 
 658         /*
 659          *      Now add it to the data chain and wake things up. 
 660          */
 661   
 662         skb->len = len - sizeof(*uh);  
 663         skb_queue_tail(&sk->receive_queue,skb);
 664 
 665 
 666         if (!sk->dead) 
 667                 sk->data_ready(sk,skb->len);
 668         
 669         release_sock(sk);
 670         return(0);
 671 }
 672 
 673 
 674 struct proto udp_prot = {
 675   sock_wmalloc,
 676   sock_rmalloc,
 677   sock_wfree,
 678   sock_rfree,
 679   sock_rspace,
 680   sock_wspace,
 681   udp_close,
 682   udp_read,
 683   udp_write,
 684   udp_sendto,
 685   udp_recvfrom,
 686   ip_build_header,
 687   udp_connect,
 688   NULL,
 689   ip_queue_xmit,
 690   ip_retransmit,
 691   NULL,
 692   NULL,
 693   udp_rcv,
 694   datagram_select,
 695   udp_ioctl,
 696   NULL,
 697   NULL,
 698   ip_setsockopt,
 699   ip_getsockopt,
 700   128,
 701   0,
 702   {NULL,},
 703   "UDP"
 704 };

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