Merge from vendor branch TNFTP:
[dragonfly.git] / sys / kern / kern_syslink.c
1 /*
2  * Copyright (c) 2006 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.8 2007/04/16 17:40:13 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
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
45 #include <sys/malloc.h>
46 #include <sys/alist.h>
47 #include <sys/file.h>
48 #include <sys/proc.h>
49 #include <sys/lock.h>
50 #include <sys/uio.h>
51 #include <sys/thread.h>
52 #include <sys/tree.h>
53 #include <sys/sysctl.h>
54 #include <sys/sysproto.h>
55 #include <sys/syslink.h>
56 #include <sys/syslink_msg.h>
57
58 #include <sys/thread2.h>
59
60 /*
61  * Red-Black trees organizing the syslink 'router' nodes and connections
62  * to router nodes.
63  */
64 struct slrouter;
65 struct sldata;
66
67 RB_HEAD(slrouter_rb_tree, slrouter);
68 RB_HEAD(sldata_rb_tree, sldata);
69 RB_PROTOTYPE2(slrouter_rb_tree, slrouter, rbnode,
70               rb_slrouter_compare, sysid_t);
71 RB_PROTOTYPE2(sldata_rb_tree, sldata, rbnode,
72               rb_sldata_compare, int);
73
74 struct slrouter {
75         RB_ENTRY(slrouter) rbnode;              /* list of routers */
76         struct sldata_rb_tree sldata_rb_root;   /* connections to router */
77         sysid_t sysid;                          /* logical sysid of router */
78         int flags;                              /* flags passed on create */
79         int bits;                               /* accomodate connections */
80         int count;                              /* number of connections */
81         int refs;
82         alist_t bitmap;
83         char label[SYSLINK_LABEL_SIZE];
84 };
85
86 /*
87  * fileops interface.  slbuf and sldata are also used in conjunction with a
88  * normal file descriptor.
89  */
90 struct slbuf {
91         char    *buf;
92         int     bufsize;        /* must be a power of 2 */
93         int     bufmask;        /* (bufsize - 1) */
94         int     rindex;         /* tail-chasing FIFO indices */
95         int     windex;
96 };
97
98 struct sldata {
99         RB_ENTRY(sldata) rbnode;
100         struct slrouter *router;        /* organizing router */
101         struct slbuf    rbuf;
102         struct slbuf    wbuf;
103         struct file     *xfp;           /* external file pointer */
104         struct lock     rlock;          /* synchronizing lock */
105         struct lock     wlock;          /* synchronizing lock */
106         struct thread   *rthread;       /* xfp -> rbuf & process */
107         struct thread   *wthread;       /* wbuf -> xfp */
108         int     flags;                  /* connection flags */
109         int     linkid;
110         int     bits;
111         int     refs;
112         char    label[SYSLINK_LABEL_SIZE];
113 };
114
115 /*
116  * syslink kernel thread support flags
117  */
118 #define SLF_RQUIT       0x0001
119 #define SLF_WQUIT       0x0002
120 #define SLF_RDONE       0x0004
121 #define SLF_WDONE       0x0008
122 #define SLF_DESTROYED   0x8000
123
124 #define SYSLINK_BUFSIZE (128*1024)
125
126 static int rb_slrouter_compare(struct slrouter *r1, struct slrouter *r2);
127 static int rb_sldata_compare(struct sldata *d1, struct sldata *d2);
128
129 static int syslink_destroy(struct slrouter *slrouter);
130 static int syslink_add(struct slrouter *slrouter, int fd,
131                         struct syslink_info *info, int *result);
132 static int syslink_rem(struct slrouter *slrouter, struct sldata *sldata,
133                         struct syslink_info *info);
134
135 static int syslink_read(struct file *fp, struct uio *uio,
136                         struct ucred *cred, int flags);
137 static int syslink_write(struct file *fp, struct uio *uio,
138                          struct ucred *cred, int flags);
139 static int syslink_close(struct file *fp);
140 static int syslink_stat(struct file *fp, struct stat *sb, struct ucred *cred);
141 static int syslink_shutdown(struct file *fp, int how);
142 static int syslink_ioctl(struct file *fp, u_long cmd, caddr_t data,
143                          struct ucred *cred);
144 static int syslink_poll(struct file *fp, int events, struct ucred *cred);
145 static int syslink_kqfilter(struct file *fp, struct knote *kn);
146
147 static void syslink_rthread(void *arg);
148 static void syslink_wthread(void *arg);
149 static void slbuf_alloc(struct slbuf *buf, int bytes);
150 static void slbuf_free(struct slbuf *buf);
151 static void sldata_rels(struct sldata *sldata);
152 static void slrouter_rels(struct slrouter *slrouter);
153 static int process_syslink_msg(struct sldata *sldata, struct syslink_msg *head);
154 static int syslink_validate(struct syslink_msg *head, int bytes);
155
156 RB_GENERATE2(slrouter_rb_tree, slrouter, rbnode,
157              rb_slrouter_compare, sysid_t, sysid);
158 RB_GENERATE2(sldata_rb_tree, sldata, rbnode,
159              rb_sldata_compare, int, linkid);
160
161 static struct fileops syslinkops = {
162     .fo_read =          syslink_read,
163     .fo_write =         syslink_write,
164     .fo_ioctl =         syslink_ioctl,
165     .fo_poll =          syslink_poll,
166     .fo_kqfilter =      syslink_kqfilter,
167     .fo_stat =          syslink_stat,
168     .fo_close =         syslink_close,
169     .fo_shutdown =      syslink_shutdown
170 };
171
172 MALLOC_DEFINE(M_SYSLINK, "syslink", "syslink manager");
173
174 static int syslink_enabled;
175 SYSCTL_INT(_kern, OID_AUTO, syslink_enabled,
176             CTLFLAG_RW, &syslink_enabled, 0, "Enable SYSLINK");
177
178 /*
179  * Support declarations and compare function for our RB trees
180  */
181 static struct slrouter_rb_tree slrouter_rb_root;
182
183 static int
184 rb_slrouter_compare(struct slrouter *r1, struct slrouter *r2)
185 {
186         if (r1->sysid < r2->sysid)
187                 return(-1);
188         if (r1->sysid > r2->sysid)
189                 return(1);
190         return(0);
191 }
192
193 static int
194 rb_sldata_compare(struct sldata *d1, struct sldata *d2)
195 {
196         if (d1->linkid < d2->linkid)
197                 return(-1);
198         if (d1->linkid > d2->linkid)
199                 return(1);
200         return(0);
201 }
202
203 /*
204  * Compare and callback functions for first-sysid and first-linkid searches.
205  */
206 static int
207 syslink_cmd_locate_cmp(struct slrouter *slrouter, void *data)
208 {
209         struct syslink_info *info = data;
210
211         if (slrouter->sysid < info->sysid)
212             return(-1);
213         if (slrouter->sysid > info->sysid)
214             return(1);
215         return(0);
216 }
217
218 static int
219 syslink_cmd_locate_callback(struct slrouter *slrouter, void *data)
220 {
221         struct syslink_info *info = data;
222
223         info->flags = slrouter->flags;  /* also clears SLIF_ERROR */
224         bcopy(slrouter->label, info->label, SYSLINK_LABEL_SIZE);
225
226         return(-1);
227 }
228
229 static int
230 syslink_cmd_find_cmp(struct sldata *sldata, void *data)
231 {
232         struct syslink_info *info = data;
233
234         if (sldata->linkid < info->linkid)
235             return(-1);
236         if (sldata->linkid > info->linkid)
237             return(1);
238         return(0);
239 }
240
241 static int
242 syslink_cmd_find_callback(struct sldata *sldata, void *data)
243 {
244         struct syslink_info *info = data;
245
246         info->linkid = sldata->linkid;
247         info->flags = sldata->flags;    /* also clears SLIF_ERROR */
248         bcopy(sldata->label, info->label, SYSLINK_LABEL_SIZE);
249
250         return(-1);
251 }
252
253 /*
254  * Primary system call interface - associate a full-duplex stream
255  * (typically a pipe or a connected socket) with a sysid namespace,
256  * or create a direct link.
257  *
258  * syslink(int fd, int cmd, void *info, size_t *infosize)
259  */
260 int
261 sys_syslink(struct syslink_args *uap)
262 {
263         struct syslink_info info;
264         struct slrouter *slrouter = NULL;
265         struct sldata *sldata = NULL;
266         int error;
267         int n;
268
269         /*
270          * System call is under construction and disabled by default. 
271          * Superuser access is also required.
272          */
273         if (syslink_enabled == 0)
274                 return (EAUTH);
275         error = suser(curthread);
276         if (error)
277                 return (error);
278
279         /*
280          * Load and validate the info structure.  Unloaded bytes are zerod out
281          */
282         bzero(&info, sizeof(info));
283         if ((unsigned)uap->bytes <= sizeof(info)) {
284                 if (uap->bytes)
285                         error = copyin(uap->info, &info, uap->bytes);
286         } else {
287                 error = EINVAL;
288         }
289         if (error)
290                 return (error);
291
292         if (info.label[sizeof(info.label)-1] != 0)
293                 return (EINVAL);
294
295         /*
296          * Process command
297          */
298
299         switch(uap->cmd) {
300         case SYSLINK_CMD_CREATE:
301                 /*
302                  * Create a new syslink router node.  Set refs to prevent the
303                  * router node from being destroyed.  One ref is our temporary
304                  * reference while the other is the SLIF_DESTROYED-interlocked
305                  * reference.
306                  */
307                 if (info.bits < 2 || info.bits > SYSLINK_ROUTER_MAXBITS)
308                         return (EINVAL);
309                 slrouter = kmalloc(sizeof(struct slrouter), M_SYSLINK,
310                                     M_WAITOK|M_ZERO);
311                 if (slrouter_rb_tree_RB_LOOKUP(&slrouter_rb_root, info.sysid)) {
312                         kfree(slrouter, M_SYSLINK);
313                         slrouter = NULL;
314                         return (EINVAL);
315                 }
316                 slrouter->sysid = info.sysid;
317                 slrouter->refs = 2;
318                 slrouter->bits = info.bits;
319                 slrouter->flags = info.flags & SLIF_USERFLAGS;
320                 slrouter->bitmap = alist_create(1 << info.bits, M_SYSLINK);
321                 RB_INIT(&slrouter->sldata_rb_root);
322                 RB_INSERT(slrouter_rb_tree, &slrouter_rb_root, slrouter);
323                 break;
324         case SYSLINK_CMD_DESTROY:
325                 /*
326                  * Destroy a syslink router node.  The physical node is
327                  * not freed until our temporary reference is removed.
328                  */
329                 slrouter = slrouter_rb_tree_RB_LOOKUP(&slrouter_rb_root,
330                                                       info.sysid);
331                 if (slrouter) {
332                         ++slrouter->refs;
333                         if ((slrouter->flags & SLIF_DESTROYED) == 0) {
334                                 slrouter->flags |= SLIF_DESTROYED;
335                                 /* SLIF_DESTROYED interlock */
336                                 slrouter_rels(slrouter);
337                                 error = syslink_destroy(slrouter);
338                                 /* still holding our private interlock */
339                         }
340                 }
341                 break;
342         case SYSLINK_CMD_LOCATE:
343                 /*
344                  * Locate the first syslink router node >= info.sysid
345                  */
346                 info.flags |= SLIF_ERROR;
347                 n = slrouter_rb_tree_RB_SCAN(
348                             &slrouter_rb_root,
349                             syslink_cmd_locate_cmp, syslink_cmd_locate_callback,
350                             &info);
351                 if (info.flags & SLIF_ERROR)
352                         error = ENOENT;
353                 break;
354         case SYSLINK_CMD_ADD:
355                 slrouter = slrouter_rb_tree_RB_LOOKUP(&slrouter_rb_root, info.sysid);
356                 if (info.bits &&
357                     (info.bits < 2 || info.bits > SYSLINK_ROUTER_MAXBITS)) {
358                         error = EINVAL;
359                 } else if (slrouter && (slrouter->flags & SLIF_DESTROYED)) {
360                         /*
361                          * Someone is trying to destroy this route node,
362                          * no new adds please!
363                          */
364                         error = EIO;
365                 } else if (slrouter) {
366                         ++slrouter->refs;
367                         error = syslink_add(slrouter, uap->fd, &info,
368                                             &uap->sysmsg_result);
369                 } else {
370                         error = EINVAL;
371                 }
372                 break;
373         case SYSLINK_CMD_REM:
374                 slrouter = slrouter_rb_tree_RB_LOOKUP(&slrouter_rb_root,
375                                                       info.sysid);
376                 if (slrouter) {
377                         ++slrouter->refs;
378                         sldata = sldata_rb_tree_RB_LOOKUP(&slrouter->sldata_rb_root, info.linkid);
379                         if (sldata) {
380                                 ++sldata->refs;
381                                 error = syslink_rem(slrouter, sldata, &info);
382                         } else {
383                                 error = ENOENT;
384                         }
385                 } else {
386                         error = EINVAL;
387                 }
388                 break;
389         case SYSLINK_CMD_FIND:
390                 slrouter = slrouter_rb_tree_RB_LOOKUP(&slrouter_rb_root, info.sysid);
391                 info.flags |= SLIF_ERROR;
392                 if (slrouter) {
393                         ++slrouter->refs;
394                         n = sldata_rb_tree_RB_SCAN(
395                                 &slrouter->sldata_rb_root,
396                                 syslink_cmd_find_cmp, syslink_cmd_find_callback,
397                                 &info);
398                         if (info.flags & SLIF_ERROR)
399                                 error = ENOENT;
400                 } else {
401                         error = EINVAL;
402                 }
403                 break;
404         default:
405                 error = EINVAL;
406                 break;
407         }
408
409         /*
410          * Cleanup
411          */
412         if (sldata)
413                 sldata_rels(sldata);
414         if (slrouter)
415                 slrouter_rels(slrouter);
416         return (error);
417 }
418
419 static
420 int
421 syslink_destroy_callback(struct sldata *sldata, void *data __unused)
422 {
423         ++sldata->refs;
424         if ((sldata->flags & SLF_RQUIT) == 0) {
425                 sldata->flags |= SLF_RQUIT;
426                 wakeup(&sldata->rbuf);
427         }
428         if ((sldata->flags & SLF_WQUIT) == 0) {
429                 sldata->flags |= SLF_WQUIT;
430                 wakeup(&sldata->wbuf);
431         }
432         sldata_rels(sldata);
433         return(0);
434 }
435
436 /*
437  * Shutdown all the connections going into this syslink.
438  *
439  * Try to wait for completion, but return after 1 second 
440  * regardless.
441  */
442 static
443 int
444 syslink_destroy(struct slrouter *slrouter)
445 {
446         int retries = 10;
447
448         while (!RB_EMPTY(&slrouter->sldata_rb_root) && retries) {
449                 RB_SCAN(sldata_rb_tree, &slrouter->sldata_rb_root, NULL,
450                         syslink_destroy_callback, slrouter);
451                 --retries;
452                 tsleep(&retries, 0, "syslnk", hz / 10);
453         }
454         if (RB_EMPTY(&slrouter->sldata_rb_root))
455                 return(0);
456         else
457                 return(EINPROGRESS);
458 }
459
460 static
461 int
462 syslink_add(struct slrouter *slrouter, int fd, struct syslink_info *info,
463             int *result)
464 {
465         struct sldata *sldata;
466         struct file *fp;
467         int maxphys;
468         int numphys;
469         int linkid;
470         int error;
471
472         error = 0;
473         maxphys = 1 << slrouter->bits;
474         numphys = info->bits ? (1 << info->bits) : 1;
475
476         /*
477          * Create a connection to the route node and allocate a physical ID.
478          * Physical ID 0 is reserved for the route node itself, and an all-1's
479          * ID is reserved as a broadcast address.
480          */
481         sldata = kmalloc(sizeof(struct sldata), M_SYSLINK, M_WAITOK|M_ZERO);
482
483         linkid = alist_alloc(slrouter->bitmap, numphys);
484         if (linkid == ALIST_BLOCK_NONE) {
485                 kfree(sldata, M_SYSLINK);
486                 return (ENOSPC);
487         }
488
489         /*
490          * Insert the node, initializing enough fields to prevent things from
491          * being ripped out from under us before we have a chance to complete
492          * the system call.
493          */
494         sldata->linkid = linkid;
495         sldata->refs = 1;
496         ++slrouter->count;
497         if (sldata_rb_tree_RB_LOOKUP(&slrouter->sldata_rb_root, linkid))
498                 panic("syslink_add: free linkid wasn't free!");
499         RB_INSERT(sldata_rb_tree, &slrouter->sldata_rb_root, sldata);
500
501         /*
502          * Complete initialization of the physical route node.  Setting 
503          * sldata->router activates the node.
504          */
505         lockinit(&sldata->rlock, "slread", 0, 0);
506         lockinit(&sldata->wlock, "slwrite", 0, 0);
507
508         if (fd < 0) {
509                 /*
510                  * We create a direct syslink descriptor.  Only the 
511                  * reader thread is needed.
512                  */
513                 error = falloc(curproc, &fp, &fd);
514                 if (error == 0) {
515                         fp->f_type = DTYPE_SYSLINK;
516                         fp->f_flag = FREAD | FWRITE;
517                         fp->f_ops = &syslinkops;
518                         fp->f_data = sldata;
519                         slbuf_alloc(&sldata->rbuf, SYSLINK_BUFSIZE);
520                         slbuf_alloc(&sldata->wbuf, SYSLINK_BUFSIZE);
521                         /* two refs: reader thread and fp descriptor */
522                         sldata->refs += 2;
523                         sldata->flags = SLF_WQUIT | SLF_WDONE;
524                         lwkt_create(syslink_rthread, sldata,
525                                     &sldata->rthread, NULL,
526                                     0, -1, "syslink_r");
527                         fsetfd(curproc, fp, fd);
528                         fdrop(fp);
529                         *result = fd;
530                 }
531         } else {
532                 sldata->xfp = holdfp(curproc->p_fd, fd, -1);
533                 if (sldata->xfp != NULL) {
534                         slbuf_alloc(&sldata->rbuf, SYSLINK_BUFSIZE);
535                         slbuf_alloc(&sldata->wbuf, SYSLINK_BUFSIZE);
536                         /* two refs: reader thread and writer thread */
537                         sldata->refs += 2;
538                         lwkt_create(syslink_rthread, sldata,
539                                     &sldata->rthread, NULL,
540                                     0, -1, "syslink_r");
541                         lwkt_create(syslink_wthread, sldata,
542                                     &sldata->wthread, NULL,
543                                     0, -1, "syslink_w");
544                 } else {
545                         error = EBADF;
546                 }
547         }
548         sldata->router = slrouter;
549         sldata_rels(sldata);
550         return(error);
551 }
552
553 static
554 int
555 syslink_rem(struct slrouter *slrouter, struct sldata *sldata,
556             struct syslink_info *info)
557 {
558         int error = EINPROGRESS;
559
560         if ((sldata->flags & SLF_RQUIT) == 0) {
561                 sldata->flags |= SLF_RQUIT;
562                 wakeup(&sldata->rbuf);
563                 error = 0;
564         }
565         if ((sldata->flags & SLF_WQUIT) == 0) {
566                 sldata->flags |= SLF_WQUIT;
567                 wakeup(&sldata->wbuf);
568                 error = 0;
569         }
570         return(error);
571 }
572
573 /*
574  * This thread reads from an external descriptor into rbuf, then parses and
575  * dispatches syslink messages from rbuf.
576  */
577 static
578 void
579 syslink_rthread(void *arg)
580 {
581         struct sldata *sldata = arg;
582         struct slbuf *slbuf = &sldata->rbuf;
583         struct syslink_msg *head;
584         const int min_msg_size = SL_MIN_MESSAGE_SIZE;
585
586         while ((sldata->flags & SLF_RQUIT) == 0) {
587                 int count;
588                 int used;
589                 int error;
590
591                 /*
592                  * Calculate contiguous space available to read and read as
593                  * much as possible.
594                  *
595                  * If the entire buffer is used there's probably a format
596                  * error of some sort and we terminate the link.
597                  */
598                 used = slbuf->windex - slbuf->rindex;
599                 error = 0;
600
601                 /*
602                  * Read some data, terminate the link if an error occurs or
603                  * if EOF is encountered.  xfp can be NULL, indicating that
604                  * the data was injected by other means.
605                  */
606                 if (sldata->xfp) {
607                         count = slbuf->bufsize - 
608                                 (slbuf->windex & slbuf->bufmask);
609                         if (count > slbuf->bufsize - used)
610                                 count = slbuf->bufsize - used;
611                         if (count == 0)
612                                 break;
613                         error = fp_read(sldata->xfp,
614                                         slbuf->buf + 
615                                          (slbuf->windex & slbuf->bufmask),
616                                         count, &count, 0, UIO_SYSSPACE);
617                         if (error)
618                                 break;
619                         if (count == 0)
620                                 break;
621                         slbuf->windex += count;
622                         used += count;
623                 } else {
624                         tsleep(slbuf, 0, "fiford", 0);
625                 }
626
627                 /*
628                  * Process as many syslink messages as we can.  The record
629                  * length must be at least a minimal PAD record (8 bytes).
630                  */
631                 while (slbuf->windex - slbuf->rindex >= min_msg_size) {
632                         int aligned_reclen;
633
634                         head = (void *)(slbuf->buf + 
635                                         (slbuf->rindex & slbuf->bufmask));
636                         if (head->sm_bytes < min_msg_size) {
637                                 error = EINVAL;
638                                 break;
639                         }
640                         aligned_reclen = SLMSG_ALIGN(head->sm_bytes);
641
642                         /*
643                          * Disallow wraps
644                          */
645                         if ((slbuf->rindex & slbuf->bufmask) >
646                             ((slbuf->rindex + aligned_reclen) & slbuf->bufmask)
647                         ) {
648                                 error = EINVAL;
649                                 break;
650                         }
651
652                         /*
653                          * Insufficient data read
654                          */
655                         if (slbuf->windex - slbuf->rindex < aligned_reclen)
656                                 break;
657
658                         /*
659                          * Process non-pad messages.  Non-pad messages have
660                          * to be at least the size of the syslink_msg
661                          * structure.
662                          *
663                          * A PAD message's sm_cmd field contains 0.
664                          */
665                         if (head->sm_cmd) {
666                                 if (head->sm_bytes < sizeof(*head)) {
667                                         error = EINVAL;
668                                         break;
669                                 }
670                                 error = process_syslink_msg(sldata, head);
671                                 if (error)
672                                         break;
673                         }
674                         cpu_sfence();
675                         slbuf->rindex += aligned_reclen;
676                 }
677                 if (error)
678                         break;
679         }
680
681         /*
682          * Mark us as done and deref sldata.  Tell the writer to terminate as
683          * well.
684          */
685         sldata->flags |= SLF_RDONE;
686         if ((sldata->flags & SLF_WDONE) == 0) {
687                 sldata->flags |= SLF_WQUIT;
688                 wakeup(&sldata->wbuf);
689         }
690         wakeup(&sldata->rbuf);
691         wakeup(&sldata->wbuf);
692         sldata_rels(sldata);
693 }
694
695 /*
696  * This thread takes outgoing syslink messages queued to wbuf and writes them
697  * to the descriptor.  PAD is stripped.  PAD is also added as required to
698  * conform to the outgoing descriptor's buffering requirements.
699  */
700 static
701 void
702 syslink_wthread(void *arg)
703 {
704         struct sldata *sldata = arg;
705         struct slbuf *slbuf = &sldata->wbuf;
706         struct syslink_msg *head;
707         int error;
708
709         while ((sldata->flags & SLF_WQUIT) == 0) {
710                 error = 0;
711                 for (;;) {
712                         int aligned_reclen;
713                         int used;
714                         int count;
715
716                         used = slbuf->windex - slbuf->rindex;
717                         if (used < SL_MIN_MESSAGE_SIZE)
718                                 break;
719
720                         head = (void *)(slbuf->buf + 
721                                         (slbuf->rindex & slbuf->bufmask));
722                         if (head->sm_bytes < SL_MIN_MESSAGE_SIZE) {
723                                 error = EINVAL;
724                                 break;
725                         }
726                         aligned_reclen = SLMSG_ALIGN(head->sm_bytes);
727
728                         /*
729                          * Disallow wraps
730                          */
731                         if ((slbuf->rindex & slbuf->bufmask) >
732                             ((slbuf->rindex + aligned_reclen) & slbuf->bufmask)
733                         ) {
734                                 error = EINVAL;
735                                 break;
736                         }
737
738                         /*
739                          * Insufficient data read
740                          */
741                         if (used < aligned_reclen)
742                                 break;
743
744                         /*
745                          * Write it out whether it is PAD or not.
746                          * XXX re-PAD for output here.
747                          */
748                         error = fp_write(sldata->xfp, head,
749                                          aligned_reclen,
750                                          &count,
751                                          UIO_SYSSPACE);
752                         if (error && error != ENOBUFS)
753                                 break;
754                         if (count != aligned_reclen) {
755                                 error = EIO;
756                                 break;
757                         }
758                         slbuf->rindex += aligned_reclen;
759                 }
760                 if (error)
761                         break;
762                 tsleep(slbuf, 0, "fifowt", 0);
763         }
764         sldata->flags |= SLF_WDONE;
765         sldata_rels(sldata);
766 }
767
768 static
769 void
770 slbuf_alloc(struct slbuf *slbuf, int bytes)
771 {
772         bzero(slbuf, sizeof(*slbuf));
773         slbuf->buf = kmalloc(bytes, M_SYSLINK, M_WAITOK);
774         slbuf->bufsize = bytes;
775         slbuf->bufmask = bytes - 1;
776 }
777
778 static
779 void
780 slbuf_free(struct slbuf *slbuf)
781 {
782         kfree(slbuf->buf, M_SYSLINK);
783         slbuf->buf = NULL;
784 }
785
786 static
787 void
788 sldata_rels(struct sldata *sldata)
789 {
790         struct slrouter *slrouter;
791
792         if (--sldata->refs == 0) {
793                 slrouter = sldata->router;
794                 KKASSERT(slrouter != NULL);
795                 ++slrouter->refs;
796                 RB_REMOVE(sldata_rb_tree, 
797                           &sldata->router->sldata_rb_root, sldata);
798                 sldata->router = NULL;
799                 slbuf_free(&sldata->rbuf);
800                 slbuf_free(&sldata->wbuf);
801                 kfree(sldata, M_SYSLINK);
802                 slrouter_rels(slrouter);
803         }
804 }
805
806 static
807 void
808 slrouter_rels(struct slrouter *slrouter)
809 {
810         if (--slrouter->refs == 0 && RB_EMPTY(&slrouter->sldata_rb_root)) {
811                 KKASSERT(slrouter->flags & SLIF_DESTROYED);
812                 RB_REMOVE(slrouter_rb_tree, &slrouter_rb_root, slrouter);
813                 alist_destroy(slrouter->bitmap, M_SYSLINK);
814                 slrouter->bitmap = NULL;
815                 kfree(slrouter, M_SYSLINK);
816         }
817 }
818
819 /*
820  * fileops for an established syslink when the kernel is asked to create a
821  * descriptor (verses one being handed to it).  No threads are created in
822  * this case.
823  */
824
825 /*
826  * Transfer zero or more messages from the kernel to userland.  Only complete
827  * messages are returned.  If the uio has insufficient space then EMSGSIZE
828  * is returned.  The kernel feeds messages to wbuf so we use wlock (structures
829  * are relative to the kernel).
830  */
831 static
832 int
833 syslink_read(struct file *fp, struct uio *uio, struct ucred *cred, int flags)
834 {
835         struct sldata *sldata = fp->f_data;
836         struct slbuf *slbuf = &sldata->wbuf;
837         struct syslink_msg *head;
838         int bytes;
839         int contig;
840         int error;
841         int nbio;
842
843         if (flags & O_FBLOCKING)
844                 nbio = 0;
845         else if (flags & O_FNONBLOCKING)
846                 nbio = 1;
847         else if (fp->f_flag & O_NONBLOCK)
848                 nbio = 1;
849         else
850                 nbio = 0;
851
852         lockmgr(&sldata->wlock, LK_EXCLUSIVE | LK_RETRY);
853
854         /*
855          * Calculate the number of bytes we can transfer in one shot.  Transfers
856          * do not wrap the FIFO.
857          */
858         contig = slbuf->bufsize - (slbuf->rindex & slbuf->bufmask);
859         for (;;) {
860                 bytes = slbuf->windex - slbuf->rindex;
861                 if (bytes)
862                         break;
863                 if (sldata->flags & SLF_RDONE) {
864                         error = EIO;
865                         break;
866                 }
867                 if (nbio) {
868                         error = EAGAIN;
869                         goto done;
870                 }
871                 tsleep(slbuf, 0, "fiford", 0);
872         }
873         if (bytes > contig)
874                 bytes = contig;
875
876         /*
877          * The uio must be able to accomodate the transfer.
878          */
879         if (uio->uio_resid < bytes) {
880                 error = ENOSPC;
881                 goto done;
882         }
883
884         /*
885          * Copy the data to userland and update rindex.
886          */
887         head = (void *)(slbuf->buf + (slbuf->rindex & slbuf->bufmask));
888         error = uiomove((caddr_t)head, bytes, uio);
889         if (error == 0)
890                 slbuf->rindex += bytes;
891
892         /*
893          * Cleanup
894          */
895 done:
896         lockmgr(&sldata->wlock, LK_RELEASE);
897         return (error);
898 }
899
900 /*
901  * Transfer zero or more messages from userland to the kernel.  Only complete
902  * messages may be written.  The kernel processes from rbuf so that is where
903  * we have to copy the messages.
904  */
905 static
906 int
907 syslink_write (struct file *fp, struct uio *uio, struct ucred *cred, int flags)
908 {
909         struct sldata *sldata = fp->f_data;
910         struct slbuf *slbuf = &sldata->rbuf;
911         struct syslink_msg *head;
912         int bytes;
913         int contig;
914         int nbio;
915         int error;
916
917         if (flags & O_FBLOCKING)
918                 nbio = 0;
919         else if (flags & O_FNONBLOCKING)
920                 nbio = 1;
921         else if (fp->f_flag & O_NONBLOCK)
922                 nbio = 1;
923         else
924                 nbio = 0;
925
926         lockmgr(&sldata->rlock, LK_EXCLUSIVE | LK_RETRY);
927
928         /* 
929          * Calculate the maximum number of contiguous bytes that may be
930          * available.  Caller is required to not wrap our FIFO.
931          */
932         contig = slbuf->bufsize - (slbuf->windex & slbuf->bufmask);
933         if (uio->uio_resid > contig) {
934                 error = ENOSPC;
935                 goto done;
936         }
937
938         /*
939          * Truncate based on actual unused space available in the FIFO.  If
940          * the uio does not fit, block and loop.
941          */
942         for (;;) {
943                 bytes = slbuf->bufsize - (slbuf->windex - slbuf->rindex);
944                 if (bytes > contig)
945                         bytes = contig;
946                 if (uio->uio_resid <= bytes)
947                         break;
948                 if (sldata->flags & SLF_RDONE) {
949                         error = EIO;
950                         goto done;
951                 }
952                 if (nbio) {
953                     error = EAGAIN;
954                     goto done;
955                 }
956                 tsleep(slbuf, 0, "fifowr", 0);
957         }
958         bytes = uio->uio_resid;
959         head = (void *)(slbuf->buf + (slbuf->windex & slbuf->bufmask));
960         error = uiomove((caddr_t)head, bytes, uio);
961         if (error == 0)
962                 error = syslink_validate(head, bytes);
963         if (error == 0) {
964                 slbuf->windex += bytes;
965                 wakeup(slbuf);
966         }
967 done:
968         lockmgr(&sldata->rlock, LK_RELEASE);
969         return(error);
970 }
971
972 static
973 int
974 syslink_close (struct file *fp)
975 {
976         struct sldata *sldata;
977
978         sldata = fp->f_data;
979         if ((sldata->flags & SLF_RQUIT) == 0) {
980                 sldata->flags |= SLF_RQUIT;
981                 wakeup(&sldata->rbuf);
982         }
983         if ((sldata->flags & SLF_WQUIT) == 0) {
984                 sldata->flags |= SLF_WQUIT;
985                 wakeup(&sldata->wbuf);
986         }
987         fp->f_data = NULL;
988         sldata_rels(sldata);
989         return(0);
990 }
991
992 static
993 int
994 syslink_stat (struct file *fp, struct stat *sb, struct ucred *cred)
995 {
996         return(EINVAL);
997 }
998
999 static
1000 int
1001 syslink_shutdown (struct file *fp, int how)
1002 {
1003         return(EINVAL);
1004 }
1005
1006 static
1007 int
1008 syslink_ioctl (struct file *fp, u_long cmd, caddr_t data, struct ucred *cred)
1009 {
1010         return(EINVAL);
1011 }
1012
1013 static
1014 int
1015 syslink_poll (struct file *fp, int events, struct ucred *cred)
1016 {
1017         return(0);
1018 }
1019
1020 static
1021 int
1022 syslink_kqfilter(struct file *fp, struct knote *kn)
1023 {
1024         return(0);
1025 }
1026
1027 /*
1028  * This routine is called from a route node's reader thread to process a
1029  * syslink message once it has been completely read and its size validated.
1030  */
1031 static
1032 int
1033 process_syslink_msg(struct sldata *sldata, struct syslink_msg *head)
1034 {
1035         kprintf("process syslink msg %08x\n", head->sm_cmd);
1036         return(0);
1037 }
1038
1039 /*
1040  * Validate that the syslink message header(s) are correctly sized.
1041  */
1042 static
1043 int
1044 syslink_validate(struct syslink_msg *head, int bytes)
1045 {
1046         const int min_msg_size = SL_MIN_MESSAGE_SIZE;
1047         int aligned_reclen;
1048
1049         while (bytes) {
1050                 /*
1051                  * Message size and alignment
1052                  */
1053                 if (bytes < min_msg_size)
1054                         return (EINVAL);
1055                 if (bytes & SL_ALIGNMASK)
1056                         return (EINVAL);
1057                 if (head->sm_cmd && bytes < sizeof(struct syslink_msg))
1058                         return (EINVAL);
1059
1060                 /*
1061                  * Buffer must contain entire record
1062                  */
1063                 aligned_reclen = SLMSG_ALIGN(head->sm_bytes);
1064                 if (bytes < aligned_reclen)
1065                         return (EINVAL);
1066                 bytes -= aligned_reclen;
1067                 head = (void *)((char *)head + aligned_reclen);
1068         }
1069         return(0);
1070 }
1071