Add the Inferno license to files we got from Inferno
[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 char *udpconnect(struct conv *c, char **argv, int argc)
150 {
151         char *e;
152         Udppriv *upriv;
153
154         upriv = c->p->priv;
155         e = Fsstdconnect(c, argv, argc);
156         Fsconnected(c, e);
157         if (e != NULL)
158                 return e;
159
160         iphtadd(&upriv->ht, c);
161         return NULL;
162 }
163
164 static 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
171 static char *udpannounce(struct conv *c, char **argv, int argc)
172 {
173         char *e;
174         Udppriv *upriv;
175
176         upriv = c->p->priv;
177         e = Fsstdannounce(c, argv, argc);
178         if (e != NULL)
179                 return e;
180         Fsconnected(c, NULL);
181         iphtadd(&upriv->ht, c);
182
183         return NULL;
184 }
185
186 static void udpcreate(struct conv *c)
187 {
188         c->rq = qopen(128 * 1024, Qmsg, 0, 0);
189         c->wq = qbypass(udpkick, c);
190 }
191
192 static void udpclose(struct conv *c)
193 {
194         Udpcb *ucb;
195         Udppriv *upriv;
196
197         upriv = c->p->priv;
198         iphtrem(&upriv->ht, c);
199
200         c->state = 0;
201         qclose(c->rq);
202         qclose(c->wq);
203         qclose(c->eq);
204         ipmove(c->laddr, IPnoaddr);
205         ipmove(c->raddr, IPnoaddr);
206         c->lport = 0;
207         c->rport = 0;
208
209         ucb = (Udpcb *) c->ptcl;
210         ucb->headers = 0;
211
212         qunlock(&c->qlock);
213 }
214
215 void udpkick(void *x, struct block *bp)
216 {
217         struct conv *c = x;
218         Udp4hdr *uh4;
219         Udp6hdr *uh6;
220         uint16_t rport;
221         uint8_t laddr[IPaddrlen], raddr[IPaddrlen];
222         Udpcb *ucb;
223         int dlen, ptcllen;
224         Udppriv *upriv;
225         struct Fs *f;
226         int version;
227         struct conv *rc;
228
229         upriv = c->p->priv;
230         assert(upriv);
231         f = c->p->f;
232
233         netlog(c->p->f, Logudp, "udp: kick\n");
234         if (bp == NULL)
235                 return;
236
237         ucb = (Udpcb *) c->ptcl;
238         switch (ucb->headers) {
239                 case 7:
240                         /* get user specified addresses */
241                         bp = pullupblock(bp, UDP_USEAD7);
242                         if (bp == NULL)
243                                 return;
244                         ipmove(raddr, bp->rp);
245                         bp->rp += IPaddrlen;
246                         ipmove(laddr, bp->rp);
247                         bp->rp += IPaddrlen;
248                         /* pick interface closest to dest */
249                         if (ipforme(f, laddr) != Runi)
250                                 findlocalip(f, laddr, raddr);
251                         bp->rp += IPaddrlen;    /* Ignore ifc address */
252                         rport = nhgets(bp->rp);
253                         bp->rp += 2 + 2;        /* Ignore local port */
254                         break;
255                 case 6:
256                         /* get user specified addresses */
257                         bp = pullupblock(bp, UDP_USEAD6);
258                         if (bp == NULL)
259                                 return;
260                         ipmove(raddr, bp->rp);
261                         bp->rp += IPaddrlen;
262                         ipmove(laddr, bp->rp);
263                         bp->rp += IPaddrlen;
264                         /* pick interface closest to dest */
265                         if (ipforme(f, laddr) != Runi)
266                                 findlocalip(f, laddr, raddr);
267                         rport = nhgets(bp->rp);
268                         bp->rp += 2 + 2;        /* Ignore local port */
269                         break;
270                 default:
271                         rport = 0;
272                         break;
273         }
274
275         if (ucb->headers) {
276                 if (memcmp(laddr, v4prefix, IPv4off) == 0 ||
277                         ipcmp(laddr, IPnoaddr) == 0)
278                         version = V4;
279                 else
280                         version = V6;
281         } else {
282                 if ((memcmp(c->raddr, v4prefix, IPv4off) == 0 &&
283                          memcmp(c->laddr, v4prefix, IPv4off) == 0)
284                         || ipcmp(c->raddr, IPnoaddr) == 0)
285                         version = V4;
286                 else
287                         version = V6;
288         }
289
290         dlen = blocklen(bp);
291
292         /* fill in pseudo header and compute checksum */
293         switch (version) {
294                 case V4:
295                         bp = padblock(bp, UDP4_IPHDR_SZ + UDP_UDPHDR_SZ);
296                         if (bp == NULL)
297                                 return;
298
299                         uh4 = (Udp4hdr *) (bp->rp);
300                         ptcllen = dlen + UDP_UDPHDR_SZ;
301                         uh4->Unused = 0;
302                         uh4->udpproto = IP_UDPPROTO;
303                         uh4->frag[0] = 0;
304                         uh4->frag[1] = 0;
305                         hnputs(uh4->udpplen, ptcllen);
306                         if (ucb->headers) {
307                                 v6tov4(uh4->udpdst, raddr);
308                                 hnputs(uh4->udpdport, rport);
309                                 v6tov4(uh4->udpsrc, laddr);
310                                 rc = NULL;
311                         } else {
312                                 v6tov4(uh4->udpdst, c->raddr);
313                                 hnputs(uh4->udpdport, c->rport);
314                                 if (ipcmp(c->laddr, IPnoaddr) == 0)
315                                         findlocalip(f, c->laddr, c->raddr);
316                                 v6tov4(uh4->udpsrc, c->laddr);
317                                 rc = c;
318                         }
319                         hnputs(uh4->udpsport, c->lport);
320                         hnputs(uh4->udplen, ptcllen);
321                         uh4->udpcksum[0] = 0;
322                         uh4->udpcksum[1] = 0;
323                         hnputs(uh4->udpcksum,
324                                    ~ptclcsum(bp, UDP4_PHDR_OFF, UDP4_PHDR_SZ));
325                         bp->checksum_start = UDP4_IPHDR_SZ;
326                         bp->checksum_offset = uh4->udpcksum - uh4->udpsport;
327                         bp->flag |= Budpck;
328                         uh4->vihl = IP_VER4;
329                         ipoput4(f, bp, 0, c->ttl, c->tos, rc);
330                         break;
331
332                 case V6:
333                         bp = padblock(bp, UDP6_IPHDR_SZ + UDP_UDPHDR_SZ);
334                         if (bp == NULL)
335                                 return;
336
337                         // using the v6 ip header to create pseudo header 
338                         // first then reset it to the normal ip header
339                         uh6 = (Udp6hdr *) (bp->rp);
340                         memset(uh6, 0, 8);
341                         ptcllen = dlen + UDP_UDPHDR_SZ;
342                         hnputl(uh6->viclfl, ptcllen);
343                         uh6->hoplimit = IP_UDPPROTO;
344                         if (ucb->headers) {
345                                 ipmove(uh6->udpdst, raddr);
346                                 hnputs(uh6->udpdport, rport);
347                                 ipmove(uh6->udpsrc, laddr);
348                                 rc = NULL;
349                         } else {
350                                 ipmove(uh6->udpdst, c->raddr);
351                                 hnputs(uh6->udpdport, c->rport);
352                                 if (ipcmp(c->laddr, IPnoaddr) == 0)
353                                         findlocalip(f, c->laddr, c->raddr);
354                                 ipmove(uh6->udpsrc, c->laddr);
355                                 rc = c;
356                         }
357                         hnputs(uh6->udpsport, c->lport);
358                         hnputs(uh6->udplen, ptcllen);
359                         uh6->udpcksum[0] = 0;
360                         uh6->udpcksum[1] = 0;
361                         hnputs(uh6->udpcksum,
362                                    ptclcsum(bp, UDP6_PHDR_OFF,
363                                                         dlen + UDP_UDPHDR_SZ + UDP6_PHDR_SZ));
364                         memset(uh6, 0, 8);
365                         uh6->viclfl[0] = IP_VER6;
366                         hnputs(uh6->len, ptcllen);
367                         uh6->nextheader = IP_UDPPROTO;
368                         ipoput6(f, bp, 0, c->ttl, c->tos, rc);
369                         break;
370
371                 default:
372                         panic("udpkick: version %d", version);
373         }
374         upriv->ustats.udpOutDatagrams++;
375 }
376
377 void udpiput(struct Proto *udp, struct Ipifc *ifc, struct block *bp)
378 {
379         int len;
380         Udp4hdr *uh4;
381         Udp6hdr *uh6;
382         struct conv *c;
383         Udpcb *ucb;
384         uint8_t raddr[IPaddrlen], laddr[IPaddrlen];
385         uint16_t rport, lport;
386         Udppriv *upriv;
387         struct Fs *f;
388         int version;
389         int ottl, oviclfl, olen;
390         uint8_t *p;
391
392         upriv = udp->priv;
393         f = udp->f;
394         upriv->ustats.udpInDatagrams++;
395
396         uh4 = (Udp4hdr *) (bp->rp);
397         version = ((uh4->vihl & 0xF0) == IP_VER6) ? V6 : V4;
398
399         /*
400          * Put back pseudo header for checksum 
401          * (remember old values for icmpnoconv())
402          */
403         switch (version) {
404                 case V4:
405                         ottl = uh4->Unused;
406                         uh4->Unused = 0;
407                         len = nhgets(uh4->udplen);
408                         olen = nhgets(uh4->udpplen);
409                         hnputs(uh4->udpplen, len);
410
411                         v4tov6(raddr, uh4->udpsrc);
412                         v4tov6(laddr, uh4->udpdst);
413                         lport = nhgets(uh4->udpdport);
414                         rport = nhgets(uh4->udpsport);
415
416                         if (!(bp->flag & Budpck) &&
417                             (uh4->udpcksum[0] || uh4->udpcksum[1]) &&
418                             ptclcsum(bp, UDP4_PHDR_OFF, len + UDP4_PHDR_SZ)) {
419                                 upriv->ustats.udpInErrors++;
420                                 netlog(f, Logudp, "udp: checksum error %I\n",
421                                        raddr);
422                                 printd("udp: checksum error %I\n", raddr);
423                                 freeblist(bp);
424                                 return;
425                         }
426                         uh4->Unused = ottl;
427                         hnputs(uh4->udpplen, olen);
428                         break;
429                 case V6:
430                         uh6 = (Udp6hdr *) (bp->rp);
431                         len = nhgets(uh6->udplen);
432                         oviclfl = nhgetl(uh6->viclfl);
433                         olen = nhgets(uh6->len);
434                         ottl = uh6->hoplimit;
435                         ipmove(raddr, uh6->udpsrc);
436                         ipmove(laddr, uh6->udpdst);
437                         lport = nhgets(uh6->udpdport);
438                         rport = nhgets(uh6->udpsport);
439                         memset(uh6, 0, 8);
440                         hnputl(uh6->viclfl, len);
441                         uh6->hoplimit = IP_UDPPROTO;
442                         if (ptclcsum(bp, UDP6_PHDR_OFF, len + UDP6_PHDR_SZ)) {
443                                 upriv->ustats.udpInErrors++;
444                                 netlog(f, Logudp, "udp: checksum error %I\n", raddr);
445                                 printd("udp: checksum error %I\n", raddr);
446                                 freeblist(bp);
447                                 return;
448                         }
449                         hnputl(uh6->viclfl, oviclfl);
450                         hnputs(uh6->len, olen);
451                         uh6->nextheader = IP_UDPPROTO;
452                         uh6->hoplimit = ottl;
453                         break;
454                 default:
455                         panic("udpiput: version %d", version);
456                         return; /* to avoid a warning */
457         }
458
459         qlock(&udp->qlock);
460
461         c = iphtlook(&upriv->ht, raddr, rport, laddr, lport);
462         if (c == NULL) {
463                 /* no converstation found */
464                 upriv->ustats.udpNoPorts++;
465                 qunlock(&udp->qlock);
466                 netlog(f, Logudp, "udp: no conv %I!%d -> %I!%d\n", raddr, rport,
467                            laddr, lport);
468
469                 switch (version) {
470                         case V4:
471                                 icmpnoconv(f, bp);
472                                 break;
473                         case V6:
474                                 icmphostunr(f, ifc, bp, icmp6_port_unreach, 0);
475                                 break;
476                         default:
477                                 panic("udpiput2: version %d", version);
478                 }
479
480                 freeblist(bp);
481                 return;
482         }
483         ucb = (Udpcb *) c->ptcl;
484
485         if (c->state == Announced) {
486                 if (ucb->headers == 0) {
487                         /* create a new conversation */
488                         if (ipforme(f, laddr) != Runi) {
489                                 switch (version) {
490                                         case V4:
491                                                 v4tov6(laddr, ifc->lifc->local);
492                                                 break;
493                                         case V6:
494                                                 ipmove(laddr, ifc->lifc->local);
495                                                 break;
496                                         default:
497                                                 panic("udpiput3: version %d", version);
498                                 }
499                         }
500                         c = Fsnewcall(c, raddr, rport, laddr, lport, version);
501                         if (c == NULL) {
502                                 qunlock(&udp->qlock);
503                                 freeblist(bp);
504                                 return;
505                         }
506                         iphtadd(&upriv->ht, c);
507                         ucb = (Udpcb *) c->ptcl;
508                 }
509         }
510
511         qlock(&c->qlock);
512         qunlock(&udp->qlock);
513
514         /*
515          * Trim the packet down to data size
516          */
517         len -= UDP_UDPHDR_SZ;
518         switch (version) {
519                 case V4:
520                         bp = trimblock(bp, UDP4_IPHDR_SZ + UDP_UDPHDR_SZ, len);
521                         break;
522                 case V6:
523                         bp = trimblock(bp, UDP6_IPHDR_SZ + UDP_UDPHDR_SZ, len);
524                         break;
525                 default:
526                         bp = NULL;
527                         panic("udpiput4: version %d", version);
528         }
529         if (bp == NULL) {
530                 qunlock(&c->qlock);
531                 netlog(f, Logudp, "udp: len err %I.%d -> %I.%d\n", raddr, rport,
532                            laddr, lport);
533                 upriv->lenerr++;
534                 return;
535         }
536
537         netlog(f, Logudpmsg, "udp: %I.%d -> %I.%d l %d\n", raddr, rport,
538                    laddr, lport, len);
539
540         switch (ucb->headers) {
541                 case 7:
542                         /* pass the src address */
543                         bp = padblock(bp, UDP_USEAD7);
544                         p = bp->rp;
545                         ipmove(p, raddr);
546                         p += IPaddrlen;
547                         ipmove(p, laddr);
548                         p += IPaddrlen;
549                         ipmove(p, ifc->lifc->local);
550                         p += IPaddrlen;
551                         hnputs(p, rport);
552                         p += 2;
553                         hnputs(p, lport);
554                         break;
555                 case 6:
556                         /* pass the src address */
557                         bp = padblock(bp, UDP_USEAD6);
558                         p = bp->rp;
559                         ipmove(p, raddr);
560                         p += IPaddrlen;
561                         ipmove(p, ipforme(f, laddr) == Runi ? laddr : ifc->lifc->local);
562                         p += IPaddrlen;
563                         hnputs(p, rport);
564                         p += 2;
565                         hnputs(p, lport);
566                         break;
567         }
568
569         if (bp->next)
570                 bp = concatblock(bp);
571
572         if (qfull(c->rq)) {
573                 qunlock(&c->qlock);
574                 netlog(f, Logudp, "udp: qfull %I.%d -> %I.%d\n", raddr, rport,
575                            laddr, lport);
576                 freeblist(bp);
577                 return;
578         }
579
580         qpass(c->rq, bp);
581         qunlock(&c->qlock);
582
583 }
584
585 char *udpctl(struct conv *c, char **f, int n)
586 {
587         Udpcb *ucb;
588
589         ucb = (Udpcb *) c->ptcl;
590         if (n == 1) {
591                 if (strcmp(f[0], "oldheaders") == 0) {
592                         ucb->headers = 6;
593                         return NULL;
594                 } else if (strcmp(f[0], "headers") == 0) {
595                         ucb->headers = 7;
596                         return NULL;
597                 }
598         }
599         return "unknown control request";
600 }
601
602 void udpadvise(struct Proto *udp, struct block *bp, char *msg)
603 {
604         Udp4hdr *h4;
605         Udp6hdr *h6;
606         uint8_t source[IPaddrlen], dest[IPaddrlen];
607         uint16_t psource, pdest;
608         struct conv *s, **p;
609         int version;
610
611         h4 = (Udp4hdr *) (bp->rp);
612         version = ((h4->vihl & 0xF0) == IP_VER6) ? V6 : V4;
613
614         switch (version) {
615                 case V4:
616                         v4tov6(dest, h4->udpdst);
617                         v4tov6(source, h4->udpsrc);
618                         psource = nhgets(h4->udpsport);
619                         pdest = nhgets(h4->udpdport);
620                         break;
621                 case V6:
622                         h6 = (Udp6hdr *) (bp->rp);
623                         ipmove(dest, h6->udpdst);
624                         ipmove(source, h6->udpsrc);
625                         psource = nhgets(h6->udpsport);
626                         pdest = nhgets(h6->udpdport);
627                         break;
628                 default:
629                         panic("udpadvise: version %d", version);
630                         return; /* to avoid a warning */
631         }
632
633         /* Look for a connection */
634         qlock(&udp->qlock);
635         for (p = udp->conv; *p; p++) {
636                 s = *p;
637                 if (s->rport == pdest)
638                         if (s->lport == psource)
639                                 if (ipcmp(s->raddr, dest) == 0)
640                                         if (ipcmp(s->laddr, source) == 0) {
641                                                 if (s->ignoreadvice)
642                                                         break;
643                                                 qlock(&s->qlock);
644                                                 qunlock(&udp->qlock);
645                                                 qhangup(s->rq, msg);
646                                                 qhangup(s->wq, msg);
647                                                 qunlock(&s->qlock);
648                                                 freeblist(bp);
649                                                 return;
650                                         }
651         }
652         qunlock(&udp->qlock);
653         freeblist(bp);
654 }
655
656 int udpstats(struct Proto *udp, char *buf, int len)
657 {
658         Udppriv *upriv;
659         char *p, *e;
660
661         upriv = udp->priv;
662         p = buf;
663         e = p + len;
664         p = seprintf(p, e, "InDatagrams: %u\n", upriv->ustats.udpInDatagrams);
665         p = seprintf(p, e, "NoPorts: %u\n", upriv->ustats.udpNoPorts);
666         p = seprintf(p, e, "InErrors: %u\n", upriv->ustats.udpInErrors);
667         p = seprintf(p, e, "OutDatagrams: %u\n", upriv->ustats.udpOutDatagrams);
668         return p - buf;
669 }
670
671 void udpnewconv(struct Proto *udp, struct conv *conv)
672 {
673         /* Fsprotoclone alloc'd our priv struct and attached it to conv already.
674          * Now we need to init it */
675         struct Udpcb *ucb = (struct Udpcb *)conv->ptcl;
676         qlock_init(&ucb->qlock);
677 }
678
679 void udpinit(struct Fs *fs)
680 {
681         struct Proto *udp;
682
683         udp = kzmalloc(sizeof(struct Proto), 0);
684         udp->priv = kzmalloc(sizeof(Udppriv), 0);
685         udp->name = "udp";
686         udp->connect = udpconnect;
687         udp->announce = udpannounce;
688         udp->ctl = udpctl;
689         udp->state = udpstate;
690         udp->create = udpcreate;
691         udp->close = udpclose;
692         udp->rcv = udpiput;
693         udp->advise = udpadvise;
694         udp->stats = udpstats;
695         udp->ipproto = IP_UDPPROTO;
696         udp->nc = Nchans;
697         udp->newconv = udpnewconv;
698         udp->ptclsize = sizeof(Udpcb);
699
700         Fsproto(fs, udp);
701 }