Annotation of linux/net/tcp/udp.c, revision 1.1

1.1     ! root        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 [email protected] or
        !            20:     C/O Department of Mathematics; Stanford University; Stanford, CA 94305
        !            21: */
        !            22: 
        !            23: #include <linux/types.h>
        !            24: #include <linux/sched.h>
        !            25: #include <linux/fcntl.h>
        !            26: #include <linux/socket.h>
        !            27: #include <netinet/in.h>
        !            28: #include "timer.h"
        !            29: #include "ip.h"
        !            30: #include "tcp.h"
        !            31: #include "sock.h"
        !            32: #include <linux/errno.h>
        !            33: #include <linux/timer.h>
        !            34: #include <asm/system.h>
        !            35: #include <asm/segment.h>
        !            36: #include "../kern_sock.h" /* for PRINTK */
        !            37: #include "udp.h"
        !            38: #include "icmp.h"
        !            39: 
        !            40: #define min(a,b) ((a)<(b)?(a):(b))
        !            41: 
        !            42: static void
        !            43: print_uh(struct udp_header *uh)
        !            44: {
        !            45:        PRINTK("source = %d, dest = %d\n", net16(uh->source), net16(uh->dest));
        !            46:        PRINTK("len = %d, check = %d\n", net16(uh->len), net16(uh->check));
        !            47: }
        !            48: 
        !            49: 
        !            50: int
        !            51: udp_select (volatile struct sock *sk, int sel_type, select_table *wait)
        !            52: {
        !            53:    select_wait(sk->sleep, wait);
        !            54:    switch (sel_type)
        !            55:      {
        !            56:        case SEL_IN:
        !            57:        if (sk->rqueue != NULL) 
        !            58:          {
        !            59:             return (1);
        !            60:          }
        !            61:        return (0);
        !            62: 
        !            63:        case SEL_OUT:
        !            64:        if (sk->prot->wspace(sk) >= MIN_WRITE_SPACE)
        !            65:          {
        !            66:             return (1);
        !            67:          }
        !            68:        return (0);
        !            69:        
        !            70:        case SEL_EX:
        !            71:        if (sk->err) return (1); /* can this ever happen? */
        !            72:        return (0);
        !            73:      }
        !            74:    return (0);
        !            75: }
        !            76: 
        !            77: /* this routine is called by the icmp module when it gets some
        !            78:    sort of error condition.  If err < 0 then the socket should
        !            79:    be closed and the error returned to the user.  If err > 0
        !            80:    it's just the icmp type << 8 | icmp code.  
        !            81:    header points to the first 8 bytes of the tcp header.  We need
        !            82:    to find the appropriate port. */
        !            83: 
        !            84: void
        !            85: udp_err (int err, unsigned char *header, unsigned long daddr,
        !            86:         unsigned long saddr, struct ip_protocol *protocol)
        !            87: {
        !            88:    struct tcp_header *th;
        !            89:    volatile struct sock *sk;
        !            90:    
        !            91:    th = (struct tcp_header *)header;
        !            92:    sk = get_sock (&udp_prot, net16(th->dest), saddr, th->source, daddr);
        !            93: 
        !            94:    if (sk == NULL) return;
        !            95:    if (err & 0xff00 == (ICMP_SOURCE_QUENCH << 8))
        !            96:      {
        !            97:        if (sk->cong_window > 1)
        !            98:          sk->cong_window = sk->cong_window/2;
        !            99:        return;
        !           100:      }
        !           101: 
        !           102:    sk->err = icmp_err_convert[err & 0xff].errno;
        !           103:    if (icmp_err_convert[err & 0xff].fatal)
        !           104:      {
        !           105:        sk->prot->close(sk, 0);
        !           106:      }
        !           107: 
        !           108:    return;
        !           109: 
        !           110: }
        !           111: 
        !           112: static  unsigned short
        !           113: udp_check (struct udp_header *uh, int len,
        !           114:           unsigned long saddr, unsigned long daddr)
        !           115: {
        !           116:    unsigned long sum;
        !           117:    PRINTK ("udp_check (uh=%X, len = %d, saddr = %X, daddr = %X)\n",
        !           118:           uh, len, saddr, daddr);
        !           119: 
        !           120:    print_uh (uh);
        !           121: 
        !           122:   __asm__("\t addl %%ecx,%%ebx\n"
        !           123:          "\t adcl %%edx,%%ebx\n"
        !           124:          "\t adcl $0, %%ebx\n"
        !           125:          : "=b" (sum)
        !           126:          : "0" (daddr), "c" (saddr), "d" ((net16(len) << 16) + IP_UDP*256)
        !           127:          : "cx","bx","dx" );
        !           128: 
        !           129:   if (len > 3)
        !           130:     {
        !           131:       __asm__(
        !           132:              "\tclc\n"
        !           133:              "1:\n"
        !           134:              "\t lodsl\n"
        !           135:              "\t adcl %%eax, %%ebx\n"
        !           136:              "\t loop 1b\n"
        !           137:              "\t adcl $0, %%ebx\n"
        !           138:              : "=b" (sum) , "=S" (uh)
        !           139:              : "0" (sum), "c" (len/4) ,"1" (uh)
        !           140:              : "ax", "cx", "bx", "si" );
        !           141:     }
        !           142: 
        !           143:   /* convert from 32 bits to 16 bits. */
        !           144:   __asm__(
        !           145:          "\t movl %%ebx, %%ecx\n"
        !           146:          "\t shrl $16,%%ecx\n"
        !           147:          "\t addw %%cx, %%bx\n"
        !           148:          "\t adcw $0, %%bx\n"
        !           149:          : "=b" (sum)
        !           150:          : "0" (sum)
        !           151:          : "bx", "cx");
        !           152: 
        !           153: 
        !           154:   /* check for an extra word. */
        !           155:   if ((len & 2) != 0)
        !           156:     {
        !           157:       __asm__("\t lodsw\n"
        !           158:              "\t addw %%ax,%%bx\n"
        !           159:              "\t adcw $0, %%bx\n"
        !           160:              : "=b" (sum), "=S" (uh)
        !           161:              : "0" (sum) ,"1" (uh)
        !           162:              : "si", "ax", "bx");
        !           163:     }
        !           164: 
        !           165:   /* now check for the extra byte. */
        !           166:   if ((len & 1) != 0)
        !           167:     {
        !           168:       __asm__("\t lodsb\n"
        !           169:              "\t movb $0,%%ah\n"
        !           170:              "\t addw %%ax,%%bx\n"
        !           171:              "\t adcw $0, %%bx\n"
        !           172:              : "=b" (sum)
        !           173:              : "0" (sum) ,"S" (uh)
        !           174:              : "si", "ax", "bx");
        !           175:     }
        !           176:   /* we only want the bottom 16 bits, but we never cleared
        !           177:      the top 16. */
        !           178:    return ((~sum) & 0xffff);
        !           179: }
        !           180: 
        !           181: static  void
        !           182: udp_send_check (struct udp_header *uh, unsigned long saddr, 
        !           183:                unsigned long daddr, int len, volatile struct sock *sk)
        !           184: {
        !           185:   uh->check = 0;
        !           186:   if (sk && sk->no_check) return;
        !           187:   uh->check = udp_check (uh, len, saddr, daddr);
        !           188: }
        !           189: 
        !           190: static  int
        !           191: udp_loopback (volatile struct sock *sk, unsigned short port,
        !           192:              unsigned char *from,
        !           193:              int len, unsigned long daddr, unsigned long saddr)
        !           194: {
        !           195:        struct udp_header *uh;
        !           196:        struct sk_buff *skb;
        !           197:        volatile struct sock *pair;
        !           198:        sk->inuse = 1;
        !           199: 
        !           200:        PRINTK ("udp_loopback \n");
        !           201: 
        !           202:        pair = get_sock (sk->prot, net16(port), saddr,
        !           203:                         sk->dummy_th.source, daddr);
        !           204: 
        !           205:        if (pair == NULL) return (0);
        !           206: 
        !           207:        skb = pair->prot->rmalloc (pair,
        !           208:                                   sizeof (*skb) + sizeof (*uh) + len + 4,
        !           209:                                   0);
        !           210: 
        !           211:        /* if we didn't get the memory, just drop the packet. */
        !           212:        if (skb == NULL) return (len);
        !           213: 
        !           214:        skb->mem_addr = skb;
        !           215:        skb->mem_len = sizeof (*skb) + len + sizeof (*uh) + 4;
        !           216: 
        !           217:        skb->daddr = saddr;
        !           218:        skb->saddr = daddr;
        !           219: 
        !           220:        skb->len = len;
        !           221:        skb->h.raw = (unsigned char *)(skb+1);
        !           222: 
        !           223:        uh = skb->h.uh;
        !           224:        uh -> source = sk->dummy_th.source;
        !           225:        uh -> dest = port;
        !           226:        uh -> len = len + sizeof (*uh);
        !           227:        verify_area (from , len);
        !           228:        memcpy_fromfs(uh+1, from, len);
        !           229:        pair->inuse = 1;
        !           230:        if (pair->rqueue == NULL)
        !           231:          {
        !           232:                  pair->rqueue = skb;
        !           233:                  skb->next = skb;
        !           234:                  skb->prev = skb;
        !           235:          }
        !           236:        else
        !           237:          {
        !           238:                  skb->next = pair->rqueue;
        !           239:                  skb->prev = pair->rqueue->prev;
        !           240:                  skb->prev->next = skb;
        !           241:                  skb->next->prev = skb;
        !           242:          }
        !           243:        wake_up (pair->sleep);
        !           244:        release_sock (pair);
        !           245:        release_sock (sk);
        !           246:        return (len);
        !           247: 
        !           248: }
        !           249: 
        !           250: static int
        !           251: udp_sendto (volatile struct sock *sk, unsigned char *from, int len,
        !           252:            int noblock,
        !           253:            unsigned flags, struct sockaddr_in *usin, int addr_len)
        !           254: {
        !           255:        /* this should be easy, we just send the packet. */
        !           256:        struct sk_buff *skb;
        !           257:        struct udp_header *uh;
        !           258:        unsigned char *buff;
        !           259:        unsigned long saddr;
        !           260:        int copied=0;
        !           261:        int amt;
        !           262:        struct device *dev=NULL;
        !           263:        struct sockaddr_in sin;
        !           264: 
        !           265:        /* check the flags. */
        !           266:        if (flags) return (-EINVAL);
        !           267:        if (len < 0) return (-EINVAL);
        !           268:        if (len == 0) return (0);
        !           269: 
        !           270:        PRINTK ("sendto len = %d\n", len);
        !           271: 
        !           272:        /* get and verify the address. */
        !           273:        if (usin)
        !           274:          {
        !           275:                  if (addr_len < sizeof (sin))
        !           276:                    return (-EINVAL);
        !           277:                  verify_area (usin, sizeof (sin));
        !           278:                  memcpy_fromfs (&sin, usin, sizeof(sin));
        !           279:                  if (sin.sin_family &&
        !           280:                      sin.sin_family != AF_INET)
        !           281:                    return (-EINVAL);
        !           282:                  if (sin.sin_port == 0)
        !           283:                    return (-EINVAL);
        !           284:          }
        !           285:        else
        !           286:          {
        !           287:                  if (sk->state != TCP_ESTABLISHED)
        !           288:                    return (-EINVAL);
        !           289:                  sin.sin_family = AF_INET;
        !           290:                  sin.sin_port = sk->dummy_th.dest;
        !           291:                  sin.sin_addr.s_addr = sk->daddr;
        !           292:          }
        !           293: 
        !           294:        /* check for a valid saddr. */
        !           295:        saddr = sk->saddr;
        !           296:        if ((saddr &  0xff000000) == 0)
        !           297:          {
        !           298:             saddr = MY_IP_ADDR;
        !           299:          }
        !           300: 
        !           301:        /* if it's a broadcast, make sure we get it. */
        !           302:        if ((sin.sin_addr.s_addr & 0xff000000) == 0)
        !           303:          {
        !           304:             int err;
        !           305:             err = udp_loopback (sk, sin.sin_port, from, len,
        !           306:                                 sin.sin_addr.s_addr, saddr);
        !           307:             if (err < 0)
        !           308:               return (err);
        !           309:          }
        !           310: 
        !           311:        sk->inuse = 1;
        !           312: 
        !           313:        while (len > 0)
        !           314:          {
        !           315:                  int tmp;
        !           316:                  skb = sk->prot->wmalloc (sk, len + sizeof (*skb)
        !           317:                                               + sk->prot->max_header, 0);
        !           318:                  /* this should never happen, but it is possible. */
        !           319: 
        !           320:                  if (skb == NULL)
        !           321:                    {
        !           322:                       printk ("udp_sendto: write buffer full?\n");
        !           323:                       print_sk(sk);
        !           324:                       release_sock (sk);
        !           325:                       if (copied || !noblock)
        !           326:                         return (copied);
        !           327:                       return (-EAGAIN);
        !           328:                    }
        !           329: 
        !           330:                  skb->mem_addr = skb;
        !           331:                  skb->mem_len = len + sizeof (*skb) + sk->prot->max_header;
        !           332:                  skb->sk = sk;
        !           333:                  skb->free = 1;
        !           334:                  skb->arp = 0;
        !           335: 
        !           336:                  /* now build the ip and dev header. */
        !           337:                  buff = (unsigned char *)(skb+1);
        !           338:                  tmp = sk->prot->build_header (skb, saddr,
        !           339:                                                sin.sin_addr.s_addr, &dev,
        !           340:                                                IP_UDP, sk->opt, skb->mem_len);
        !           341:                  if (tmp < 0 )
        !           342:                    {
        !           343:                            sk->prot->wfree (sk, skb->mem_addr, skb->mem_len);
        !           344:                            release_sock (sk);
        !           345:                            return (tmp);
        !           346:                    }
        !           347:                  buff += tmp;
        !           348: 
        !           349:                  /* we shouldn't do this, instead we should just
        !           350:                     let the ip protocol fragment the packet. */
        !           351:                  amt = min (len + tmp + sizeof (*uh), dev->mtu);
        !           352: 
        !           353:                  PRINTK ("amt = %d, dev = %X, dev->mtu = %d\n",
        !           354:                          amt, dev, dev->mtu);
        !           355: 
        !           356:                  skb->len = amt;
        !           357:                  amt -= tmp; 
        !           358: 
        !           359:                  uh = (struct udp_header *)buff;
        !           360:                  uh->len = net16(amt);
        !           361:                  uh->source = sk->dummy_th.source;
        !           362:                  uh->dest = sin.sin_port;
        !           363: 
        !           364:                  amt -= sizeof (*uh);
        !           365:                  buff += sizeof (*uh);
        !           366: 
        !           367:                  verify_area (from, amt);
        !           368:                  memcpy_fromfs( buff, from, amt);
        !           369: 
        !           370:                  len -= amt;
        !           371:                  copied += amt;
        !           372:                  from += amt;
        !           373:                  udp_send_check (uh, saddr, sin.sin_addr.s_addr,
        !           374:                                  amt+sizeof (*uh), sk);
        !           375:                                  
        !           376:                  sk->prot->queue_xmit (sk, dev, skb, 1);
        !           377:          }
        !           378:        release_sock (sk);
        !           379:        return (copied);
        !           380: }
        !           381: 
        !           382: static int
        !           383: udp_write (volatile struct sock *sk, unsigned char *buff, int len, int noblock,
        !           384:           unsigned flags)
        !           385: {
        !           386:        return (udp_sendto (sk, buff, len, noblock, flags, NULL, 0));
        !           387: }
        !           388: 
        !           389: int
        !           390: udp_recvfrom (volatile struct sock *sk, unsigned char *to, int len,
        !           391:              int noblock,
        !           392:              unsigned flags, struct sockaddr_in *sin, int *addr_len)
        !           393: {
        !           394:        /* this should be easy, if there is something there we
        !           395:           return it, otherwise we block. */
        !           396:        int copied=0;
        !           397:        struct sk_buff *skb;
        !           398:        if (len == 0) return (0);
        !           399:        if (len < 0) return (-EINVAL);
        !           400:        if (addr_len)
        !           401:          {
        !           402:                  verify_area (addr_len, sizeof(*addr_len));
        !           403:                  put_fs_long (sizeof (*sin), addr_len);
        !           404:          }
        !           405:        sk->inuse = 1;
        !           406:        while (sk->rqueue == NULL)
        !           407:          {
        !           408:             if (noblock)
        !           409:               {
        !           410:                  release_sock (sk);
        !           411:                  return (-EAGAIN);
        !           412:               }
        !           413:             release_sock (sk);
        !           414:             cli();
        !           415:             if (sk->rqueue == NULL)
        !           416:               {
        !           417:                  interruptible_sleep_on (sk->sleep);
        !           418:                  if (current->signal & ~current->blocked)
        !           419:                    {
        !           420:                       return (-ERESTARTSYS);
        !           421:                    }
        !           422:               }
        !           423:             sti();
        !           424:          }
        !           425:        skb = sk->rqueue;
        !           426: 
        !           427:        if (!(flags & MSG_PEEK))
        !           428:          {
        !           429:                  if (skb->next == skb )
        !           430:                    {
        !           431:                            sk->rqueue = NULL;
        !           432:                    }
        !           433:                  else
        !           434:                    {
        !           435:                            sk->rqueue = sk->rqueue ->next;
        !           436:                            skb->prev->next = skb->next;
        !           437:                            skb->next->prev = skb->prev;
        !           438:                    }
        !           439:          }
        !           440:        copied = min (len, skb->len);
        !           441:        verify_area (to, copied);
        !           442:        memcpy_tofs (to, skb->h.raw + sizeof (struct udp_header), copied);
        !           443:        /* copy the address. */
        !           444:        if (sin)
        !           445:          {
        !           446:                  struct sockaddr_in addr;
        !           447:                  addr.sin_family = AF_INET;
        !           448:                  addr.sin_port = skb->h.uh->source;
        !           449:                  addr.sin_addr.s_addr = skb->daddr;
        !           450:                  verify_area (sin, sizeof (*sin));
        !           451:                  memcpy_tofs(sin, &addr, sizeof (*sin));
        !           452:          }
        !           453: 
        !           454:        if (!(flags & MSG_PEEK))
        !           455:          {
        !           456:             free_skb (skb, FREE_READ);
        !           457:          }
        !           458:        release_sock (sk);
        !           459:        return (copied);
        !           460: 
        !           461: }
        !           462: 
        !           463: 
        !           464: int
        !           465: udp_read (volatile struct sock *sk, unsigned char *buff, int len, int noblock,
        !           466:          unsigned flags)
        !           467: {
        !           468:        return (udp_recvfrom (sk, buff, len, noblock, flags, NULL, NULL));
        !           469: }
        !           470: 
        !           471: int
        !           472: udp_connect (volatile struct sock *sk, struct sockaddr_in *usin, int addr_len)
        !           473: {
        !           474:        struct sockaddr_in sin;
        !           475:        if (addr_len < sizeof (sin)) return (-EINVAL);
        !           476:        verify_area (usin, sizeof (sin));
        !           477:        memcpy_fromfs (&sin, usin, sizeof (sin));
        !           478:        if (sin.sin_family && sin.sin_family != AF_INET)
        !           479:          return (-EAFNOSUPPORT);
        !           480:        sk->daddr = sin.sin_addr.s_addr;
        !           481:        sk->dummy_th.dest = sin.sin_port;
        !           482:        sk->state = TCP_ESTABLISHED;
        !           483:        return(0);
        !           484: }
        !           485: 
        !           486: static void
        !           487: udp_close(volatile struct sock *sk, int timeout)
        !           488: {
        !           489:        sk->inuse = 1;
        !           490:        sk->state = TCP_CLOSE;
        !           491:        if (sk->dead)
        !           492:          destroy_sock (sk);
        !           493:        else
        !           494:          release_sock (sk);
        !           495: }
        !           496: 
        !           497: int
        !           498: udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
        !           499:        unsigned long daddr, unsigned short len,
        !           500:        unsigned long saddr, int redo, struct ip_protocol *protocol)
        !           501: {
        !           502:        /* all we need to do is get the socket, and then do a checksum. */
        !           503:        struct proto *prot=&udp_prot;
        !           504:        volatile struct sock *sk;
        !           505:        struct udp_header *uh;
        !           506: 
        !           507:        uh = (struct udp_header *) skb->h.uh;
        !           508: 
        !           509:        if (dev->add_arp) dev->add_arp (saddr, skb, dev);
        !           510: 
        !           511:        sk = get_sock (prot, net16(uh->dest), saddr, uh->source, daddr);
        !           512: 
        !           513:        /* if we don't know about the socket, forget about it. */
        !           514:        if (sk == NULL &&
        !           515:            (daddr & 0xff000000 != 0) && (daddr & 0xff000000 != 0xff000000))
        !           516:          {
        !           517:             icmp_reply (skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, dev);
        !           518:             skb->sk = NULL;
        !           519:             free_skb (skb, 0);
        !           520:             return (0);
        !           521:          }
        !           522: 
        !           523: 
        !           524:        if (!redo)
        !           525:          {
        !           526:             if (uh->check && udp_check (uh, len, saddr, daddr))
        !           527:               {
        !           528:                  PRINTK ("bad udp checksum\n");
        !           529:                  skb->sk = NULL;
        !           530:                  free_skb (skb, 0);
        !           531:                  return (0);
        !           532:               }
        !           533: 
        !           534:             skb->sk = sk;
        !           535:             skb->dev = dev;
        !           536:             skb->len = len;
        !           537: 
        !           538:             /* these are supposed to be switched. */
        !           539:             skb->daddr = saddr;
        !           540:             skb->saddr = daddr;
        !           541: 
        !           542:             /* Now deal with the in use. */
        !           543:             cli();
        !           544:             if (sk->inuse)
        !           545:               {
        !           546:                  if (sk->back_log == NULL)
        !           547:                    {
        !           548:                       sk->back_log = skb;
        !           549:                       skb->next = skb;
        !           550:                       skb->prev = skb;
        !           551:                    }
        !           552:                  else
        !           553:                    {
        !           554:                       skb->next = sk->back_log;
        !           555:                       skb->prev = sk->back_log->prev;
        !           556:                       skb->prev->next = skb;
        !           557:                       skb->next->prev = skb;
        !           558:                    }
        !           559:                  sti();
        !           560:                  return (0);
        !           561:               }
        !           562:             sk->inuse = 1;
        !           563:             sti();
        !           564:          }
        !           565: 
        !           566:        /* charge it too the socket. */
        !           567:        if (sk->rmem_alloc + skb->mem_len >= SK_RMEM_MAX)
        !           568:          {
        !           569:             skb->sk = NULL;
        !           570:             free_skb (skb, 0);
        !           571:             release_sock (sk);
        !           572:             return (0);
        !           573:          }
        !           574:             
        !           575:        sk->rmem_alloc += skb->mem_len;
        !           576: 
        !           577:        /* At this point we should print the thing out. */
        !           578:        PRINTK ("<< \n");
        !           579:        print_sk (sk);
        !           580: 
        !           581:        /* now add it to the data chain and wake things up. */
        !           582:        if (sk->rqueue == NULL)
        !           583:          {
        !           584:                  sk->rqueue = skb;
        !           585:                  skb->next = skb;
        !           586:                  skb->prev = skb;
        !           587:          }
        !           588:        else
        !           589:          {
        !           590:                  skb->next = sk->rqueue;
        !           591:                  skb->prev = sk->rqueue->prev;
        !           592:                  skb->prev->next = skb;
        !           593:                  skb->next->prev = skb;
        !           594:          }
        !           595: 
        !           596:        skb->len = len - sizeof (*uh);
        !           597: 
        !           598:        if (!sk->dead)
        !           599:          wake_up (sk->sleep);
        !           600: 
        !           601:        release_sock (sk);
        !           602:        return (0);
        !           603: }
        !           604: 
        !           605: 
        !           606: 
        !           607: struct proto udp_prot =
        !           608: {
        !           609:   sock_wmalloc,
        !           610:   sock_rmalloc,
        !           611:   sock_wfree,
        !           612:   sock_rfree,
        !           613:   sock_rspace,
        !           614:   sock_wspace,
        !           615:   udp_close,
        !           616:   udp_read,
        !           617:   udp_write,
        !           618:   udp_sendto,
        !           619:   udp_recvfrom,
        !           620:   ip_build_header,
        !           621:   udp_connect,
        !           622:   NULL,
        !           623:   ip_queue_xmit,
        !           624:   ip_retransmit,
        !           625:   NULL,
        !           626:   NULL,
        !           627:   udp_rcv,
        !           628:   udp_select,
        !           629:   NULL,
        !           630:   NULL,
        !           631:   128,
        !           632:   0,
        !           633:   {NULL,}
        !           634: };
        !           635: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.