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