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