akaros/kern/src/net/udp.c
<<
>>
Prefs
   1/* Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
   2 * Portions Copyright © 1997-1999 Vita Nuova Limited
   3 * Portions Copyright © 2000-2007 Vita Nuova Holdings Limited
   4 *                                (www.vitanuova.com)
   5 * Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
   6 *
   7 * Modified for the Akaros operating system:
   8 * Copyright (c) 2013-2014 The Regents of the University of California
   9 * Copyright (c) 2013-2015 Google Inc.
  10 *
  11 * Permission is hereby granted, free of charge, to any person obtaining a copy
  12 * of this software and associated documentation files (the "Software"), to deal
  13 * in the Software without restriction, including without limitation the rights
  14 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  15 * copies of the Software, and to permit persons to whom the Software is
  16 * furnished to do so, subject to the following conditions:
  17 *
  18 * The above copyright notice and this permission notice shall be included in
  19 * all copies or substantial portions of the Software.
  20 *
  21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
  24 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  26 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  27 * SOFTWARE. */
  28
  29#define DEBUG
  30#include <slab.h>
  31#include <kmalloc.h>
  32#include <kref.h>
  33#include <string.h>
  34#include <stdio.h>
  35#include <assert.h>
  36#include <error.h>
  37#include <cpio.h>
  38#include <pmap.h>
  39#include <smp.h>
  40#include <net/ip.h>
  41
  42#include <slab.h>
  43#include <kmalloc.h>
  44#include <kref.h>
  45#include <string.h>
  46#include <stdio.h>
  47#include <assert.h>
  48#include <error.h>
  49#include <cpio.h>
  50#include <pmap.h>
  51#include <smp.h>
  52#include <net/ip.h>
  53
  54#define DPRINT if(0)print
  55
  56enum {
  57        UDP_UDPHDR_SZ = 8,
  58
  59        UDP4_PHDR_OFF = 8,
  60        UDP4_PHDR_SZ = 12,
  61        UDP4_IPHDR_SZ = 20,
  62        UDP6_IPHDR_SZ = 40,
  63        UDP6_PHDR_SZ = 40,
  64        UDP6_PHDR_OFF = 0,
  65
  66        IP_UDPPROTO = 17,
  67        UDP_USEAD7 = 52,
  68        UDP_USEAD6 = 36,
  69
  70        Udprxms = 200,
  71        Udptickms = 100,
  72        Udpmaxxmit = 10,
  73};
  74
  75typedef struct Udp4hdr Udp4hdr;
  76struct Udp4hdr {
  77        /* ip header */
  78        uint8_t vihl;                   /* Version and header length */
  79        uint8_t tos;                    /* Type of service */
  80        uint8_t length[2];              /* packet length */
  81        uint8_t id[2];                  /* Identification */
  82        uint8_t frag[2];                /* Fragment information */
  83        uint8_t Unused;
  84        uint8_t udpproto;               /* Protocol */
  85        uint8_t udpplen[2];             /* Header plus data length */
  86        uint8_t udpsrc[IPv4addrlen];    /* Ip source */
  87        uint8_t udpdst[IPv4addrlen];    /* Ip destination */
  88
  89        /* udp header */
  90        uint8_t udpsport[2];            /* Source port */
  91        uint8_t udpdport[2];            /* Destination port */
  92        uint8_t udplen[2];              /* data length */
  93        uint8_t udpcksum[2];            /* Checksum */
  94};
  95
  96typedef struct Udp6hdr Udp6hdr;
  97struct Udp6hdr {
  98        uint8_t viclfl[4];
  99        uint8_t len[2];
 100        uint8_t nextheader;
 101        uint8_t hoplimit;
 102        uint8_t udpsrc[IPaddrlen];
 103        uint8_t udpdst[IPaddrlen];
 104
 105        /* udp header */
 106        uint8_t udpsport[2];            /* Source port */
 107        uint8_t udpdport[2];            /* Destination port */
 108        uint8_t udplen[2];              /* data length */
 109        uint8_t udpcksum[2];            /* Checksum */
 110};
 111
 112/* MIB II counters */
 113typedef struct Udpstats Udpstats;
 114struct Udpstats {
 115        uint32_t udpInDatagrams;
 116        uint32_t udpNoPorts;
 117        uint32_t udpInErrors;
 118        uint32_t udpOutDatagrams;
 119};
 120
 121typedef struct Udppriv Udppriv;
 122struct Udppriv {
 123        struct Ipht ht;
 124
 125        /* MIB counters */
 126        Udpstats ustats;
 127
 128        /* non-MIB stats */
 129        uint32_t csumerr;               /* checksum errors */
 130        uint32_t lenerr;                /* short packet */
 131};
 132
 133void (*etherprofiler) (char *name, int qlen);
 134void udpkick(void *x, struct block *bp);
 135
 136/*
 137 *  protocol specific part of Conv
 138 */
 139typedef struct Udpcb Udpcb;
 140struct Udpcb {
 141        uint8_t headers;
 142};
 143
 144static void udpconnect(struct conv *c, char **argv, int argc)
 145{
 146        Udppriv *upriv;
 147
 148        upriv = c->p->priv;
 149        Fsstdconnect(c, argv, argc);
 150        Fsconnected(c, 0);
 151
 152        iphtadd(&upriv->ht, c);
 153}
 154
 155static void udpbind(struct conv *c, char **argv, int argc)
 156{
 157        Udppriv *upriv;
 158
 159        upriv = c->p->priv;
 160        Fsstdbind(c, argv, argc);
 161        iphtadd(&upriv->ht, c);
 162}
 163
 164static int udpstate(struct conv *c, char *state, int n)
 165{
 166        return snprintf(state, n, "%s qin %d qout %d\n",
 167                        c->inuse ? "Open" : "Closed",
 168                        c->rq ? qlen(c->rq) : 0, c->wq ? qlen(c->wq) : 0);
 169}
 170
 171static void udpannounce(struct conv *c, char **argv, int argc)
 172{
 173        Udppriv *upriv;
 174
 175        upriv = c->p->priv;
 176        Fsstdannounce(c, argv, argc);
 177        Fsconnected(c, NULL);
 178        iphtadd(&upriv->ht, c);
 179}
 180
 181static void udpbypass(struct conv *cv, char **argv, int argc)
 182{
 183        Udppriv *upriv = cv->p->priv;
 184
 185        Fsstdbypass(cv, argv, argc);
 186        iphtadd(&upriv->ht, cv);
 187}
 188
 189static void udpcreate(struct conv *c)
 190{
 191        c->rq = qopen(128 * 1024, Qmsg, 0, 0);
 192        c->wq = qbypass(udpkick, c);
 193}
 194
 195static void udpclose(struct conv *c)
 196{
 197        Udpcb *ucb;
 198        Udppriv *upriv;
 199
 200        upriv = c->p->priv;
 201        iphtrem(&upriv->ht, c);
 202
 203        c->state = 0;
 204        qclose(c->rq);
 205        qclose(c->wq);
 206        qclose(c->eq);
 207        ipmove(c->laddr, IPnoaddr);
 208        ipmove(c->raddr, IPnoaddr);
 209        c->lport = 0;
 210        c->rport = 0;
 211
 212        ucb = (Udpcb *) c->ptcl;
 213        ucb->headers = 0;
 214
 215        qunlock(&c->qlock);
 216}
 217
 218void udpkick(void *x, struct block *bp)
 219{
 220        struct conv *c = x;
 221        Udp4hdr *uh4;
 222        Udp6hdr *uh6;
 223        uint16_t rport;
 224        uint8_t laddr[IPaddrlen], raddr[IPaddrlen];
 225        Udpcb *ucb;
 226        int dlen, ptcllen;
 227        Udppriv *upriv;
 228        struct Fs *f;
 229        int version;
 230        struct conv *rc;
 231
 232        upriv = c->p->priv;
 233        assert(upriv);
 234        f = c->p->f;
 235
 236        netlog(c->p->f, Logudp, "udp: kick\n");
 237        if (bp == NULL)
 238                return;
 239
 240        ucb = (Udpcb *) c->ptcl;
 241        switch (ucb->headers) {
 242        case 7:
 243                /* get user specified addresses */
 244                bp = pullupblock(bp, UDP_USEAD7);
 245                if (bp == NULL)
 246                        return;
 247                ipmove(raddr, bp->rp);
 248                bp->rp += IPaddrlen;
 249                ipmove(laddr, bp->rp);
 250                bp->rp += IPaddrlen;
 251                /* pick interface closest to dest */
 252                if (ipforme(f, laddr) != Runi)
 253                        findlocalip(f, laddr, raddr);
 254                bp->rp += IPaddrlen;    /* Ignore ifc address */
 255                rport = nhgets(bp->rp);
 256                bp->rp += 2 + 2;        /* Ignore local port */
 257                break;
 258        case 6:
 259                /* get user specified addresses */
 260                bp = pullupblock(bp, UDP_USEAD6);
 261                if (bp == NULL)
 262                        return;
 263                ipmove(raddr, bp->rp);
 264                bp->rp += IPaddrlen;
 265                ipmove(laddr, bp->rp);
 266                bp->rp += IPaddrlen;
 267                /* pick interface closest to dest */
 268                if (ipforme(f, laddr) != Runi)
 269                        findlocalip(f, laddr, raddr);
 270                rport = nhgets(bp->rp);
 271                bp->rp += 2 + 2;        /* Ignore local port */
 272                break;
 273        default:
 274                rport = 0;
 275                break;
 276        }
 277
 278        if (ucb->headers) {
 279                if (memcmp(laddr, v4prefix, IPv4off) == 0 ||
 280                        ipcmp(laddr, IPnoaddr) == 0)
 281                        version = V4;
 282                else
 283                        version = V6;
 284        } else {
 285                if ((memcmp(c->raddr, v4prefix, IPv4off) == 0 &&
 286                         memcmp(c->laddr, v4prefix, IPv4off) == 0)
 287                        || ipcmp(c->raddr, IPnoaddr) == 0)
 288                        version = V4;
 289                else
 290                        version = V6;
 291        }
 292
 293        dlen = blocklen(bp);
 294
 295        /* fill in pseudo header and compute checksum */
 296        switch (version) {
 297        case V4:
 298                bp = padblock(bp, UDP4_IPHDR_SZ + UDP_UDPHDR_SZ);
 299                if (bp == NULL)
 300                        return;
 301
 302                uh4 = (Udp4hdr *) (bp->rp);
 303                ptcllen = dlen + UDP_UDPHDR_SZ;
 304                uh4->Unused = 0;
 305                uh4->udpproto = IP_UDPPROTO;
 306                uh4->frag[0] = 0;
 307                uh4->frag[1] = 0;
 308                hnputs(uh4->udpplen, ptcllen);
 309                if (ucb->headers) {
 310                        v6tov4(uh4->udpdst, raddr);
 311                        hnputs(uh4->udpdport, rport);
 312                        v6tov4(uh4->udpsrc, laddr);
 313                        rc = NULL;
 314                } else {
 315                        v6tov4(uh4->udpdst, c->raddr);
 316                        hnputs(uh4->udpdport, c->rport);
 317                        if (ipcmp(c->laddr, IPnoaddr) == 0)
 318                                findlocalip(f, c->laddr, c->raddr);
 319                        v6tov4(uh4->udpsrc, c->laddr);
 320                        rc = c;
 321                }
 322                hnputs(uh4->udpsport, c->lport);
 323                hnputs(uh4->udplen, ptcllen);
 324                uh4->udpcksum[0] = 0;
 325                uh4->udpcksum[1] = 0;
 326                bp->network_offset = 0;
 327                bp->transport_offset = offsetof(Udp4hdr, udpsport);
 328                assert(bp->transport_offset == UDP4_IPHDR_SZ);
 329                hnputs(uh4->udpcksum,
 330                           ~ptclcsum(bp, UDP4_PHDR_OFF, UDP4_PHDR_SZ));
 331                bp->tx_csum_offset = uh4->udpcksum - uh4->udpsport;
 332                bp->flag |= Budpck;
 333                uh4->vihl = IP_VER4;
 334                ipoput4(f, bp, 0, c->ttl, c->tos, rc);
 335                break;
 336
 337        case V6:
 338                bp = padblock(bp, UDP6_IPHDR_SZ + UDP_UDPHDR_SZ);
 339                if (bp == NULL)
 340                        return;
 341
 342                // using the v6 ip header to create pseudo header
 343                // first then reset it to the normal ip header
 344                uh6 = (Udp6hdr *) (bp->rp);
 345                memset(uh6, 0, 8);
 346                ptcllen = dlen + UDP_UDPHDR_SZ;
 347                hnputl(uh6->viclfl, ptcllen);
 348                uh6->hoplimit = IP_UDPPROTO;
 349                if (ucb->headers) {
 350                        ipmove(uh6->udpdst, raddr);
 351                        hnputs(uh6->udpdport, rport);
 352                        ipmove(uh6->udpsrc, laddr);
 353                        rc = NULL;
 354                } else {
 355                        ipmove(uh6->udpdst, c->raddr);
 356                        hnputs(uh6->udpdport, c->rport);
 357                        if (ipcmp(c->laddr, IPnoaddr) == 0)
 358                                findlocalip(f, c->laddr, c->raddr);
 359                        ipmove(uh6->udpsrc, c->laddr);
 360                        rc = c;
 361                }
 362                hnputs(uh6->udpsport, c->lport);
 363                hnputs(uh6->udplen, ptcllen);
 364                uh6->udpcksum[0] = 0;
 365                uh6->udpcksum[1] = 0;
 366                hnputs(uh6->udpcksum,
 367                           ptclcsum(bp, UDP6_PHDR_OFF, dlen + UDP_UDPHDR_SZ +
 368                                    UDP6_PHDR_SZ));
 369                memset(uh6, 0, 8);
 370                bp->network_offset = 0;
 371                bp->transport_offset = offsetof(Udp6hdr, udpsport);
 372                uh6->viclfl[0] = IP_VER6;
 373                hnputs(uh6->len, ptcllen);
 374                uh6->nextheader = IP_UDPPROTO;
 375                ipoput6(f, bp, 0, c->ttl, c->tos, rc);
 376                break;
 377
 378        default:
 379                panic("udpkick: version %d", version);
 380        }
 381        upriv->ustats.udpOutDatagrams++;
 382}
 383
 384void udpiput(struct Proto *udp, struct Ipifc *ifc, struct block *bp)
 385{
 386        int len;
 387        Udp4hdr *uh4;
 388        Udp6hdr *uh6;
 389        struct conv *c;
 390        Udpcb *ucb;
 391        uint8_t raddr[IPaddrlen], laddr[IPaddrlen];
 392        uint16_t rport, lport;
 393        Udppriv *upriv;
 394        struct Fs *f;
 395        int version;
 396        int ottl, oviclfl, olen;
 397        uint8_t *p;
 398
 399        upriv = udp->priv;
 400        f = udp->f;
 401        upriv->ustats.udpInDatagrams++;
 402
 403        uh4 = (Udp4hdr *) (bp->rp);
 404        version = ((uh4->vihl & 0xF0) == IP_VER6) ? V6 : V4;
 405
 406        /*
 407         * Put back pseudo header for checksum
 408         * (remember old values for icmpnoconv())
 409         */
 410        switch (version) {
 411        case V4:
 412                ottl = uh4->Unused;
 413                uh4->Unused = 0;
 414                len = nhgets(uh4->udplen);
 415                olen = nhgets(uh4->udpplen);
 416                hnputs(uh4->udpplen, len);
 417
 418                v4tov6(raddr, uh4->udpsrc);
 419                v4tov6(laddr, uh4->udpdst);
 420                lport = nhgets(uh4->udpdport);
 421                rport = nhgets(uh4->udpsport);
 422
 423                if (!(bp->flag & Budpck) &&
 424                    (uh4->udpcksum[0] || uh4->udpcksum[1]) &&
 425                    ptclcsum(bp, UDP4_PHDR_OFF, len + UDP4_PHDR_SZ)) {
 426                        upriv->ustats.udpInErrors++;
 427                        netlog(f, Logudp, "udp: checksum error %I\n",
 428                               raddr);
 429                        printd("udp: checksum error %I\n", raddr);
 430                        freeblist(bp);
 431                        return;
 432                }
 433                uh4->Unused = ottl;
 434                hnputs(uh4->udpplen, olen);
 435                break;
 436        case V6:
 437                uh6 = (Udp6hdr *) (bp->rp);
 438                len = nhgets(uh6->udplen);
 439                oviclfl = nhgetl(uh6->viclfl);
 440                olen = nhgets(uh6->len);
 441                ottl = uh6->hoplimit;
 442                ipmove(raddr, uh6->udpsrc);
 443                ipmove(laddr, uh6->udpdst);
 444                lport = nhgets(uh6->udpdport);
 445                rport = nhgets(uh6->udpsport);
 446                memset(uh6, 0, 8);
 447                hnputl(uh6->viclfl, len);
 448                uh6->hoplimit = IP_UDPPROTO;
 449                if (ptclcsum(bp, UDP6_PHDR_OFF, len + UDP6_PHDR_SZ)) {
 450                        upriv->ustats.udpInErrors++;
 451                        netlog(f, Logudp, "udp: checksum error %I\n", raddr);
 452                        printd("udp: checksum error %I\n", raddr);
 453                        freeblist(bp);
 454                        return;
 455                }
 456                hnputl(uh6->viclfl, oviclfl);
 457                hnputs(uh6->len, olen);
 458                uh6->nextheader = IP_UDPPROTO;
 459                uh6->hoplimit = ottl;
 460                break;
 461        default:
 462                panic("udpiput: version %d", version);
 463                return; /* to avoid a warning */
 464        }
 465
 466        c = iphtlook(&upriv->ht, raddr, rport, laddr, lport);
 467        if (c == NULL) {
 468                /* no converstation found */
 469                upriv->ustats.udpNoPorts++;
 470                netlog(f, Logudp, "udp: no conv %I!%d -> %I!%d\n", raddr, rport,
 471                           laddr, lport);
 472
 473                switch (version) {
 474                case V4:
 475                        icmpnoconv(f, bp);
 476                        break;
 477                case V6:
 478                        icmphostunr(f, ifc, bp, icmp6_port_unreach, 0);
 479                        break;
 480                default:
 481                        panic("udpiput2: version %d", version);
 482                }
 483
 484                freeblist(bp);
 485                return;
 486        }
 487
 488        if (c->state == Bypass) {
 489                bypass_or_drop(c, bp);
 490                return;
 491        }
 492
 493        ucb = (Udpcb *) c->ptcl;
 494
 495        if (c->state == Announced) {
 496                if (ucb->headers == 0) {
 497                        /* create a new conversation */
 498                        if (ipforme(f, laddr) != Runi) {
 499                                switch (version) {
 500                                case V4:
 501                                        v4tov6(laddr, ifc->lifc->local);
 502                                        break;
 503                                case V6:
 504                                        ipmove(laddr, ifc->lifc->local);
 505                                        break;
 506                                default:
 507                                        panic("udpiput3: version %d", version);
 508                                }
 509                        }
 510                        qlock(&udp->qlock);
 511                        c = Fsnewcall(c, raddr, rport, laddr, lport, version);
 512                        qunlock(&udp->qlock);
 513                        if (c == NULL) {
 514                                freeblist(bp);
 515                                return;
 516                        }
 517                        iphtadd(&upriv->ht, c);
 518                        ucb = (Udpcb *) c->ptcl;
 519                }
 520        }
 521
 522        qlock(&c->qlock);
 523
 524        /*
 525         * Trim the packet down to data size
 526         */
 527        len -= UDP_UDPHDR_SZ;
 528        switch (version) {
 529        case V4:
 530                bp = trimblock(bp, UDP4_IPHDR_SZ + UDP_UDPHDR_SZ, len);
 531                break;
 532        case V6:
 533                bp = trimblock(bp, UDP6_IPHDR_SZ + UDP_UDPHDR_SZ, len);
 534                break;
 535        default:
 536                bp = NULL;
 537                panic("udpiput4: version %d", version);
 538        }
 539        if (bp == NULL) {
 540                qunlock(&c->qlock);
 541                netlog(f, Logudp, "udp: len err %I.%d -> %I.%d\n", raddr, rport,
 542                           laddr, lport);
 543                upriv->lenerr++;
 544                return;
 545        }
 546
 547        netlog(f, Logudpmsg, "udp: %I.%d -> %I.%d l %d\n", raddr, rport,
 548                   laddr, lport, len);
 549
 550        switch (ucb->headers) {
 551        case 7:
 552                /* pass the src address */
 553                bp = padblock(bp, UDP_USEAD7);
 554                p = bp->rp;
 555                ipmove(p, raddr);
 556                p += IPaddrlen;
 557                ipmove(p, laddr);
 558                p += IPaddrlen;
 559                ipmove(p, ifc->lifc->local);
 560                p += IPaddrlen;
 561                hnputs(p, rport);
 562                p += 2;
 563                hnputs(p, lport);
 564                break;
 565        case 6:
 566                /* pass the src address */
 567                bp = padblock(bp, UDP_USEAD6);
 568                p = bp->rp;
 569                ipmove(p, raddr);
 570                p += IPaddrlen;
 571                ipmove(p, ipforme(f, laddr) == Runi ? laddr : ifc->lifc->local);
 572                p += IPaddrlen;
 573                hnputs(p, rport);
 574                p += 2;
 575                hnputs(p, lport);
 576                break;
 577        }
 578
 579        if (bp->next)
 580                bp = concatblock(bp);
 581
 582        if (qfull(c->rq)) {
 583                qunlock(&c->qlock);
 584                netlog(f, Logudp, "udp: qfull %I.%d -> %I.%d\n", raddr, rport,
 585                           laddr, lport);
 586                freeblist(bp);
 587                return;
 588        }
 589
 590        qpass(c->rq, bp);
 591        qunlock(&c->qlock);
 592
 593}
 594
 595static void udpctl(struct conv *c, char **f, int n)
 596{
 597        Udpcb *ucb = (Udpcb*)c->ptcl;
 598
 599        if ((n == 1) && strcmp(f[0], "oldheaders") == 0)
 600                ucb->headers = 6;
 601        else if ((n == 1) && strcmp(f[0], "headers") == 0)
 602                ucb->headers = 7;
 603        else
 604                error(EINVAL, "unknown command to %s", __func__);
 605}
 606
 607void udpadvise(struct Proto *udp, struct block *bp, char *msg)
 608{
 609        Udp4hdr *h4;
 610        Udp6hdr *h6;
 611        uint8_t source[IPaddrlen], dest[IPaddrlen];
 612        uint16_t psource, pdest;
 613        struct conv *s, **p;
 614        int version;
 615
 616        h4 = (Udp4hdr *) (bp->rp);
 617        version = ((h4->vihl & 0xF0) == IP_VER6) ? V6 : V4;
 618
 619        switch (version) {
 620        case V4:
 621                v4tov6(dest, h4->udpdst);
 622                v4tov6(source, h4->udpsrc);
 623                psource = nhgets(h4->udpsport);
 624                pdest = nhgets(h4->udpdport);
 625                break;
 626        case V6:
 627                h6 = (Udp6hdr *) (bp->rp);
 628                ipmove(dest, h6->udpdst);
 629                ipmove(source, h6->udpsrc);
 630                psource = nhgets(h6->udpsport);
 631                pdest = nhgets(h6->udpdport);
 632                break;
 633        default:
 634                panic("udpadvise: version %d", version);
 635                return; /* to avoid a warning */
 636        }
 637
 638        /* Look for a connection */
 639        for (p = udp->conv; *p; p++) {
 640                s = *p;
 641                if (s->rport == pdest)
 642                        if (s->lport == psource)
 643                                if (ipcmp(s->raddr, dest) == 0)
 644                                        if (ipcmp(s->laddr, source) == 0) {
 645                                                if (s->ignoreadvice)
 646                                                        break;
 647                                                qlock(&s->qlock);
 648                                                qhangup(s->rq, msg);
 649                                                qhangup(s->wq, msg);
 650                                                qunlock(&s->qlock);
 651                                                freeblist(bp);
 652                                                return;
 653                                        }
 654        }
 655        freeblist(bp);
 656}
 657
 658int udpstats(struct Proto *udp, char *buf, int len)
 659{
 660        Udppriv *upriv;
 661        char *p, *e;
 662
 663        upriv = udp->priv;
 664        p = buf;
 665        e = p + len;
 666        p = seprintf(p, e, "InDatagrams: %u\n", upriv->ustats.udpInDatagrams);
 667        p = seprintf(p, e, "NoPorts: %u\n", upriv->ustats.udpNoPorts);
 668        p = seprintf(p, e, "InErrors: %u\n", upriv->ustats.udpInErrors);
 669        p = seprintf(p, e, "OutDatagrams: %u\n", upriv->ustats.udpOutDatagrams);
 670        return p - buf;
 671}
 672
 673void udpinit(struct Fs *fs)
 674{
 675        struct Proto *udp;
 676
 677        udp = kzmalloc(sizeof(struct Proto), 0);
 678        udp->priv = kzmalloc(sizeof(Udppriv), 0);
 679        udp->name = "udp";
 680        udp->connect = udpconnect;
 681        udp->bind = udpbind;
 682        udp->announce = udpannounce;
 683        udp->bypass = udpbypass;
 684        udp->ctl = udpctl;
 685        udp->state = udpstate;
 686        udp->create = udpcreate;
 687        udp->close = udpclose;
 688        udp->rcv = udpiput;
 689        udp->advise = udpadvise;
 690        udp->stats = udpstats;
 691        udp->ipproto = IP_UDPPROTO;
 692        udp->nc = 4096;
 693        udp->ptclsize = sizeof(Udpcb);
 694
 695        Fsproto(fs, udp);
 696}
 697