root/net/tcp/udp.c

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

DEFINITIONS

This source file includes following definitions.
  1. print_uh
  2. udp_select
  3. udp_err
  4. udp_check
  5. udp_send_check
  6. udp_loopback
  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 /* udp.c */
   2 /*
   3     Copyright (C) 1992  Ross Biro
   4 
   5     This program is free software; you can redistribute it and/or modify
   6     it under the terms of the GNU General Public License as published by
   7     the Free Software Foundation; either version 2, or (at your option)
   8     any later version.
   9 
  10     This program is distributed in the hope that it will be useful,
  11     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13     GNU General Public License for more details.
  14 
  15     You should have received a copy of the GNU General Public License
  16     along with this program; if not, write to the Free Software
  17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  18 
  19     The Author may be reached as bir7@leland.stanford.edu or
  20     C/O Department of Mathematics; Stanford University; Stanford, CA 94305
  21 */
  22 /* $Id: udp.c,v 0.8.4.5 1992/11/18 15:38:03 bir7 Exp $ */
  23 /* $Log: udp.c,v $
  24  * Revision 0.8.4.5  1992/11/18  15:38:03  bir7
  25  * fixed minor problem in waiting for memory.
  26  *
  27  * Revision 0.8.4.4  1992/11/17  14:19:47  bir7
  28  * *** empty log message ***
  29  *
  30  * Revision 0.8.4.3  1992/11/15  14:55:30  bir7
  31  * Fixed ctrl-h and added NULL checking to print_uh
  32  *
  33  * Revision 0.8.4.2  1992/11/10  10:38:48  bir7
  34  * Change free_s to kfree_s and accidently changed free_skb to kfree_skb.
  35  *
  36  * Revision 0.8.4.1  1992/11/10  00:17:18  bir7
  37  * version change only.
  38  *
  39  * Revision 0.8.3.5  1992/11/10  00:14:47  bir7
  40  * Changed malloc to kmalloc and added $iId$ and 
  41  * */
  42 
  43 #include <linux/types.h>
  44 #include <linux/sched.h>
  45 #include <linux/fcntl.h>
  46 #include <linux/socket.h>
  47 #include <netinet/in.h>
  48 #include "timer.h"
  49 #include "ip.h"
  50 #include "tcp.h"
  51 #include "sock.h"
  52 #include <linux/errno.h>
  53 #include <linux/timer.h>
  54 #include <linux/termios.h> /* for ioctl's */
  55 #include <asm/system.h>
  56 #include <asm/segment.h>
  57 #include <linux/mm.h>
  58 #include "../kern_sock.h" /* for PRINTK */
  59 #include "udp.h"
  60 #include "icmp.h"
  61 
  62 #define min(a,b) ((a)<(b)?(a):(b))
  63 
  64 static void
  65 print_uh(struct udp_header *uh)
     /* [previous][next][first][last][top][bottom][index][help] */
  66 {
  67   if (uh == NULL)
  68     {
  69       PRINTK ("(NULL)\n");
  70       return;
  71     }
  72         PRINTK("source = %d, dest = %d\n", net16(uh->source), net16(uh->dest));
  73         PRINTK("len = %d, check = %d\n", net16(uh->len), net16(uh->check));
  74 }
  75 
  76 
  77 int
  78 udp_select (volatile struct sock *sk, int sel_type, select_table *wait)
     /* [previous][next][first][last][top][bottom][index][help] */
  79 {
  80    select_wait(sk->sleep, wait);
  81    switch (sel_type)
  82      {
  83        case SEL_IN:
  84         if (sk->rqueue != NULL) 
  85           {
  86              return (1);
  87           }
  88         return (0);
  89 
  90        case SEL_OUT:
  91         if (sk->prot->wspace(sk) >= MIN_WRITE_SPACE)
  92           {
  93              return (1);
  94           }
  95         return (0);
  96         
  97        case SEL_EX:
  98         if (sk->err) return (1); /* can this ever happen? */
  99         return (0);
 100      }
 101    return (0);
 102 }
 103 
 104 /* this routine is called by the icmp module when it gets some
 105    sort of error condition.  If err < 0 then the socket should
 106    be closed and the error returned to the user.  If err > 0
 107    it's just the icmp type << 8 | icmp code.  
 108    header points to the first 8 bytes of the tcp header.  We need
 109    to find the appropriate port. */
 110 
 111 void
 112 udp_err (int err, unsigned char *header, unsigned long daddr,
     /* [previous][next][first][last][top][bottom][index][help] */
 113          unsigned long saddr, struct ip_protocol *protocol)
 114 {
 115    struct tcp_header *th;
 116    volatile struct sock *sk;
 117    
 118    th = (struct tcp_header *)header;
 119    sk = get_sock (&udp_prot, net16(th->dest), saddr, th->source, daddr);
 120 
 121    if (sk == NULL) return;
 122    if (err & 0xff00 == (ICMP_SOURCE_QUENCH << 8))
 123      {
 124         if (sk->cong_window > 1)
 125           sk->cong_window = sk->cong_window/2;
 126         return;
 127      }
 128 
 129    sk->err = icmp_err_convert[err & 0xff].errno;
 130    if (icmp_err_convert[err & 0xff].fatal)
 131      {
 132         sk->prot->close(sk, 0);
 133      }
 134 
 135    return;
 136 
 137 }
 138 
 139 static  unsigned short
 140 udp_check (struct udp_header *uh, int len,
     /* [previous][next][first][last][top][bottom][index][help] */
 141            unsigned long saddr, unsigned long daddr)
 142 {
 143    unsigned long sum;
 144    PRINTK ("udp_check (uh=%X, len = %d, saddr = %X, daddr = %X)\n",
 145            uh, len, saddr, daddr);
 146 
 147    print_uh (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" ((net16(len) << 16) + IPPROTO_UDP*256)
 154           : "cx","bx","dx" );
 155 
 156   if (len > 3)
 157     {
 158       __asm__(
 159               "\tclc\n"
 160               "1:\n"
 161               "\t lodsl\n"
 162               "\t adcl %%eax, %%ebx\n"
 163               "\t loop 1b\n"
 164               "\t adcl $0, %%ebx\n"
 165               : "=b" (sum) , "=S" (uh)
 166               : "0" (sum), "c" (len/4) ,"1" (uh)
 167               : "ax", "cx", "bx", "si" );
 168     }
 169 
 170   /* convert from 32 bits to 16 bits. */
 171   __asm__(
 172           "\t movl %%ebx, %%ecx\n"
 173           "\t shrl $16,%%ecx\n"
 174           "\t addw %%cx, %%bx\n"
 175           "\t adcw $0, %%bx\n"
 176           : "=b" (sum)
 177           : "0" (sum)
 178           : "bx", "cx");
 179 
 180 
 181   /* check for an extra word. */
 182   if ((len & 2) != 0)
 183     {
 184       __asm__("\t lodsw\n"
 185               "\t addw %%ax,%%bx\n"
 186               "\t adcw $0, %%bx\n"
 187               : "=b" (sum), "=S" (uh)
 188               : "0" (sum) ,"1" (uh)
 189               : "si", "ax", "bx");
 190     }
 191 
 192   /* now check for the extra byte. */
 193   if ((len & 1) != 0)
 194     {
 195       __asm__("\t lodsb\n"
 196               "\t movb $0,%%ah\n"
 197               "\t addw %%ax,%%bx\n"
 198               "\t adcw $0, %%bx\n"
 199               : "=b" (sum)
 200               : "0" (sum) ,"S" (uh)
 201               : "si", "ax", "bx");
 202     }
 203   /* we only want the bottom 16 bits, but we never cleared
 204      the top 16. */
 205    return ((~sum) & 0xffff);
 206 }
 207 
 208 static  void
 209 udp_send_check (struct udp_header *uh, unsigned long saddr, 
     /* [previous][next][first][last][top][bottom][index][help] */
 210                 unsigned long daddr, int len, volatile struct sock *sk)
 211 {
 212   uh->check = 0;
 213   if (sk && sk->no_check) return;
 214   uh->check = udp_check (uh, len, saddr, daddr);
 215 }
 216 
 217 static  int
 218 udp_loopback (volatile struct sock *sk, unsigned short port,
     /* [previous][next][first][last][top][bottom][index][help] */
 219               unsigned char *from,
 220               int len, unsigned long daddr, unsigned long saddr)
 221 {
 222         struct udp_header *uh;
 223         struct sk_buff *skb;
 224         volatile struct sock *pair;
 225         sk->inuse = 1;
 226 
 227         PRINTK ("udp_loopback \n");
 228 
 229         pair = get_sock (sk->prot, net16(port), saddr,
 230                          sk->dummy_th.source, daddr);
 231 
 232         if (pair == NULL) return (0);
 233 
 234         skb = pair->prot->rmalloc (pair,
 235                                    sizeof (*skb) + sizeof (*uh) + len + 4,
 236                                    0, GFP_KERNEL);
 237 
 238         /* if we didn't get the memory, just drop the packet. */
 239         if (skb == NULL) return (len);
 240 
 241         skb->mem_addr = skb;
 242         skb->mem_len = sizeof (*skb) + len + sizeof (*uh) + 4;
 243 
 244         skb->daddr = saddr;
 245         skb->saddr = daddr;
 246 
 247         skb->len = len;
 248         skb->h.raw = (unsigned char *)(skb+1);
 249 
 250         uh = skb->h.uh;
 251         uh -> source = sk->dummy_th.source;
 252         uh -> dest = port;
 253         uh -> len = len + sizeof (*uh);
 254 /*      verify_area (from , len); */
 255         memcpy_fromfs(uh+1, from, len);
 256         pair->inuse = 1;
 257         if (pair->rqueue == NULL)
 258           {
 259                   pair->rqueue = skb;
 260                   skb->next = skb;
 261                   skb->prev = skb;
 262           }
 263         else
 264           {
 265                   skb->next = pair->rqueue;
 266                   skb->prev = pair->rqueue->prev;
 267                   skb->prev->next = skb;
 268                   skb->next->prev = skb;
 269           }
 270         wake_up (pair->sleep);
 271         release_sock (pair);
 272         release_sock (sk);
 273         return (len);
 274 
 275 }
 276 
 277 static int
 278 udp_sendto (volatile struct sock *sk, unsigned char *from, int len,
     /* [previous][next][first][last][top][bottom][index][help] */
 279             int noblock,
 280             unsigned flags, struct sockaddr_in *usin, int addr_len)
 281 {
 282         /* this should be easy, we just send the packet. */
 283         struct sk_buff *skb;
 284         struct udp_header *uh;
 285         unsigned char *buff;
 286         unsigned long saddr;
 287         int copied=0;
 288         int amt;
 289         struct device *dev=NULL;
 290         struct sockaddr_in sin;
 291 
 292         /* check the flags. */
 293         if (flags) return (-EINVAL);
 294         if (len < 0) return (-EINVAL);
 295         if (len == 0) return (0);
 296 
 297         PRINTK ("sendto len = %d\n", len);
 298 
 299         /* get and verify the address. */
 300         if (usin)
 301           {
 302                   if (addr_len < sizeof (sin))
 303                     return (-EINVAL);
 304 /*                verify_area (usin, sizeof (sin));*/
 305                   memcpy_fromfs (&sin, usin, sizeof(sin));
 306                   if (sin.sin_family &&
 307                       sin.sin_family != AF_INET)
 308                     return (-EINVAL);
 309                   if (sin.sin_port == 0)
 310                     return (-EINVAL);
 311           }
 312         else
 313           {
 314                   if (sk->state != TCP_ESTABLISHED)
 315                     return (-EINVAL);
 316                   sin.sin_family = AF_INET;
 317                   sin.sin_port = sk->dummy_th.dest;
 318                   sin.sin_addr.s_addr = sk->daddr;
 319           }
 320 
 321         /* check for a valid saddr. */
 322         saddr = sk->saddr;
 323         if ((saddr &  0xff000000) == 0)
 324           {
 325              saddr = MY_IP_ADDR;
 326           }
 327 
 328         /* if it's a broadcast, make sure we get it. */
 329         if ((sin.sin_addr.s_addr & 0xff000000) == 0)
 330           {
 331              int err;
 332              err = udp_loopback (sk, sin.sin_port, from, len,
 333                                  sin.sin_addr.s_addr, saddr);
 334              if (err < 0)
 335                return (err);
 336           }
 337 
 338         sk->inuse = 1;
 339 
 340         while (len > 0)
 341           {
 342                   int tmp;
 343                   skb = sk->prot->wmalloc (sk, len + sizeof (*skb)
 344                                                + sk->prot->max_header, 0,
 345                                            GFP_KERNEL);
 346                   /* this should never happen, but it is possible. */
 347 
 348                   if (skb == NULL)
 349                     {
 350                        printk ("udp_sendto: write buffer full?\n");
 351                        print_sk(sk);
 352                        tmp = sk->wmem_alloc;
 353                        release_sock (sk);
 354                        if (copied) return (copied);
 355                        if (noblock) return (-EAGAIN);
 356                        cli();
 357                        if (tmp <= sk->wmem_alloc)
 358                          {
 359                            interruptible_sleep_on (sk->sleep);
 360                            if (current->signal & ~current->blocked)
 361                              {
 362                                sti();
 363                                if (copied) return (copied);
 364                                return (-ERESTARTSYS);
 365                              }
 366                          }
 367                        sk->inuse = 1;
 368                        sti();
 369                        continue;
 370                     }
 371 
 372                   skb->mem_addr = skb;
 373                   skb->mem_len = len + sizeof (*skb) + sk->prot->max_header;
 374                   skb->sk = sk;
 375                   skb->free = 1;
 376                   skb->arp = 0;
 377 
 378                   /* now build the ip and dev header. */
 379                   buff = (unsigned char *)(skb+1);
 380                   tmp = sk->prot->build_header (skb, saddr,
 381                                                 sin.sin_addr.s_addr, &dev,
 382                                                 IPPROTO_UDP, sk->opt, skb->mem_len);
 383                   if (tmp < 0 )
 384                     {
 385                             sk->prot->wfree (sk, skb->mem_addr, skb->mem_len);
 386                             release_sock (sk);
 387                             return (tmp);
 388                     }
 389                   buff += tmp;
 390 
 391                   /* we shouldn't do this, instead we should just
 392                      let the ip protocol fragment the packet. */
 393                   amt = min (len + tmp + sizeof (*uh), dev->mtu);
 394 
 395                   PRINTK ("amt = %d, dev = %X, dev->mtu = %d\n",
 396                           amt, dev, dev->mtu);
 397 
 398                   skb->len = amt;
 399                   amt -= tmp; 
 400 
 401                   uh = (struct udp_header *)buff;
 402                   uh->len = net16(amt);
 403                   uh->source = sk->dummy_th.source;
 404                   uh->dest = sin.sin_port;
 405 
 406                   amt -= sizeof (*uh);
 407                   buff += sizeof (*uh);
 408 
 409 /*                verify_area (from, amt);*/
 410                   memcpy_fromfs( buff, from, amt);
 411 
 412                   len -= amt;
 413                   copied += amt;
 414                   from += amt;
 415                   udp_send_check (uh, saddr, sin.sin_addr.s_addr,
 416                                   amt+sizeof (*uh), sk);
 417                                   
 418                   sk->prot->queue_xmit (sk, dev, skb, 1);
 419           }
 420         release_sock (sk);
 421         return (copied);
 422 }
 423 
 424 static int
 425 udp_write (volatile struct sock *sk, unsigned char *buff, int len, int noblock,
     /* [previous][next][first][last][top][bottom][index][help] */
 426            unsigned flags)
 427 {
 428         return (udp_sendto (sk, buff, len, noblock, flags, NULL, 0));
 429 }
 430 
 431 
 432 static int
 433 udp_ioctl (volatile struct sock *sk, int cmd, unsigned long arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 434 {
 435   switch (cmd)
 436     {
 437     default:
 438       return (-EINVAL);
 439 
 440       case TIOCOUTQ:
 441         {
 442           unsigned long amount;
 443           if (sk->state == TCP_LISTEN)
 444             return (-EINVAL);
 445           amount = sk->prot->wspace(sk)/2;
 446           verify_area ((void *)arg, sizeof (unsigned long));
 447           put_fs_long (amount, (unsigned long *)arg);
 448           return (0);
 449         }
 450 
 451 
 452       case TIOCINQ:
 453 /*      case FIONREAD:*/
 454         {
 455           struct sk_buff *skb;
 456           unsigned long amount;
 457           if (sk->state == TCP_LISTEN)
 458             return (-EINVAL);
 459           amount = 0;
 460           skb = sk->rqueue;
 461           if (skb != NULL)
 462             {
 463               /* we will only return the amount of this packet since that is all
 464                  that will be read. */
 465               amount = skb->len;
 466             }
 467 
 468           verify_area ((void *)arg, sizeof (unsigned long));
 469           put_fs_long (amount, (unsigned long *)arg);
 470           return (0);
 471         }
 472     }
 473 }
 474 
 475 int
 476 udp_recvfrom (volatile struct sock *sk, unsigned char *to, int len,
     /* [previous][next][first][last][top][bottom][index][help] */
 477               int noblock,
 478               unsigned flags, struct sockaddr_in *sin, int *addr_len)
 479 {
 480         /* this should be easy, if there is something there we
 481            return it, otherwise we block. */
 482         int copied=0;
 483         struct sk_buff *skb;
 484         if (len == 0) return (0);
 485         if (len < 0) return (-EINVAL);
 486 
 487         /* this will pick up errors that occured
 488            while the program was doing something
 489            else. */
 490         if (sk->err)
 491           {
 492             int err;
 493             err = -sk->err;
 494             sk->err = 0;
 495             return (err);
 496           }
 497         if (addr_len)
 498           {
 499                   verify_area (addr_len, sizeof(*addr_len));
 500                   put_fs_long (sizeof (*sin), addr_len);
 501           }
 502         sk->inuse = 1;
 503         while (sk->rqueue == NULL)
 504           {
 505              if (noblock)
 506                {
 507                   release_sock (sk);
 508                   return (-EAGAIN);
 509                }
 510              release_sock (sk);
 511              cli();
 512              if (sk->rqueue == NULL)
 513                {
 514                   interruptible_sleep_on (sk->sleep);
 515                   if (current->signal & ~current->blocked)
 516                     {
 517                        return (-ERESTARTSYS);
 518                     }
 519                }
 520              sti();
 521           }
 522         skb = sk->rqueue;
 523 
 524         if (!(flags & MSG_PEEK))
 525           {
 526                   if (skb->next == skb )
 527                     {
 528                             sk->rqueue = NULL;
 529                     }
 530                   else
 531                     {
 532                             sk->rqueue = sk->rqueue ->next;
 533                             skb->prev->next = skb->next;
 534                             skb->next->prev = skb->prev;
 535                     }
 536           }
 537         copied = min (len, skb->len);
 538         verify_area (to, copied);
 539         memcpy_tofs (to, skb->h.raw + sizeof (struct udp_header), copied);
 540         /* copy the address. */
 541         if (sin)
 542           {
 543                   struct sockaddr_in addr;
 544                   addr.sin_family = AF_INET;
 545                   addr.sin_port = skb->h.uh->source;
 546                   addr.sin_addr.s_addr = skb->daddr;
 547                   verify_area (sin, sizeof (*sin));
 548                   memcpy_tofs(sin, &addr, sizeof (*sin));
 549           }
 550 
 551         if (!(flags & MSG_PEEK))
 552           {
 553              kfree_skb (skb, FREE_READ);
 554           }
 555         release_sock (sk);
 556         return (copied);
 557 
 558 }
 559 
 560 
 561 int
 562 udp_read (volatile struct sock *sk, unsigned char *buff, int len, int noblock,
     /* [previous][next][first][last][top][bottom][index][help] */
 563           unsigned flags)
 564 {
 565         return (udp_recvfrom (sk, buff, len, noblock, flags, NULL, NULL));
 566 }
 567 
 568 int
 569 udp_connect (volatile struct sock *sk, struct sockaddr_in *usin, int addr_len)
     /* [previous][next][first][last][top][bottom][index][help] */
 570 {
 571         struct sockaddr_in sin;
 572         if (addr_len < sizeof (sin)) return (-EINVAL);
 573 /*      verify_area (usin, sizeof (sin)); */
 574         memcpy_fromfs (&sin, usin, sizeof (sin));
 575         if (sin.sin_family && sin.sin_family != AF_INET)
 576           return (-EAFNOSUPPORT);
 577         sk->daddr = sin.sin_addr.s_addr;
 578         sk->dummy_th.dest = sin.sin_port;
 579         sk->state = TCP_ESTABLISHED;
 580         return(0);
 581 }
 582 
 583 static void
 584 udp_close(volatile struct sock *sk, int timeout)
     /* [previous][next][first][last][top][bottom][index][help] */
 585 {
 586         sk->inuse = 1;
 587         sk->state = TCP_CLOSE;
 588         if (sk->dead)
 589           destroy_sock (sk);
 590         else
 591           release_sock (sk);
 592 }
 593 
 594 int
 595 udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
     /* [previous][next][first][last][top][bottom][index][help] */
 596         unsigned long daddr, unsigned short len,
 597         unsigned long saddr, int redo, struct ip_protocol *protocol)
 598 {
 599         /* all we need to do is get the socket, and then do a checksum. */
 600         struct proto *prot=&udp_prot;
 601         volatile struct sock *sk;
 602         struct udp_header *uh;
 603 
 604         uh = (struct udp_header *) skb->h.uh;
 605 
 606         if (dev->add_arp) dev->add_arp (saddr, skb, dev);
 607 
 608         sk = get_sock (prot, net16(uh->dest), saddr, uh->source, daddr);
 609 
 610         /* if we don't know about the socket, forget about it. */
 611         if (sk == NULL)
 612           {
 613             if ((daddr & 0xff000000 != 0) && (daddr & 0xff000000 != 0xff000000))
 614               {
 615                 icmp_reply (skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, dev);
 616               }
 617             skb->sk = NULL;
 618             kfree_skb (skb, 0);
 619             return (0);
 620           }
 621 
 622 
 623         if (!redo)
 624           {
 625              if (uh->check && udp_check (uh, len, saddr, daddr))
 626                {
 627                   PRINTK ("bad udp checksum\n");
 628                   skb->sk = NULL;
 629                   kfree_skb (skb, 0);
 630                   return (0);
 631                }
 632 
 633              skb->sk = sk;
 634              skb->dev = dev;
 635              skb->len = len;
 636 
 637              /* these are supposed to be switched. */
 638              skb->daddr = saddr;
 639              skb->saddr = daddr;
 640 
 641              /* Now deal with the in use. */
 642              cli();
 643              if (sk->inuse)
 644                {
 645                   if (sk->back_log == NULL)
 646                     {
 647                        sk->back_log = skb;
 648                        skb->next = skb;
 649                        skb->prev = skb;
 650                     }
 651                   else
 652                     {
 653                        skb->next = sk->back_log;
 654                        skb->prev = sk->back_log->prev;
 655                        skb->prev->next = skb;
 656                        skb->next->prev = skb;
 657                     }
 658                   sti();
 659                   return (0);
 660                }
 661              sk->inuse = 1;
 662              sti();
 663           }
 664 
 665         /* charge it too the socket. */
 666         if (sk->rmem_alloc + skb->mem_len >= SK_RMEM_MAX)
 667           {
 668              skb->sk = NULL;
 669              kfree_skb (skb, 0);
 670              release_sock (sk);
 671              return (0);
 672           }
 673              
 674         sk->rmem_alloc += skb->mem_len;
 675 
 676         /* At this point we should print the thing out. */
 677         PRINTK ("<< \n");
 678         print_sk (sk);
 679 
 680         /* now add it to the data chain and wake things up. */
 681         if (sk->rqueue == NULL)
 682           {
 683                   sk->rqueue = skb;
 684                   skb->next = skb;
 685                   skb->prev = skb;
 686           }
 687         else
 688           {
 689                   skb->next = sk->rqueue;
 690                   skb->prev = sk->rqueue->prev;
 691                   skb->prev->next = skb;
 692                   skb->next->prev = skb;
 693           }
 694 
 695         skb->len = len - sizeof (*uh);
 696 
 697         if (!sk->dead)
 698           wake_up (sk->sleep);
 699 
 700         release_sock (sk);
 701         return (0);
 702 }
 703 
 704 
 705 
 706 struct proto udp_prot =
 707 {
 708   sock_wmalloc,
 709   sock_rmalloc,
 710   sock_wfree,
 711   sock_rfree,
 712   sock_rspace,
 713   sock_wspace,
 714   udp_close,
 715   udp_read,
 716   udp_write,
 717   udp_sendto,
 718   udp_recvfrom,
 719   ip_build_header,
 720   udp_connect,
 721   NULL,
 722   ip_queue_xmit,
 723   ip_retransmit,
 724   NULL,
 725   NULL,
 726   udp_rcv,
 727   udp_select,
 728   udp_ioctl,
 729   NULL,
 730   128,
 731   0,
 732   {NULL,}
 733 };
 734 

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