vmm: refactor userspace's emsr_fakewrite()
[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 <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
56 enum {
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
75 typedef struct Udp4hdr Udp4hdr;
76 struct 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
96 typedef struct Udp6hdr Udp6hdr;
97 struct 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 */
113 typedef struct Udpstats Udpstats;
114 struct Udpstats {
115         uint32_t udpInDatagrams;
116         uint32_t udpNoPorts;
117         uint32_t udpInErrors;
118         uint32_t udpOutDatagrams;
119 };
120
121 typedef struct Udppriv Udppriv;
122 struct 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
133 void (*etherprofiler) (char *name, int qlen);
134 void udpkick(void *x, struct block *bp);
135
136 /*
137  *  protocol specific part of Conv
138  */
139 typedef struct Udpcb Udpcb;
140 struct Udpcb {
141         uint8_t headers;
142 };
143
144 static 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
155 static 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
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 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
181 static 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
189 static void udpcreate(struct conv *c)
190 {
191         c->rq = qopen(128 * 1024, Qmsg, 0, 0);
192         c->wq = qbypass(udpkick, c);
193 }
194
195 static 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
218 void 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
384 void 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
595 static 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
607 void 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
658 int 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
673 void 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 }