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