Merge from vendor branch AWK:
[dragonfly.git] / sys / kern / kern_syslink.c
1 /*
2  * Copyright (c) 2006-2007 The DragonFly Project.  All rights reserved.
3  * 
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
6  * 
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  * 
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  * $DragonFly: src/sys/kern/kern_syslink.c,v 1.10 2007/04/26 02:10:59 dillon Exp $
35  */
36 /*
37  * This module implements the syslink() system call and protocol which
38  * is used to glue clusters together as well as to interface userland
39  * devices and filesystems to the kernel.
40  *
41  * We implement the management node concept in this module.  A management
42  * node is basically a router node with additional features that take much
43  * of the protocol burden away from connecting terminal nodes.
44  */
45
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/kernel.h>
49 #include <sys/malloc.h>
50 #include <sys/alist.h>
51 #include <sys/file.h>
52 #include <sys/proc.h>
53 #include <sys/lock.h>
54 #include <sys/uio.h>
55 #include <sys/thread.h>
56 #include <sys/tree.h>
57 #include <sys/sysctl.h>
58 #include <sys/sysproto.h>
59 #include <sys/mbuf.h>
60 #include <sys/socket.h>
61 #include <sys/socketvar.h>
62 #include <sys/socketops.h>
63 #include <sys/syslink.h>
64 #include <sys/syslink_msg.h>
65 #include <netinet/in.h>
66
67 #include <sys/thread2.h>
68
69 #include "opt_syslink.h"
70
71 /*
72  * Red-Black trees organizing the syslink 'router' nodes and connections
73  * to router nodes.
74  */
75 struct slrouter;
76 struct sldata;
77
78 RB_HEAD(slrouter_rb_tree, slrouter);
79 RB_HEAD(sldata_rb_tree, sldata);
80 RB_PROTOTYPE2(slrouter_rb_tree, slrouter, rbnode,
81               rb_slrouter_compare, sysid_t);
82 RB_PROTOTYPE2(sldata_rb_tree, sldata, rbnode,
83               rb_sldata_compare, int);
84
85 /*
86  * Fifo used to buffer broadcast packets
87  */
88 struct slbuf {
89         char    *buf;
90         int     bufsize;        /* must be a power of 2 */
91         int     bufmask;        /* (bufsize - 1) */
92         int     rindex;         /* tail-chasing FIFO indices */
93         int     windex;
94 };
95
96 /*
97  * Syslink Router abstraction
98  */
99 struct slrouter {
100         RB_ENTRY(slrouter) rbnode;              /* list of routers */
101         struct sldata_rb_tree sldata_rb_root;   /* connections to router */
102         sysid_t sysid;                          /* logical sysid of router */
103         int     flags;                          /* flags passed on create */
104         int     bits;                           /* accomodate connections */
105         int     count;                          /* number of connections */
106         int     refs;
107         alist_t         bitmap;
108         struct slbuf    bbuf;                   /* broadcast buffer */
109         char label[SYSLINK_LABEL_SIZE];
110 };
111
112 /*
113  * Syslink Connection abstraction
114  */
115 struct sldata {
116         RB_ENTRY(sldata) rbnode;
117         struct slrouter *router;        /* organizing router */
118         struct file     *xfp;           /* external file pointer */
119         struct lock     rlock;          /* synchronizing lock */
120         struct lock     wlock;          /* synchronizing lock */
121         struct thread   *rthread;       /* helper thread */
122         struct thread   *wthread;       /* helper thread */
123         struct sockbuf  sior;           /* accumulate incoming mbufs */
124         struct sockbuf  siow;           /* accumulate outgoing mbufs */
125         struct sockaddr sa;             /* used w/SLIF_SUBNET mode */
126         int     bindex;                 /* broadcast index */
127         int     flags;                  /* connection flags */
128         int     linkid;
129         int     bits;
130         int     refs;
131         char    label[SYSLINK_LABEL_SIZE];
132 };
133
134 #define SYSLINK_BBUFSIZE        (32*1024)
135 #define SYSLINK_SIOBUFSIZE      (128*1024)
136
137 static int rb_slrouter_compare(struct slrouter *r1, struct slrouter *r2);
138 static int rb_sldata_compare(struct sldata *d1, struct sldata *d2);
139
140 static int syslink_destroy(struct slrouter *slrouter);
141 static int syslink_add(struct slrouter *slrouter,
142                         struct syslink_info *info, int *result);
143 static int syslink_rem(struct slrouter *slrouter, struct sldata *sldata,
144                         struct syslink_info *info);
145
146 static int syslink_read(struct file *fp, struct uio *uio,
147                         struct ucred *cred, int flags);
148 static int syslink_write(struct file *fp, struct uio *uio,
149                          struct ucred *cred, int flags);
150 static int syslink_close(struct file *fp);
151 static int syslink_stat(struct file *fp, struct stat *sb, struct ucred *cred);
152 static int syslink_shutdown(struct file *fp, int how);
153 static int syslink_ioctl(struct file *fp, u_long cmd, caddr_t data,
154                          struct ucred *cred);
155 static int syslink_poll(struct file *fp, int events, struct ucred *cred);
156 static int syslink_kqfilter(struct file *fp, struct knote *kn);
157
158 static void syslink_rthread_so(void *arg);
159 static void syslink_rthread_fp(void *arg);
160 static void syslink_wthread_so(void *arg);
161 static void syslink_wthread_fp(void *arg);
162 static int syslink_getsubnet(struct sockaddr *sa);
163 static struct mbuf *syslink_parse_stream(struct sockbuf *sio);
164 static void syslink_route(struct slrouter *slrouter, int linkid, struct mbuf *m);
165 static void slbuf_alloc(struct slbuf *buf, int bytes);
166 static void slbuf_free(struct slbuf *buf);
167 static void sldata_rels(struct sldata *sldata);
168 static void slrouter_rels(struct slrouter *slrouter);
169 static int process_syslink_msg(struct sldata *sldata, struct syslink_msg *head);
170 static int syslink_validate(struct syslink_msg *head, int bytes);
171
172 RB_GENERATE2(slrouter_rb_tree, slrouter, rbnode,
173              rb_slrouter_compare, sysid_t, sysid);
174 RB_GENERATE2(sldata_rb_tree, sldata, rbnode,
175              rb_sldata_compare, int, linkid);
176
177 static struct fileops syslinkops = {
178     .fo_read =          syslink_read,
179     .fo_write =         syslink_write,
180     .fo_ioctl =         syslink_ioctl,
181     .fo_poll =          syslink_poll,
182     .fo_kqfilter =      syslink_kqfilter,
183     .fo_stat =          syslink_stat,
184     .fo_close =         syslink_close,
185     .fo_shutdown =      syslink_shutdown
186 };
187
188 MALLOC_DEFINE(M_SYSLINK, "syslink", "syslink manager");
189
190 static int syslink_enabled;
191 SYSCTL_INT(_kern, OID_AUTO, syslink_enabled,
192             CTLFLAG_RW, &syslink_enabled, 0, "Enable SYSLINK");
193
194 /*
195  * Support declarations and compare function for our RB trees
196  */
197 static struct slrouter_rb_tree slrouter_rb_root;
198
199 static int
200 rb_slrouter_compare(struct slrouter *r1, struct slrouter *r2)
201 {
202         if (r1->sysid < r2->sysid)
203                 return(-1);
204         if (r1->sysid > r2->sysid)
205                 return(1);
206         return(0);
207 }
208
209 static int
210 rb_sldata_compare(struct sldata *d1, struct sldata *d2)
211 {
212         if (d1->linkid < d2->linkid)
213                 return(-1);
214         if (d1->linkid > d2->linkid)
215                 return(1);
216         return(0);
217 }
218
219 /*
220  * Compare and callback functions for first-sysid and first-linkid searches.
221  */
222 static int
223 syslink_cmd_locate_cmp(struct slrouter *slrouter, void *data)
224 {
225         struct syslink_info *info = data;
226
227         if (slrouter->sysid < info->sysid)
228             return(-1);
229         if (slrouter->sysid > info->sysid)
230             return(1);
231         return(0);
232 }
233
234 static int
235 syslink_cmd_locate_callback(struct slrouter *slrouter, void *data)
236 {
237         struct syslink_info *info = data;
238
239         info->flags = slrouter->flags;  /* also clears SLIF_ERROR */
240         bcopy(slrouter->label, info->label, SYSLINK_LABEL_SIZE);
241
242         return(-1);
243 }
244
245 static int
246 syslink_cmd_find_cmp(struct sldata *sldata, void *data)
247 {
248         struct syslink_info *info = data;
249
250         if (sldata->linkid < info->linkid)
251             return(-1);
252         if (sldata->linkid > info->linkid)
253             return(1);
254         return(0);
255 }
256
257 static int
258 syslink_cmd_find_callback(struct sldata *sldata, void *data)
259 {
260         struct syslink_info *info = data;
261
262         info->linkid = sldata->linkid;
263         info->flags = sldata->flags;    /* also clears SLIF_ERROR */
264         bcopy(sldata->label, info->label, SYSLINK_LABEL_SIZE);
265
266         return(-1);
267 }
268
269 /*
270  * Primary system call interface - associate a full-duplex stream
271  * (typically a pipe or a connected socket) with a sysid namespace,
272  * or create a direct link.
273  *
274  * syslink(int cmd, struct syslink_info *info, size_t bytes)
275  */
276 int
277 sys_syslink(struct syslink_args *uap)
278 {
279         struct syslink_info info;
280         struct slrouter *slrouter = NULL;
281         struct sldata *sldata = NULL;
282         int error;
283         int n;
284
285         /*
286          * System call is under construction and disabled by default. 
287          * Superuser access is also required.
288          */
289         if (syslink_enabled == 0)
290                 return (EAUTH);
291         error = suser(curthread);
292         if (error)
293                 return (error);
294
295         /*
296          * Load and validate the info structure.  Unloaded bytes are zerod
297          * out.  The label field must always be 0-filled, even if not used
298          * for a command.
299          */
300         bzero(&info, sizeof(info));
301         if ((unsigned)uap->bytes <= sizeof(info)) {
302                 if (uap->bytes)
303                         error = copyin(uap->info, &info, uap->bytes);
304         } else {
305                 error = EINVAL;
306         }
307         if (error)
308                 return (error);
309
310         if (info.label[sizeof(info.label)-1] != 0)
311                 return (EINVAL);
312
313         /*
314          * Process command
315          */
316         switch(uap->cmd) {
317         case SYSLINK_CMD_CREATE:
318                 /*
319                  * Create a new syslink router node.  Set refs to prevent the
320                  * router node from being destroyed.  One ref is our temporary
321                  * reference while the other is the SLIF_DESTROYED-interlocked
322                  * reference.
323                  */
324                 if (info.bits < 2 || info.bits > SYSLINK_ROUTER_MAXBITS)
325                         return (EINVAL);
326                 slrouter = kmalloc(sizeof(struct slrouter), M_SYSLINK,
327                                     M_WAITOK|M_ZERO);
328                 if (slrouter_rb_tree_RB_LOOKUP(&slrouter_rb_root, info.sysid)) {
329                         kfree(slrouter, M_SYSLINK);
330                         slrouter = NULL;
331                         return (EINVAL);
332                 }
333                 slrouter->sysid = info.sysid;
334                 slrouter->refs = 2;
335                 slrouter->bits = info.bits;
336                 slrouter->flags = info.flags & SLIF_USERFLAGS;
337                 slrouter->bitmap = alist_create(1 << info.bits, M_SYSLINK);
338                 slbuf_alloc(&slrouter->bbuf, SYSLINK_BBUFSIZE);
339                 RB_INIT(&slrouter->sldata_rb_root);
340                 RB_INSERT(slrouter_rb_tree, &slrouter_rb_root, slrouter);
341                 break;
342         case SYSLINK_CMD_DESTROY:
343                 /*
344                  * Destroy a syslink router node.  The physical node is
345                  * not freed until our temporary reference is removed.
346                  */
347                 slrouter = slrouter_rb_tree_RB_LOOKUP(&slrouter_rb_root,
348                                                       info.sysid);
349                 if (slrouter) {
350                         ++slrouter->refs;
351                         if ((slrouter->flags & SLIF_DESTROYED) == 0) {
352                                 slrouter->flags |= SLIF_DESTROYED;
353                                 /* SLIF_DESTROYED interlock */
354                                 slrouter_rels(slrouter);
355                                 error = syslink_destroy(slrouter);
356                                 /* still holding our private interlock */
357                         }
358                 }
359                 break;
360         case SYSLINK_CMD_LOCATE:
361                 /*
362                  * Locate the first syslink router node >= info.sysid
363                  */
364                 info.flags |= SLIF_ERROR;
365                 n = slrouter_rb_tree_RB_SCAN(
366                             &slrouter_rb_root,
367                             syslink_cmd_locate_cmp, syslink_cmd_locate_callback,
368                             &info);
369                 if (info.flags & SLIF_ERROR)
370                         error = ENOENT;
371                 break;
372         case SYSLINK_CMD_ADD:
373                 slrouter = slrouter_rb_tree_RB_LOOKUP(&slrouter_rb_root, info.sysid);
374                 if (info.bits &&
375                     (info.bits < 2 || info.bits > SYSLINK_ROUTER_MAXBITS)) {
376                         error = EINVAL;
377                 } else if (slrouter && (slrouter->flags & SLIF_DESTROYED)) {
378                         /*
379                          * Someone is trying to destroy this route node,
380                          * no new adds please!
381                          */
382                         error = EIO;
383                 } else if (slrouter) {
384                         ++slrouter->refs;
385                         error = syslink_add(slrouter, &info,
386                                             &uap->sysmsg_result);
387                 } else {
388                         error = EINVAL;
389                 }
390                 break;
391         case SYSLINK_CMD_REM:
392                 slrouter = slrouter_rb_tree_RB_LOOKUP(&slrouter_rb_root,
393                                                       info.sysid);
394                 if (slrouter) {
395                         ++slrouter->refs;
396                         sldata = sldata_rb_tree_RB_LOOKUP(&slrouter->sldata_rb_root, info.linkid);
397                         if (sldata) {
398                                 ++sldata->refs;
399                                 error = syslink_rem(slrouter, sldata, &info);
400                         } else {
401                                 error = ENOENT;
402                         }
403                 } else {
404                         error = EINVAL;
405                 }
406                 break;
407         case SYSLINK_CMD_FIND:
408                 slrouter = slrouter_rb_tree_RB_LOOKUP(&slrouter_rb_root, info.sysid);
409                 info.flags |= SLIF_ERROR;
410                 if (slrouter) {
411                         ++slrouter->refs;
412                         n = sldata_rb_tree_RB_SCAN(
413                                 &slrouter->sldata_rb_root,
414                                 syslink_cmd_find_cmp, syslink_cmd_find_callback,
415                                 &info);
416                         if (info.flags & SLIF_ERROR)
417                                 error = ENOENT;
418                 } else {
419                         error = EINVAL;
420                 }
421                 break;
422         default:
423                 error = EINVAL;
424                 break;
425         }
426
427         /*
428          * Cleanup
429          */
430         if (sldata)
431                 sldata_rels(sldata);
432         if (slrouter)
433                 slrouter_rels(slrouter);
434         return (error);
435 }
436
437 static
438 int
439 syslink_destroy_callback(struct sldata *sldata, void *data __unused)
440 {
441         ++sldata->refs;
442         if ((sldata->flags & SLIF_RQUIT) == 0) {
443                 sldata->flags |= SLIF_RQUIT;
444                 wakeup(&sldata->rthread);
445         }
446         if ((sldata->flags & SLIF_WQUIT) == 0) {
447                 sldata->flags |= SLIF_WQUIT;
448                 wakeup(&sldata->wthread);
449         }
450         sldata_rels(sldata);
451         return(0);
452 }
453
454 /*
455  * Shutdown all the connections going into this syslink.
456  *
457  * Try to wait for completion, but return after 1 second 
458  * regardless.
459  */
460 static
461 int
462 syslink_destroy(struct slrouter *slrouter)
463 {
464         int retries = 10;
465
466         while (!RB_EMPTY(&slrouter->sldata_rb_root) && retries) {
467                 RB_SCAN(sldata_rb_tree, &slrouter->sldata_rb_root, NULL,
468                         syslink_destroy_callback, slrouter);
469                 --retries;
470                 tsleep(&retries, 0, "syslnk", hz / 10);
471         }
472         if (RB_EMPTY(&slrouter->sldata_rb_root))
473                 return(0);
474         else
475                 return(EINPROGRESS);
476 }
477
478 static
479 int
480 syslink_add(struct slrouter *slrouter, struct syslink_info *info,
481             int *result)
482 {
483         struct sldata *sldata;
484         struct file *fp;
485         int maxphys;
486         int numphys;
487         int linkid;
488         int error;
489
490         error = 0;
491         maxphys = 1 << slrouter->bits;
492         numphys = info->bits ? (1 << info->bits) : 1;
493
494         /*
495          * Create a connection to the route node and allocate a physical ID.
496          * Physical ID 0 is reserved for the route node itself, and an all-1's
497          * ID is reserved as a broadcast address.
498          */
499         sldata = kmalloc(sizeof(struct sldata), M_SYSLINK, M_WAITOK|M_ZERO);
500
501         linkid = alist_alloc(slrouter->bitmap, numphys);
502         if (linkid == ALIST_BLOCK_NONE) {
503                 kfree(sldata, M_SYSLINK);
504                 return (ENOSPC);
505         }
506
507         /*
508          * Insert the node, initializing enough fields to prevent things from
509          * being ripped out from under us before we have a chance to complete
510          * the system call.
511          */
512         sldata->linkid = linkid;
513         sldata->refs = 1;
514         ++slrouter->count;
515         if (sldata_rb_tree_RB_LOOKUP(&slrouter->sldata_rb_root, linkid))
516                 panic("syslink_add: free linkid wasn't free!");
517         RB_INSERT(sldata_rb_tree, &slrouter->sldata_rb_root, sldata);
518
519         /*
520          * Complete initialization of the physical route node.  Setting 
521          * sldata->router activates the node.
522          */
523         sbinit(&sldata->sior, SYSLINK_SIOBUFSIZE);
524         sbinit(&sldata->siow, SYSLINK_SIOBUFSIZE);
525         sldata->bindex = slrouter->bbuf.windex;
526         sldata->flags = info->flags & SLIF_USERFLAGS;
527         lockinit(&sldata->rlock, "slread", 0, 0);
528         lockinit(&sldata->wlock, "slwrite", 0, 0);
529         bcopy(&info->u.sa, &sldata->sa, sizeof(sldata->sa));
530
531         if (info->fd < 0) {
532                 /*
533                  * We create a direct syslink descriptor.  No helper threads
534                  * are needed.
535                  */
536                 error = falloc(curproc, &fp, &info->fd);
537                 if (error == 0) {
538                         fp->f_type = DTYPE_SYSLINK;
539                         fp->f_flag = FREAD | FWRITE;
540                         fp->f_ops = &syslinkops;
541                         fp->f_data = sldata;
542                         /* one ref: the fp descriptor */
543                         sldata->refs += 1;
544                         sldata->flags |= SLIF_WQUIT | SLIF_WDONE;
545                         sldata->flags |= SLIF_RQUIT | SLIF_RDONE;
546                         fsetfd(curproc, fp, info->fd);
547                         fdrop(fp);
548                         *result = info->fd;
549                 }
550         } else {
551                 sldata->xfp = holdfp(curproc->p_fd, info->fd, -1);
552                 if (sldata->xfp != NULL) {
553                         /* two refs: reader thread and writer thread */
554                         sldata->refs += 2;
555                         if (sldata->xfp->f_type == DTYPE_SOCKET) {
556                                 lwkt_create(syslink_rthread_so, sldata,
557                                             &sldata->rthread, NULL,
558                                             0, -1, "syslink_r");
559                                 lwkt_create(syslink_wthread_so, sldata,
560                                             &sldata->wthread, NULL,
561                                             0, -1, "syslink_w");
562                         } else {
563                                 lwkt_create(syslink_rthread_fp, sldata,
564                                             &sldata->rthread, NULL,
565                                             0, -1, "syslink_r");
566                                 lwkt_create(syslink_wthread_fp, sldata,
567                                             &sldata->wthread, NULL,
568                                             0, -1, "syslink_w");
569                         }
570                 } else {
571                         error = EBADF;
572                 }
573         }
574         sldata->router = slrouter;
575         sldata_rels(sldata);
576         return(error);
577 }
578
579 static
580 int
581 syslink_rem(struct slrouter *slrouter, struct sldata *sldata,
582             struct syslink_info *info)
583 {
584         int error = EINPROGRESS;
585
586         if ((sldata->flags & SLIF_RQUIT) == 0) {
587                 sldata->flags |= SLIF_RQUIT;
588                 wakeup(&sldata->rthread);
589                 error = 0;
590         }
591         if ((sldata->flags & SLIF_WQUIT) == 0) {
592                 sldata->flags |= SLIF_WQUIT;
593                 wakeup(&sldata->wthread);
594                 error = 0;
595         }
596         return(error);
597 }
598
599 /*
600  * Read syslink messages from an external socket and route them.
601  */
602 static
603 void
604 syslink_rthread_so(void *arg)
605 {
606         struct sldata *sldata = arg;
607         struct socket *so;
608         struct sockaddr *sa;
609         struct mbuf *m;
610         int soflags;
611         int linkid;
612         int error;
613         int needsa;
614
615         so = (void *)sldata->xfp->f_data;
616         sa = NULL;
617
618         /*
619          * Calculate whether we need to get the peer address or not.
620          * We need to obtain the peer address for packet-mode sockets
621          * representing subnets (rather then single connections).
622          */
623         needsa = (sldata->bits && (sldata->flags & SLIF_PACKET));
624
625         while ((sldata->flags & SLIF_RQUIT) == 0) {
626                 /*
627                  * Read some data.  This is easy if the data is packetized,
628                  * otherwise we can still obtain an mbuf chain but we have
629                  * to parse out the syslink messages.
630                  */
631                 soflags = 0;
632                 error = so_pru_soreceive(so,
633                                          (needsa ? &sa : NULL),
634                                          NULL, &sldata->sior,
635                                          NULL, &soflags);
636
637                 /*
638                  * The target is responsible for adjusting the src address
639                  * field in the syslink_msg.  We may need subnet information
640                  * from the sockaddr to accomplish this.
641                  *
642                  * For streams representing subnets the originator is
643                  * responsible for tagging its subnet bits in the src
644                  * address but we have to renormalize
645                  */
646                 linkid = sldata->linkid;
647                 if (sldata->flags & SLIF_PACKET) {
648                         if (sldata->bits) {
649                                 linkid += syslink_getsubnet(sa) &
650                                           ((1 << sldata->bits) - 1);
651                         }
652                         if ((m = sldata->sior.sb_mb) != NULL) {
653                                 sbinit(&sldata->sior, SYSLINK_SIOBUFSIZE);
654                                 syslink_route(sldata->router, linkid, m);
655                         }
656                 } else {
657                         while ((m = syslink_parse_stream(&sldata->sior)) != NULL) {
658                                 syslink_route(sldata->router, linkid, m);
659                         }
660                 }
661         
662
663
664                 /*
665                  * 
666                  */
667                 if ((sldata->flags & SLIF_SUBNET) && sldata->bits && sa) {
668                         linkid += syslink_getsubnet(sa) &
669                                   ((1 << sldata->bits) - 1);
670                         FREE(sa, M_SONAME);
671                 } 
672                 if (error)
673                         break;
674
675                 /*
676                  * Note: Incoming syslink messages must have their headers
677                  * adjusted to reflect the origination address.  This will
678                  * be handled by syslink_route.
679                  */
680                 if (sldata->flags & SLIF_PACKET) {
681                         /*
682                          * Packetized data can just be directly routed.
683                          */
684                         if ((m = sldata->sior.sb_mb) != NULL) {
685                                 sbinit(&sldata->sior, SYSLINK_SIOBUFSIZE);
686                                 syslink_route(sldata->router, linkid, m);
687                         }
688                 } else {
689                         /*
690                          * Stream data has to be parsed out.
691                          */
692                         while ((m = syslink_parse_stream(&sldata->sior)) != NULL) {
693                                 syslink_route(sldata->router, linkid, m);
694                         }
695                 }
696         }
697
698         /*
699          * Mark us as done and deref sldata.  Tell the writer to terminate as
700          * well.
701          */
702         sldata->flags |= SLIF_RDONE;
703         sbflush(&sldata->sior);
704         sbflush(&sldata->siow);
705         if ((sldata->flags & SLIF_WDONE) == 0) {
706                 sldata->flags |= SLIF_WQUIT;
707                 wakeup(&sldata->wthread);
708         }
709         wakeup(&sldata->rthread);
710         wakeup(&sldata->wthread);
711         sldata_rels(sldata);
712 }
713
714 /*
715  * Read syslink messages from an external descriptor and route them.  Used
716  * when no socket interface is available.
717  */
718 static
719 void
720 syslink_rthread_fp(void *arg)
721 {
722         struct sldata *sldata = arg;
723
724 #if 0
725         /*
726          * Loop until told otherwise
727          */
728         while ((sldata->flags & SLIF_RQUIT) == 0) {
729                 error = fp_read(slink->xfp,
730                                 slbuf->buf +
731                                 (slbuf->windex & slbuf->bufmask
732                                 ),
733                                 count, &count, 0, UIO_SYSSPACE);
734         }
735 #endif
736
737         /*
738          * Mark us as done and deref sldata.  Tell the writer to terminate as
739          * well.
740          */
741         sldata->flags |= SLIF_RDONE;
742         sbflush(&sldata->sior);
743         sbflush(&sldata->siow);
744         if ((sldata->flags & SLIF_WDONE) == 0) {
745                 sldata->flags |= SLIF_WQUIT;
746                 wakeup(&sldata->wthread);
747         }
748         wakeup(&sldata->rthread);
749         wakeup(&sldata->wthread);
750         sldata_rels(sldata);
751 }
752
753 static
754 struct mbuf *
755 syslink_parse_stream(struct sockbuf *sio)
756 {
757         return(NULL);
758 }
759
760 static
761 void
762 syslink_route(struct slrouter *slrouter, int linkid, struct mbuf *m)
763 {
764         m_freem(m);
765 }
766
767 #if 0
768
769
770                 int count;
771                 int used;
772                 int error;
773
774                 /*
775                  * Calculate contiguous space available to read and read as
776                  * much as possible.
777                  *
778                  * If the entire buffer is used there's probably a format
779                  * error of some sort and we terminate the link.
780                  */
781                 used = slbuf->windex - slbuf->rindex;
782                 error = 0;
783
784                 /*
785                  * Read some data, terminate the link if an error occurs or
786                  * if EOF is encountered.  xfp can be NULL, indicating that
787                  * the data was injected by other means.
788                  */
789                 if (sldata->xfp) {
790                         count = slbuf->bufsize - 
791                                 (slbuf->windex & slbuf->bufmask);
792                         if (count > slbuf->bufsize - used)
793                                 count = slbuf->bufsize - used;
794                         if (count == 0)
795                                 break;
796                         error = fp_read(sldata->xfp,
797                                         slbuf->buf + 
798                                          (slbuf->windex & slbuf->bufmask),
799                                         count, &count, 0, UIO_SYSSPACE);
800                         if (error)
801                                 break;
802                         if (count == 0)
803                                 break;
804                         slbuf->windex += count;
805                         used += count;
806                 } else {
807                         tsleep(slbuf, 0, "fiford", 0);
808                 }
809
810                 /*
811                  * Process as many syslink messages as we can.  The record
812                  * length must be at least a minimal PAD record (8 bytes).
813                  */
814                 while (slbuf->windex - slbuf->rindex >= min_msg_size) {
815                         int aligned_reclen;
816
817                         head = (void *)(slbuf->buf + 
818                                         (slbuf->rindex & slbuf->bufmask));
819                         if (head->sm_bytes < min_msg_size) {
820                                 error = EINVAL;
821                                 break;
822                         }
823                         aligned_reclen = SLMSG_ALIGN(head->sm_bytes);
824
825                         /*
826                          * Disallow wraps
827                          */
828                         if ((slbuf->rindex & slbuf->bufmask) >
829                             ((slbuf->rindex + aligned_reclen) & slbuf->bufmask)
830                         ) {
831                                 error = EINVAL;
832                                 break;
833                         }
834
835                         /*
836                          * Insufficient data read
837                          */
838                         if (slbuf->windex - slbuf->rindex < aligned_reclen)
839                                 break;
840
841                         /*
842                          * Process non-pad messages.  Non-pad messages have
843                          * to be at least the size of the syslink_msg
844                          * structure.
845                          *
846                          * A PAD message's sm_cmd field contains 0.
847                          */
848                         if (head->sm_cmd) {
849                                 if (head->sm_bytes < sizeof(*head)) {
850                                         error = EINVAL;
851                                         break;
852                                 }
853                                 error = process_syslink_msg(sldata, head);
854                                 if (error)
855                                         break;
856                         }
857                         cpu_sfence();
858                         slbuf->rindex += aligned_reclen;
859                 }
860                 if (error)
861                         break;
862         }
863
864 }
865
866 #endif
867
868 /*
869  * This thread takes outgoing syslink messages queued to wbuf and writes them
870  * to the descriptor.  PAD is stripped.  PAD is also added as required to
871  * conform to the outgoing descriptor's buffering requirements.
872  */
873 static
874 void
875 syslink_wthread_so(void *arg)
876 {
877         struct sldata *sldata = arg;
878         struct slrouter *slrouter;
879         struct syslink_msg *head;
880         struct sockaddr *sa;
881         struct socket *so;
882         struct iovec aiov;
883         struct uio auio;
884         int error;
885         int avail;
886         int bytes;
887
888 #if 0
889         so = (void *)sldata->xfp->f_data;
890         slrouter = sldata->router;
891
892         while ((sldata->flags & SLIF_WQUIT) == 0) {
893                 /*
894                  * Deal with any broadcast data sitting in the route node's
895                  * broadcast buffer.  If we have fallen too far behind the
896                  * data may no longer be valid.
897                  *
898                  * avail -- available data in broadcast buffer and
899                  * bytes -- available contiguous data in broadcast buffer
900                  */
901                 if (slrouter->bbuf.rindex - sldata->bindex > 0)
902                         sldata->bindex = slrouter->bbuf.rindex;
903                 if ((avail = slrouter->bbuf.windex - sldata->bindex) > 0) {
904                         bytes = slrouter->bbuf.bufsize -
905                                 (sldata->bindex & slrouter->bbuf.bufmask);
906                         if (bytes > avail)
907                                 bytes = avail;
908                         head = (void *)(slrouter->bbuf.buf +
909                                 (sldata->bindex & slrouter->bbuf.bufmask));
910                         /*
911                          * Break into packets if necessary, else just write
912                          * it all in one fell swoop.
913                          */
914                         aiov.iov_base = (void *)head;
915                         aiov.iov_len = bytes;
916                         auio.uio_iov = &aiov;
917                         auio.uio_iovcnt = 1;
918                         auio.uio_offset = 0;
919                         auio.uio_resid = bytes;
920                         auio.uio_segflg = UIO_SYSSPACE;
921                         auio.uio_rw = UIO_WRITE;
922                         auio.uio_td = curthread;
923                         if (sldata->flags & SLIF_PACKET) {
924                                 if (head->sm_bytes < SL_MIN_MESSAGE_SIZE) {
925                                         kprintf("syslink_msg too small, terminating\n");
926                                         break;
927                                 }
928                                 if (head->sm_bytes > bytes) {
929                                         kprintf("syslink_msg not FIFO aligned, terminating\n");
930                                         break;
931                                 }
932                                 bytes = SLMSG_ALIGN(head->sm_bytes);
933                                 so_pru_sosend(so, sa, &auio, NULL, NULL, 0, curthread);
934                         } else {
935                                 so_pru_sosend(so, sa, &auio, NULL, NULL, 0, curthread);
936                         }
937                         continue;
938                 }
939
940                 /*
941                  * Deal with mbuf records waiting to be output
942                  */
943                 if (sldata->siow.sb_mb != NULL) {
944                         
945                 }
946
947                 /*
948                  * Block waiting for something to do.
949                  */
950                 tsleep(&sldata->wthread, 0, "wait", 0);
951         }
952
953
954                 error = 0;
955                 for (;;) {
956                         int aligned_reclen;
957                         int used;
958                         int count;
959
960                         used = slbuf->windex - slbuf->rindex;
961                         if (used < SL_MIN_MESSAGE_SIZE)
962                                 break;
963
964                         head = (void *)(slbuf->buf + 
965                                         (slbuf->rindex & slbuf->bufmask));
966                         if (head->sm_bytes < SL_MIN_MESSAGE_SIZE) {
967                                 error = EINVAL;
968                                 break;
969                         }
970                         aligned_reclen = SLMSG_ALIGN(head->sm_bytes);
971
972                         /*
973                          * Disallow wraps
974                          */
975                         if ((slbuf->rindex & slbuf->bufmask) >
976                             ((slbuf->rindex + aligned_reclen) & slbuf->bufmask)
977                         ) {
978                                 error = EINVAL;
979                                 break;
980                         }
981
982                         /*
983                          * Insufficient data read
984                          */
985                         if (used < aligned_reclen)
986                                 break;
987
988                         /*
989                          * Write it out whether it is PAD or not.
990                          * XXX re-PAD for output here.
991                          */
992                         error = fp_write(sldata->xfp, head,
993                                          aligned_reclen,
994                                          &count,
995                                          UIO_SYSSPACE);
996                         if (error && error != ENOBUFS)
997                                 break;
998                         if (count != aligned_reclen) {
999                                 error = EIO;
1000                                 break;
1001                         }
1002                         slbuf->rindex += aligned_reclen;
1003                 }
1004                 if (error)
1005                         break;
1006                 tsleep(slbuf, 0, "fifowt", 0);
1007         }
1008 #endif
1009         sldata->flags |= SLIF_WDONE;
1010         sldata_rels(sldata);
1011 }
1012
1013 static
1014 void
1015 syslink_wthread_fp(void *arg)
1016 {
1017         struct sldata *sldata = arg;
1018
1019         sldata->flags |= SLIF_WDONE;
1020         sldata_rels(sldata);
1021 }
1022
1023 static
1024 void
1025 slbuf_alloc(struct slbuf *slbuf, int bytes)
1026 {
1027         bzero(slbuf, sizeof(*slbuf));
1028         slbuf->buf = kmalloc(bytes, M_SYSLINK, M_WAITOK);
1029         slbuf->bufsize = bytes;
1030         slbuf->bufmask = bytes - 1;
1031 }
1032
1033 static
1034 void
1035 slbuf_free(struct slbuf *slbuf)
1036 {
1037         kfree(slbuf->buf, M_SYSLINK);
1038         slbuf->buf = NULL;
1039 }
1040
1041 static
1042 void
1043 sldata_rels(struct sldata *sldata)
1044 {
1045         struct slrouter *slrouter;
1046
1047         if (--sldata->refs == 0) {
1048                 slrouter = sldata->router;
1049                 KKASSERT(slrouter != NULL);
1050                 ++slrouter->refs;
1051                 RB_REMOVE(sldata_rb_tree, 
1052                           &sldata->router->sldata_rb_root, sldata);
1053                 sldata->router = NULL;
1054                 kfree(sldata, M_SYSLINK);
1055                 slrouter_rels(slrouter);
1056         }
1057 }
1058
1059 static
1060 void
1061 slrouter_rels(struct slrouter *slrouter)
1062 {
1063         if (--slrouter->refs == 0 && RB_EMPTY(&slrouter->sldata_rb_root)) {
1064                 KKASSERT(slrouter->flags & SLIF_DESTROYED);
1065                 RB_REMOVE(slrouter_rb_tree, &slrouter_rb_root, slrouter);
1066                 alist_destroy(slrouter->bitmap, M_SYSLINK);
1067                 slrouter->bitmap = NULL;
1068                 slbuf_free(&slrouter->bbuf);
1069                 kfree(slrouter, M_SYSLINK);
1070         }
1071 }
1072
1073 /*
1074  * A switched ethernet socket connected to a syslink router node may
1075  * represent an entire subnet.  We need to generate a subnet id from
1076  * the originating IP address which the caller can then incorporate into
1077  * the base linkid assigned to the connection to form the actual linkid
1078  * originating the message.
1079  */
1080 static
1081 int
1082 syslink_getsubnet(struct sockaddr *sa)
1083 {
1084         struct in_addr *i4;
1085         struct in6_addr *i6;
1086         int linkid;
1087
1088         switch(sa->sa_family) {
1089         case AF_INET:
1090                 i4 = &((struct sockaddr_in *)sa)->sin_addr;
1091                 linkid = (int)ntohl(i4->s_addr);
1092                 break;
1093         case AF_INET6:
1094                 i6 = &((struct sockaddr_in6 *)sa)->sin6_addr;
1095                 linkid = (int)ntohl(i6->s6_addr32[0]); /* XXX */
1096                 break;
1097         default:
1098                 linkid = 0;
1099                 break;
1100         }
1101         return(linkid);
1102 }
1103
1104 /*
1105  * fileops for an established syslink when the kernel is asked to create a
1106  * descriptor (verses one being handed to it).  No threads are created in
1107  * this case.
1108  */
1109
1110 /*
1111  * Transfer zero or more messages from the kernel to userland.  Only complete
1112  * messages are returned.  If the uio has insufficient space then EMSGSIZE
1113  * is returned.  The kernel feeds messages to wbuf so we use wlock (structures
1114  * are relative to the kernel).
1115  */
1116 static
1117 int
1118 syslink_read(struct file *fp, struct uio *uio, struct ucred *cred, int flags)
1119 {
1120         struct sldata *sldata = fp->f_data;
1121 #if 0
1122         struct syslink_msg *head;
1123         int bytes;
1124         int contig;
1125 #endif
1126         int error;
1127         int nbio;
1128
1129         if (flags & O_FBLOCKING)
1130                 nbio = 0;
1131         else if (flags & O_FNONBLOCKING)
1132                 nbio = 1;
1133         else if (fp->f_flag & O_NONBLOCK)
1134                 nbio = 1;
1135         else
1136                 nbio = 0;
1137
1138         lockmgr(&sldata->wlock, LK_EXCLUSIVE | LK_RETRY);
1139         error = 0;
1140
1141 #if 0
1142         /*
1143          * Calculate the number of bytes we can transfer in one shot.  Transfers
1144          * do not wrap the FIFO.
1145          */
1146         contig = slbuf->bufsize - (slbuf->rindex & slbuf->bufmask);
1147         for (;;) {
1148                 bytes = slbuf->windex - slbuf->rindex;
1149                 if (bytes)
1150                         break;
1151                 if (sldata->flags & SLIF_RDONE) {
1152                         error = EIO;
1153                         break;
1154                 }
1155                 if (nbio) {
1156                         error = EAGAIN;
1157                         goto done;
1158                 }
1159                 tsleep(slbuf, 0, "fiford", 0);
1160         }
1161         if (bytes > contig)
1162                 bytes = contig;
1163
1164         /*
1165          * The uio must be able to accomodate the transfer.
1166          */
1167         if (uio->uio_resid < bytes) {
1168                 error = ENOSPC;
1169                 goto done;
1170         }
1171
1172         /*
1173          * Copy the data to userland and update rindex.
1174          */
1175         head = (void *)(slbuf->buf + (slbuf->rindex & slbuf->bufmask));
1176         error = uiomove((caddr_t)head, bytes, uio);
1177         if (error == 0)
1178                 slbuf->rindex += bytes;
1179
1180         /*
1181          * Cleanup
1182          */
1183 done:
1184 #endif
1185         lockmgr(&sldata->wlock, LK_RELEASE);
1186         return (error);
1187 }
1188
1189 /*
1190  * Transfer zero or more messages from userland to the kernel.  Only complete
1191  * messages may be written.  The kernel processes from rbuf so that is where
1192  * we have to copy the messages.
1193  */
1194 static
1195 int
1196 syslink_write (struct file *fp, struct uio *uio, struct ucred *cred, int flags)
1197 {
1198         struct sldata *sldata = fp->f_data;
1199 #if 0
1200         struct slbuf *slbuf = &sldata->rbuf;
1201         struct syslink_msg *head;
1202         int bytes;
1203         int contig;
1204 #endif
1205         int nbio;
1206         int error;
1207
1208         if (flags & O_FBLOCKING)
1209                 nbio = 0;
1210         else if (flags & O_FNONBLOCKING)
1211                 nbio = 1;
1212         else if (fp->f_flag & O_NONBLOCK)
1213                 nbio = 1;
1214         else
1215                 nbio = 0;
1216
1217         lockmgr(&sldata->rlock, LK_EXCLUSIVE | LK_RETRY);
1218         error = 0;
1219
1220 #if 0
1221         /* 
1222          * Calculate the maximum number of contiguous bytes that may be
1223          * available.  Caller is required to not wrap our FIFO.
1224          */
1225         contig = slbuf->bufsize - (slbuf->windex & slbuf->bufmask);
1226         if (uio->uio_resid > contig) {
1227                 error = ENOSPC;
1228                 goto done;
1229         }
1230
1231         /*
1232          * Truncate based on actual unused space available in the FIFO.  If
1233          * the uio does not fit, block and loop.
1234          */
1235         for (;;) {
1236                 bytes = slbuf->bufsize - (slbuf->windex - slbuf->rindex);
1237                 if (bytes > contig)
1238                         bytes = contig;
1239                 if (uio->uio_resid <= bytes)
1240                         break;
1241                 if (sldata->flags & SLIF_RDONE) {
1242                         error = EIO;
1243                         goto done;
1244                 }
1245                 if (nbio) {
1246                     error = EAGAIN;
1247                     goto done;
1248                 }
1249                 tsleep(slbuf, 0, "fifowr", 0);
1250         }
1251         bytes = uio->uio_resid;
1252         head = (void *)(slbuf->buf + (slbuf->windex & slbuf->bufmask));
1253         error = uiomove((caddr_t)head, bytes, uio);
1254         if (error == 0)
1255                 error = syslink_validate(head, bytes);
1256         if (error == 0) {
1257                 slbuf->windex += bytes;
1258                 wakeup(slbuf);
1259         }
1260 done:
1261 #endif
1262         lockmgr(&sldata->rlock, LK_RELEASE);
1263         return(error);
1264 }
1265
1266 static
1267 int
1268 syslink_close (struct file *fp)
1269 {
1270         struct sldata *sldata;
1271
1272         sldata = fp->f_data;
1273         if ((sldata->flags & SLIF_RQUIT) == 0) {
1274                 sldata->flags |= SLIF_RQUIT;
1275                 wakeup(&sldata->rthread);
1276         }
1277         if ((sldata->flags & SLIF_WQUIT) == 0) {
1278                 sldata->flags |= SLIF_WQUIT;
1279                 wakeup(&sldata->wthread);
1280         }
1281         fp->f_data = NULL;
1282         sldata_rels(sldata);
1283         return(0);
1284 }
1285
1286 static
1287 int
1288 syslink_stat (struct file *fp, struct stat *sb, struct ucred *cred)
1289 {
1290         return(EINVAL);
1291 }
1292
1293 static
1294 int
1295 syslink_shutdown (struct file *fp, int how)
1296 {
1297         return(EINVAL);
1298 }
1299
1300 static
1301 int
1302 syslink_ioctl (struct file *fp, u_long cmd, caddr_t data, struct ucred *cred)
1303 {
1304         return(EINVAL);
1305 }
1306
1307 static
1308 int
1309 syslink_poll (struct file *fp, int events, struct ucred *cred)
1310 {
1311         return(0);
1312 }
1313
1314 static
1315 int
1316 syslink_kqfilter(struct file *fp, struct knote *kn)
1317 {
1318         return(0);
1319 }
1320
1321 /*
1322  * This routine is called from a route node's reader thread to process a
1323  * syslink message once it has been completely read and its size validated.
1324  */
1325 static
1326 int
1327 process_syslink_msg(struct sldata *sldata, struct syslink_msg *head)
1328 {
1329         kprintf("process syslink msg %08x\n", head->sm_cmd);
1330         return(0);
1331 }
1332
1333 /*
1334  * Validate that the syslink message header(s) are correctly sized.
1335  */
1336 static
1337 int
1338 syslink_validate(struct syslink_msg *head, int bytes)
1339 {
1340         const int min_msg_size = SL_MIN_MESSAGE_SIZE;
1341         int aligned_reclen;
1342
1343         while (bytes) {
1344                 /*
1345                  * Message size and alignment
1346                  */
1347                 if (bytes < min_msg_size)
1348                         return (EINVAL);
1349                 if (bytes & SL_ALIGNMASK)
1350                         return (EINVAL);
1351                 if (head->sm_cmd && bytes < sizeof(struct syslink_msg))
1352                         return (EINVAL);
1353
1354                 /*
1355                  * Buffer must contain entire record
1356                  */
1357                 aligned_reclen = SLMSG_ALIGN(head->sm_bytes);
1358                 if (bytes < aligned_reclen)
1359                         return (EINVAL);
1360                 bytes -= aligned_reclen;
1361                 head = (void *)((char *)head + aligned_reclen);
1362         }
1363         return(0);
1364 }
1365