Fix 8 space tab formatting for non-C files
[akaros.git] / kern / src / net / udp.c
index 932063e..c3e901b 100644 (file)
-/**
- * Contains shamelessly stolen code from BSD & lwip, both have
- * BSD-style licenses
+/* Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+ * Portions Copyright © 1997-1999 Vita Nuova Limited
+ * Portions Copyright © 2000-2007 Vita Nuova Holdings Limited
+ *                                (www.vitanuova.com)
+ * Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
  *
- */
-#include <ros/common.h>
-#include <string.h>
-#include <kmalloc.h>
-#include <socket.h>
-#include <net.h>
-#include <sys/queue.h> //TODO: use sys/queue.h rather than implementing
-#include <arch/atomic.h>
+ * Modified for the Akaros operating system:
+ * Copyright (c) 2013-2014 The Regents of the University of California
+ * Copyright (c) 2013-2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE. */
 
-#include <bits/netinet.h>
+#define DEBUG
+#include <slab.h>
+#include <kmalloc.h>
+#include <kref.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <error.h>
+#include <cpio.h>
+#include <pmap.h>
+#include <smp.h>
 #include <net/ip.h>
-#include <net/udp.h>
+
 #include <slab.h>
-#include <socket.h>
+#include <kmalloc.h>
+#include <kref.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <error.h>
+#include <cpio.h>
+#include <pmap.h>
+#include <smp.h>
+#include <net/ip.h>
+
+#define DPRINT if(0)print
+
+enum {
+       UDP_UDPHDR_SZ = 8,
+
+       UDP4_PHDR_OFF = 8,
+       UDP4_PHDR_SZ = 12,
+       UDP4_IPHDR_SZ = 20,
+       UDP6_IPHDR_SZ = 40,
+       UDP6_PHDR_SZ = 40,
+       UDP6_PHDR_OFF = 0,
+
+       IP_UDPPROTO = 17,
+       UDP_USEAD7 = 52,
+       UDP_USEAD6 = 36,
+
+       Udprxms = 200,
+       Udptickms = 100,
+       Udpmaxxmit = 10,
+};
+
+typedef struct Udp4hdr Udp4hdr;
+struct Udp4hdr {
+       /* ip header */
+       uint8_t vihl;                   /* Version and header length */
+       uint8_t tos;                    /* Type of service */
+       uint8_t length[2];              /* packet length */
+       uint8_t id[2];                  /* Identification */
+       uint8_t frag[2];                /* Fragment information */
+       uint8_t Unused;
+       uint8_t udpproto;               /* Protocol */
+       uint8_t udpplen[2];             /* Header plus data length */
+       uint8_t udpsrc[IPv4addrlen];    /* Ip source */
+       uint8_t udpdst[IPv4addrlen];    /* Ip destination */
+
+       /* udp header */
+       uint8_t udpsport[2];            /* Source port */
+       uint8_t udpdport[2];            /* Destination port */
+       uint8_t udplen[2];              /* data length */
+       uint8_t udpcksum[2];            /* Checksum */
+};
+
+typedef struct Udp6hdr Udp6hdr;
+struct Udp6hdr {
+       uint8_t viclfl[4];
+       uint8_t len[2];
+       uint8_t nextheader;
+       uint8_t hoplimit;
+       uint8_t udpsrc[IPaddrlen];
+       uint8_t udpdst[IPaddrlen];
+
+       /* udp header */
+       uint8_t udpsport[2];            /* Source port */
+       uint8_t udpdport[2];            /* Destination port */
+       uint8_t udplen[2];              /* data length */
+       uint8_t udpcksum[2];            /* Checksum */
+};
+
+/* MIB II counters */
+typedef struct Udpstats Udpstats;
+struct Udpstats {
+       uint32_t udpInDatagrams;
+       uint32_t udpNoPorts;
+       uint32_t udpInErrors;
+       uint32_t udpOutDatagrams;
+};
+
+typedef struct Udppriv Udppriv;
+struct Udppriv {
+       struct Ipht ht;
+
+       /* MIB counters */
+       Udpstats ustats;
+
+       /* non-MIB stats */
+       uint32_t csumerr;               /* checksum errors */
+       uint32_t lenerr;                /* short packet */
+};
+
+void (*etherprofiler) (char *name, int qlen);
+void udpkick(void *x, struct block *bp);
+
+/*
+ *  protocol specific part of Conv
+ */
+typedef struct Udpcb Udpcb;
+struct Udpcb {
+       uint8_t headers;
+};
+
+static void udpconnect(struct conv *c, char **argv, int argc)
+{
+       Udppriv *upriv;
+
+       upriv = c->p->priv;
+       Fsstdconnect(c, argv, argc);
+       Fsconnected(c, 0);
+
+       iphtadd(&upriv->ht, c);
+}
+
+static void udpbind(struct conv *c, char **argv, int argc)
+{
+       Udppriv *upriv;
+
+       upriv = c->p->priv;
+       Fsstdbind(c, argv, argc);
+       iphtadd(&upriv->ht, c);
+}
+
+static int udpstate(struct conv *c, char *state, int n)
+{
+       return snprintf(state, n, "%s qin %d qout %d\n",
+                       c->inuse ? "Open" : "Closed",
+                       c->rq ? qlen(c->rq) : 0, c->wq ? qlen(c->wq) : 0);
+}
+
+static void udpannounce(struct conv *c, char **argv, int argc)
+{
+       Udppriv *upriv;
+
+       upriv = c->p->priv;
+       Fsstdannounce(c, argv, argc);
+       Fsconnected(c, NULL);
+       iphtadd(&upriv->ht, c);
+}
+
+static void udpbypass(struct conv *cv, char **argv, int argc)
+{
+       Udppriv *upriv = cv->p->priv;
+
+       Fsstdbypass(cv, argv, argc);
+       iphtadd(&upriv->ht, cv);
+}
+
+static void udpcreate(struct conv *c)
+{
+       c->rq = qopen(128 * 1024, Qmsg, 0, 0);
+       c->wq = qbypass(udpkick, c);
+}
+
+static void udpclose(struct conv *c)
+{
+       Udpcb *ucb;
+       Udppriv *upriv;
+
+       upriv = c->p->priv;
+       iphtrem(&upriv->ht, c);
 
-struct udp_pcb *udp_pcbs;
-uint16_t udp_port_num = SOCKET_PORT_START;
+       c->state = 0;
+       qclose(c->rq);
+       qclose(c->wq);
+       qclose(c->eq);
+       ipmove(c->laddr, IPnoaddr);
+       ipmove(c->raddr, IPnoaddr);
+       c->lport = 0;
+       c->rport = 0;
 
+       ucb = (Udpcb *) c->ptcl;
+       ucb->headers = 0;
 
-struct udp_pcb* udp_new(void){
-       struct udp_pcb *pcb = kmem_cache_alloc(udp_pcb_kcache, 0);
-    // if pcb is only tracking ttl, then no need!
-       if (pcb!= NULL){
-               pcb->ttl = UDP_TTL;
-       memset(pcb, 0, sizeof(struct udp_pcb));
+       qunlock(&c->qlock);
+}
+
+void udpkick(void *x, struct block *bp)
+{
+       struct conv *c = x;
+       Udp4hdr *uh4;
+       Udp6hdr *uh6;
+       uint16_t rport;
+       uint8_t laddr[IPaddrlen], raddr[IPaddrlen];
+       Udpcb *ucb;
+       int dlen, ptcllen;
+       Udppriv *upriv;
+       struct Fs *f;
+       int version;
+       struct conv *rc;
+
+       upriv = c->p->priv;
+       assert(upriv);
+       f = c->p->f;
+
+       netlog(c->p->f, Logudp, "udp: kick\n");
+       if (bp == NULL)
+               return;
+
+       ucb = (Udpcb *) c->ptcl;
+       switch (ucb->headers) {
+       case 7:
+               /* get user specified addresses */
+               bp = pullupblock(bp, UDP_USEAD7);
+               if (bp == NULL)
+                       return;
+               ipmove(raddr, bp->rp);
+               bp->rp += IPaddrlen;
+               ipmove(laddr, bp->rp);
+               bp->rp += IPaddrlen;
+               /* pick interface closest to dest */
+               if (ipforme(f, laddr) != Runi)
+                       findlocalip(f, laddr, raddr);
+               bp->rp += IPaddrlen;    /* Ignore ifc address */
+               rport = nhgets(bp->rp);
+               bp->rp += 2 + 2;        /* Ignore local port */
+               break;
+       case 6:
+               /* get user specified addresses */
+               bp = pullupblock(bp, UDP_USEAD6);
+               if (bp == NULL)
+                       return;
+               ipmove(raddr, bp->rp);
+               bp->rp += IPaddrlen;
+               ipmove(laddr, bp->rp);
+               bp->rp += IPaddrlen;
+               /* pick interface closest to dest */
+               if (ipforme(f, laddr) != Runi)
+                       findlocalip(f, laddr, raddr);
+               rport = nhgets(bp->rp);
+               bp->rp += 2 + 2;        /* Ignore local port */
+               break;
+       default:
+               rport = 0;
+               break;
+       }
+
+       if (ucb->headers) {
+               if (memcmp(laddr, v4prefix, IPv4off) == 0 ||
+                       ipcmp(laddr, IPnoaddr) == 0)
+                       version = V4;
+               else
+                       version = V6;
+       } else {
+               if ((memcmp(c->raddr, v4prefix, IPv4off) == 0 &&
+                        memcmp(c->laddr, v4prefix, IPv4off) == 0)
+                       || ipcmp(c->raddr, IPnoaddr) == 0)
+                       version = V4;
+               else
+                       version = V6;
+       }
+
+       dlen = blocklen(bp);
+
+       /* fill in pseudo header and compute checksum */
+       switch (version) {
+       case V4:
+               bp = padblock(bp, UDP4_IPHDR_SZ + UDP_UDPHDR_SZ);
+               if (bp == NULL)
+                       return;
+
+               uh4 = (Udp4hdr *) (bp->rp);
+               ptcllen = dlen + UDP_UDPHDR_SZ;
+               uh4->Unused = 0;
+               uh4->udpproto = IP_UDPPROTO;
+               uh4->frag[0] = 0;
+               uh4->frag[1] = 0;
+               hnputs(uh4->udpplen, ptcllen);
+               if (ucb->headers) {
+                       v6tov4(uh4->udpdst, raddr);
+                       hnputs(uh4->udpdport, rport);
+                       v6tov4(uh4->udpsrc, laddr);
+                       rc = NULL;
+               } else {
+                       v6tov4(uh4->udpdst, c->raddr);
+                       hnputs(uh4->udpdport, c->rport);
+                       if (ipcmp(c->laddr, IPnoaddr) == 0)
+                               findlocalip(f, c->laddr, c->raddr);
+                       v6tov4(uh4->udpsrc, c->laddr);
+                       rc = c;
+               }
+               hnputs(uh4->udpsport, c->lport);
+               hnputs(uh4->udplen, ptcllen);
+               uh4->udpcksum[0] = 0;
+               uh4->udpcksum[1] = 0;
+               bp->network_offset = 0;
+               bp->transport_offset = offsetof(Udp4hdr, udpsport);
+               assert(bp->transport_offset == UDP4_IPHDR_SZ);
+               hnputs(uh4->udpcksum,
+                          ~ptclcsum(bp, UDP4_PHDR_OFF, UDP4_PHDR_SZ));
+               bp->tx_csum_offset = uh4->udpcksum - uh4->udpsport;
+               bp->flag |= Budpck;
+               uh4->vihl = IP_VER4;
+               ipoput4(f, bp, 0, c->ttl, c->tos, rc);
+               break;
+
+       case V6:
+               bp = padblock(bp, UDP6_IPHDR_SZ + UDP_UDPHDR_SZ);
+               if (bp == NULL)
+                       return;
+
+               // using the v6 ip header to create pseudo header
+               // first then reset it to the normal ip header
+               uh6 = (Udp6hdr *) (bp->rp);
+               memset(uh6, 0, 8);
+               ptcllen = dlen + UDP_UDPHDR_SZ;
+               hnputl(uh6->viclfl, ptcllen);
+               uh6->hoplimit = IP_UDPPROTO;
+               if (ucb->headers) {
+                       ipmove(uh6->udpdst, raddr);
+                       hnputs(uh6->udpdport, rport);
+                       ipmove(uh6->udpsrc, laddr);
+                       rc = NULL;
+               } else {
+                       ipmove(uh6->udpdst, c->raddr);
+                       hnputs(uh6->udpdport, c->rport);
+                       if (ipcmp(c->laddr, IPnoaddr) == 0)
+                               findlocalip(f, c->laddr, c->raddr);
+                       ipmove(uh6->udpsrc, c->laddr);
+                       rc = c;
+               }
+               hnputs(uh6->udpsport, c->lport);
+               hnputs(uh6->udplen, ptcllen);
+               uh6->udpcksum[0] = 0;
+               uh6->udpcksum[1] = 0;
+               hnputs(uh6->udpcksum,
+                          ptclcsum(bp, UDP6_PHDR_OFF, dlen + UDP_UDPHDR_SZ +
+                                   UDP6_PHDR_SZ));
+               memset(uh6, 0, 8);
+               bp->network_offset = 0;
+               bp->transport_offset = offsetof(Udp6hdr, udpsport);
+               uh6->viclfl[0] = IP_VER6;
+               hnputs(uh6->len, ptcllen);
+               uh6->nextheader = IP_UDPPROTO;
+               ipoput6(f, bp, 0, c->ttl, c->tos, rc);
+               break;
+
+       default:
+               panic("udpkick: version %d", version);
        }
-       return pcb;
+       upriv->ustats.udpOutDatagrams++;
 }
 
-int udp_send(struct udp_pcb *pcb, struct pbuf *p)
+void udpiput(struct Proto *udp, struct Ipifc *ifc, struct block *bp)
 {
-  /* send to the packet using remote ip and port stored in the pcb */
-  // rip and rport should be in socket not pcb?
-  return udp_sendto(pcb, p, &pcb->remote_ip, pcb->remote_port);
+       int len;
+       Udp4hdr *uh4;
+       Udp6hdr *uh6;
+       struct conv *c;
+       Udpcb *ucb;
+       uint8_t raddr[IPaddrlen], laddr[IPaddrlen];
+       uint16_t rport, lport;
+       Udppriv *upriv;
+       struct Fs *f;
+       int version;
+       int ottl, oviclfl, olen;
+       uint8_t *p;
+
+       upriv = udp->priv;
+       f = udp->f;
+       upriv->ustats.udpInDatagrams++;
+
+       uh4 = (Udp4hdr *) (bp->rp);
+       version = ((uh4->vihl & 0xF0) == IP_VER6) ? V6 : V4;
+
+       /*
+        * Put back pseudo header for checksum
+        * (remember old values for icmpnoconv())
+        */
+       switch (version) {
+       case V4:
+               ottl = uh4->Unused;
+               uh4->Unused = 0;
+               len = nhgets(uh4->udplen);
+               olen = nhgets(uh4->udpplen);
+               hnputs(uh4->udpplen, len);
+
+               v4tov6(raddr, uh4->udpsrc);
+               v4tov6(laddr, uh4->udpdst);
+               lport = nhgets(uh4->udpdport);
+               rport = nhgets(uh4->udpsport);
+
+               if (!(bp->flag & Budpck) &&
+                   (uh4->udpcksum[0] || uh4->udpcksum[1]) &&
+                   ptclcsum(bp, UDP4_PHDR_OFF, len + UDP4_PHDR_SZ)) {
+                       upriv->ustats.udpInErrors++;
+                       netlog(f, Logudp, "udp: checksum error %I\n",
+                              raddr);
+                       printd("udp: checksum error %I\n", raddr);
+                       freeblist(bp);
+                       return;
+               }
+               uh4->Unused = ottl;
+               hnputs(uh4->udpplen, olen);
+               break;
+       case V6:
+               uh6 = (Udp6hdr *) (bp->rp);
+               len = nhgets(uh6->udplen);
+               oviclfl = nhgetl(uh6->viclfl);
+               olen = nhgets(uh6->len);
+               ottl = uh6->hoplimit;
+               ipmove(raddr, uh6->udpsrc);
+               ipmove(laddr, uh6->udpdst);
+               lport = nhgets(uh6->udpdport);
+               rport = nhgets(uh6->udpsport);
+               memset(uh6, 0, 8);
+               hnputl(uh6->viclfl, len);
+               uh6->hoplimit = IP_UDPPROTO;
+               if (ptclcsum(bp, UDP6_PHDR_OFF, len + UDP6_PHDR_SZ)) {
+                       upriv->ustats.udpInErrors++;
+                       netlog(f, Logudp, "udp: checksum error %I\n", raddr);
+                       printd("udp: checksum error %I\n", raddr);
+                       freeblist(bp);
+                       return;
+               }
+               hnputl(uh6->viclfl, oviclfl);
+               hnputs(uh6->len, olen);
+               uh6->nextheader = IP_UDPPROTO;
+               uh6->hoplimit = ottl;
+               break;
+       default:
+               panic("udpiput: version %d", version);
+               return; /* to avoid a warning */
+       }
+
+       c = iphtlook(&upriv->ht, raddr, rport, laddr, lport);
+       if (c == NULL) {
+               /* no converstation found */
+               upriv->ustats.udpNoPorts++;
+               netlog(f, Logudp, "udp: no conv %I!%d -> %I!%d\n", raddr, rport,
+                          laddr, lport);
+
+               switch (version) {
+               case V4:
+                       icmpnoconv(f, bp);
+                       break;
+               case V6:
+                       icmphostunr(f, ifc, bp, icmp6_port_unreach, 0);
+                       break;
+               default:
+                       panic("udpiput2: version %d", version);
+               }
+
+               freeblist(bp);
+               return;
+       }
+
+       if (c->state == Bypass) {
+               bypass_or_drop(c, bp);
+               return;
+       }
+
+       ucb = (Udpcb *) c->ptcl;
+
+       if (c->state == Announced) {
+               if (ucb->headers == 0) {
+                       /* create a new conversation */
+                       if (ipforme(f, laddr) != Runi) {
+                               switch (version) {
+                               case V4:
+                                       v4tov6(laddr, ifc->lifc->local);
+                                       break;
+                               case V6:
+                                       ipmove(laddr, ifc->lifc->local);
+                                       break;
+                               default:
+                                       panic("udpiput3: version %d", version);
+                               }
+                       }
+                       qlock(&udp->qlock);
+                       c = Fsnewcall(c, raddr, rport, laddr, lport, version);
+                       qunlock(&udp->qlock);
+                       if (c == NULL) {
+                               freeblist(bp);
+                               return;
+                       }
+                       iphtadd(&upriv->ht, c);
+                       ucb = (Udpcb *) c->ptcl;
+               }
+       }
+
+       qlock(&c->qlock);
+
+       /*
+        * Trim the packet down to data size
+        */
+       len -= UDP_UDPHDR_SZ;
+       switch (version) {
+       case V4:
+               bp = trimblock(bp, UDP4_IPHDR_SZ + UDP_UDPHDR_SZ, len);
+               break;
+       case V6:
+               bp = trimblock(bp, UDP6_IPHDR_SZ + UDP_UDPHDR_SZ, len);
+               break;
+       default:
+               bp = NULL;
+               panic("udpiput4: version %d", version);
+       }
+       if (bp == NULL) {
+               qunlock(&c->qlock);
+               netlog(f, Logudp, "udp: len err %I.%d -> %I.%d\n", raddr, rport,
+                          laddr, lport);
+               upriv->lenerr++;
+               return;
+       }
+
+       netlog(f, Logudpmsg, "udp: %I.%d -> %I.%d l %d\n", raddr, rport,
+                  laddr, lport, len);
+
+       switch (ucb->headers) {
+       case 7:
+               /* pass the src address */
+               bp = padblock(bp, UDP_USEAD7);
+               p = bp->rp;
+               ipmove(p, raddr);
+               p += IPaddrlen;
+               ipmove(p, laddr);
+               p += IPaddrlen;
+               ipmove(p, ifc->lifc->local);
+               p += IPaddrlen;
+               hnputs(p, rport);
+               p += 2;
+               hnputs(p, lport);
+               break;
+       case 6:
+               /* pass the src address */
+               bp = padblock(bp, UDP_USEAD6);
+               p = bp->rp;
+               ipmove(p, raddr);
+               p += IPaddrlen;
+               ipmove(p, ipforme(f, laddr) == Runi ? laddr : ifc->lifc->local);
+               p += IPaddrlen;
+               hnputs(p, rport);
+               p += 2;
+               hnputs(p, lport);
+               break;
+       }
+
+       if (bp->next)
+               bp = concatblock(bp);
+
+       if (qfull(c->rq)) {
+               qunlock(&c->qlock);
+               netlog(f, Logudp, "udp: qfull %I.%d -> %I.%d\n", raddr, rport,
+                          laddr, lport);
+               freeblist(bp);
+               return;
+       }
+
+       qpass(c->rq, bp);
+       qunlock(&c->qlock);
+
 }
 
+static void udpctl(struct conv *c, char **f, int n)
+{
+       Udpcb *ucb = (Udpcb*)c->ptcl;
 
-int udp_sendto(struct udp_pcb *pcb, struct pbuf *p,
-                    struct in_addr *dst_ip, uint16_t dst_port){
-    // we now have one netif to send to, otherwise we need to route
-    // ip_route();
-    struct udp_hdr *udphdr;
-    struct pbuf *q;
-               /* TODO: utility to peform inet_ntop and        inet_pton for debugging*/
-               printd("udp_sendto ip %x, port %d\n", dst_ip->s_addr, dst_port); 
-    // broadcast?
-    if (pcb->local_port == 0) {
-                               /* if the PCB not bound to a port, bind it and give local ip */
-        if (udp_bind(pcb, &pcb->local_ip, pcb->local_port)!=0)
-                                       warn("udp binding failed \n");
-    }
-    if (pbuf_header(p, UDP_HLEN)){ // we could probably save this check for block.
-        // CHECK: should allocate enough for the other headers too
-        q = pbuf_alloc(PBUF_IP, UDP_HLEN, PBUF_RAM);
-        if (q == NULL)
-           panic("out of memory");
-        // if the original packet is not empty
-        if (p->tot_len !=0) {
-            pbuf_chain(q,p);
-            // check if it is chained properly ..
-        }
-    } else {
-                               /* Successfully padded the header*/
-                               q = p;
-    }
-    udphdr = (struct udp_hdr *) q->payload;
-               printd("src port %x, dst port %x \n, length %x ", pcb->local_port, dst_port, q->tot_len);
-    udphdr->src_port = htons(pcb->local_port);
-    udphdr->dst_port = (dst_port);
-    udphdr->checksum = 0x0000; //either use brho's checksum or use cards' capabilities
-    udphdr->length = htons(q->tot_len); // 630
-               // ip_output(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDP);
-               ip_output(q, &global_ip, dst_ip, IPPROTO_UDP);
-
-    return 0;
-
-    // generate checksum if we need it.. check net.c
-    //src_ip = GLOBAL_IP;
-    // ip_output(blah);
-
-    // check if there is space to operate in place (likely not)
-    // allocate additional pbuf
-    // chain the two bufs together
-    // add udp headers
-    // call ip layer
-
-    // checksum calculation?
+       if ((n == 1) && strcmp(f[0], "oldheaders") == 0)
+               ucb->headers = 6;
+       else if ((n == 1) && strcmp(f[0], "headers") == 0)
+               ucb->headers = 7;
+       else
+               error(EINVAL, "unknown command to %s", __func__);
 }
-/* TODO: use the real queues we have implemented... */
-int udp_bind(struct udp_pcb *pcb, struct in_addr *ip, uint16_t port){ 
-    int rebind = pcb->local_port;
-    struct udp_pcb *ipcb;
-               assert(pcb);
-               /* trying to assign port */
-    if (port != 0)
-        pcb->local_port = port;
-
-    /* no lock needed since we are just traversing/reading */
-    /* Check for double bind and rebind of the same pcb */
-    for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) {
-        /* is this UDP PCB already on active list? */
-        if (pcb == ipcb) {
-            rebind = 1; //already on the list
-        } else if (ipcb->local_port == port){
-            warn("someone else is using the port %d\n" , port); 
-            return -1;
-        }
-    }
-    /* accept data for all interfaces */
-    if (ip == NULL || (ip->s_addr == INADDR_ANY.s_addr))
-        pcb->local_ip = INADDR_ANY;
-    /* assign a port */
-    if (port == 0) {
-        port = SOCKET_PORT_START; 
-        ipcb = udp_pcbs;
-        while ((ipcb != NULL) && (port != SOCKET_PORT_END)) {
-            if (ipcb->local_port == port) {
-                /* port is already used by another udp_pcb */
-                port++;
-                /* restart scanning all udp pcbs */
-                ipcb = udp_pcbs;
-            } else {
-                /* go on with next udp pcb */
-                ipcb = ipcb->next;
-            }
-        }
-        if (ipcb != NULL){
-            warn("No more udp ports available!");
-        }
-    }
-    if (rebind == 0) {
-        /* place the PCB on the active list if not already there */
-                               pcb->next = udp_pcbs;
-                               udp_pcbs = pcb;
-    }
-               printk("local port bound to 0x%x \n", port);
-    pcb->local_port = port;
-    return 0;
+
+void udpadvise(struct Proto *udp, struct block *bp, char *msg)
+{
+       Udp4hdr *h4;
+       Udp6hdr *h6;
+       uint8_t source[IPaddrlen], dest[IPaddrlen];
+       uint16_t psource, pdest;
+       struct conv *s, **p;
+       int version;
+
+       h4 = (Udp4hdr *) (bp->rp);
+       version = ((h4->vihl & 0xF0) == IP_VER6) ? V6 : V4;
+
+       switch (version) {
+       case V4:
+               v4tov6(dest, h4->udpdst);
+               v4tov6(source, h4->udpsrc);
+               psource = nhgets(h4->udpsport);
+               pdest = nhgets(h4->udpdport);
+               break;
+       case V6:
+               h6 = (Udp6hdr *) (bp->rp);
+               ipmove(dest, h6->udpdst);
+               ipmove(source, h6->udpsrc);
+               psource = nhgets(h6->udpsport);
+               pdest = nhgets(h6->udpdport);
+               break;
+       default:
+               panic("udpadvise: version %d", version);
+               return; /* to avoid a warning */
+       }
+
+       /* Look for a connection */
+       for (p = udp->conv; *p; p++) {
+               s = *p;
+               if (s->rport == pdest)
+                       if (s->lport == psource)
+                               if (ipcmp(s->raddr, dest) == 0)
+                                       if (ipcmp(s->laddr, source) == 0) {
+                                               if (s->ignoreadvice)
+                                                       break;
+                                               qlock(&s->qlock);
+                                               qhangup(s->rq, msg);
+                                               qhangup(s->wq, msg);
+                                               qunlock(&s->qlock);
+                                               freeblist(bp);
+                                               return;
+                                       }
+       }
+       freeblist(bp);
 }
 
+int udpstats(struct Proto *udp, char *buf, int len)
+{
+       Udppriv *upriv;
+       char *p, *e;
+
+       upriv = udp->priv;
+       p = buf;
+       e = p + len;
+       p = seprintf(p, e, "InDatagrams: %u\n", upriv->ustats.udpInDatagrams);
+       p = seprintf(p, e, "NoPorts: %u\n", upriv->ustats.udpNoPorts);
+       p = seprintf(p, e, "InErrors: %u\n", upriv->ustats.udpInErrors);
+       p = seprintf(p, e, "OutDatagrams: %u\n", upriv->ustats.udpOutDatagrams);
+       return p - buf;
+}
 
+void udpinit(struct Fs *fs)
+{
+       struct Proto *udp;
 
+       udp = kzmalloc(sizeof(struct Proto), 0);
+       udp->priv = kzmalloc(sizeof(Udppriv), 0);
+       udp->name = "udp";
+       udp->connect = udpconnect;
+       udp->bind = udpbind;
+       udp->announce = udpannounce;
+       udp->bypass = udpbypass;
+       udp->ctl = udpctl;
+       udp->state = udpstate;
+       udp->create = udpcreate;
+       udp->close = udpclose;
+       udp->rcv = udpiput;
+       udp->advise = udpadvise;
+       udp->stats = udpstats;
+       udp->ipproto = IP_UDPPROTO;
+       udp->nc = 4096;
+       udp->ptclsize = sizeof(Udpcb);
 
+       Fsproto(fs, udp);
+}