2 * Copyright (c) 2006 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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
34 * $DragonFly: src/sys/kern/kern_syslink.c,v 1.9 2007/04/22 00:59:25 dillon Exp $
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.
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>
51 #include <sys/thread.h>
53 #include <sys/sysctl.h>
54 #include <sys/sysproto.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>
63 #include <sys/thread2.h>
66 * Red-Black trees organizing the syslink 'router' nodes and connections
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);
80 * Fifo used to buffer broadcast packets
84 int bufsize; /* must be a power of 2 */
85 int bufmask; /* (bufsize - 1) */
86 int rindex; /* tail-chasing FIFO indices */
91 * Syslink Router abstraction
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 */
102 struct slbuf bbuf; /* broadcast buffer */
103 char label[SYSLINK_LABEL_SIZE];
107 * Syslink Connection abstraction
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 */
124 char label[SYSLINK_LABEL_SIZE];
127 #define SYSLINK_BBUFSIZE (32*1024)
128 #define SYSLINK_SIOBUFSIZE (128*1024)
130 static int rb_slrouter_compare(struct slrouter *r1, struct slrouter *r2);
131 static int rb_sldata_compare(struct sldata *d1, struct sldata *d2);
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);
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,
148 static int syslink_poll(struct file *fp, int events, struct ucred *cred);
149 static int syslink_kqfilter(struct file *fp, struct knote *kn);
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);
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);
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
181 MALLOC_DEFINE(M_SYSLINK, "syslink", "syslink manager");
183 static int syslink_enabled;
184 SYSCTL_INT(_kern, OID_AUTO, syslink_enabled,
185 CTLFLAG_RW, &syslink_enabled, 0, "Enable SYSLINK");
188 * Support declarations and compare function for our RB trees
190 static struct slrouter_rb_tree slrouter_rb_root;
193 rb_slrouter_compare(struct slrouter *r1, struct slrouter *r2)
195 if (r1->sysid < r2->sysid)
197 if (r1->sysid > r2->sysid)
203 rb_sldata_compare(struct sldata *d1, struct sldata *d2)
205 if (d1->linkid < d2->linkid)
207 if (d1->linkid > d2->linkid)
213 * Compare and callback functions for first-sysid and first-linkid searches.
216 syslink_cmd_locate_cmp(struct slrouter *slrouter, void *data)
218 struct syslink_info *info = data;
220 if (slrouter->sysid < info->sysid)
222 if (slrouter->sysid > info->sysid)
228 syslink_cmd_locate_callback(struct slrouter *slrouter, void *data)
230 struct syslink_info *info = data;
232 info->flags = slrouter->flags; /* also clears SLIF_ERROR */
233 bcopy(slrouter->label, info->label, SYSLINK_LABEL_SIZE);
239 syslink_cmd_find_cmp(struct sldata *sldata, void *data)
241 struct syslink_info *info = data;
243 if (sldata->linkid < info->linkid)
245 if (sldata->linkid > info->linkid)
251 syslink_cmd_find_callback(struct sldata *sldata, void *data)
253 struct syslink_info *info = data;
255 info->linkid = sldata->linkid;
256 info->flags = sldata->flags; /* also clears SLIF_ERROR */
257 bcopy(sldata->label, info->label, SYSLINK_LABEL_SIZE);
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.
267 * syslink(int cmd, struct syslink_info *info, size_t bytes)
270 sys_syslink(struct syslink_args *uap)
272 struct syslink_info info;
273 struct slrouter *slrouter = NULL;
274 struct sldata *sldata = NULL;
279 * System call is under construction and disabled by default.
280 * Superuser access is also required.
282 if (syslink_enabled == 0)
284 error = suser(curthread);
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
293 bzero(&info, sizeof(info));
294 if ((unsigned)uap->bytes <= sizeof(info)) {
296 error = copyin(uap->info, &info, uap->bytes);
303 if (info.label[sizeof(info.label)-1] != 0)
310 case SYSLINK_CMD_CREATE:
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
317 if (info.bits < 2 || info.bits > SYSLINK_ROUTER_MAXBITS)
319 slrouter = kmalloc(sizeof(struct slrouter), M_SYSLINK,
321 if (slrouter_rb_tree_RB_LOOKUP(&slrouter_rb_root, info.sysid)) {
322 kfree(slrouter, M_SYSLINK);
326 slrouter->sysid = info.sysid;
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);
335 case SYSLINK_CMD_DESTROY:
337 * Destroy a syslink router node. The physical node is
338 * not freed until our temporary reference is removed.
340 slrouter = slrouter_rb_tree_RB_LOOKUP(&slrouter_rb_root,
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 */
353 case SYSLINK_CMD_LOCATE:
355 * Locate the first syslink router node >= info.sysid
357 info.flags |= SLIF_ERROR;
358 n = slrouter_rb_tree_RB_SCAN(
360 syslink_cmd_locate_cmp, syslink_cmd_locate_callback,
362 if (info.flags & SLIF_ERROR)
365 case SYSLINK_CMD_ADD:
366 slrouter = slrouter_rb_tree_RB_LOOKUP(&slrouter_rb_root, info.sysid);
368 (info.bits < 2 || info.bits > SYSLINK_ROUTER_MAXBITS)) {
370 } else if (slrouter && (slrouter->flags & SLIF_DESTROYED)) {
372 * Someone is trying to destroy this route node,
373 * no new adds please!
376 } else if (slrouter) {
378 error = syslink_add(slrouter, &info,
379 &uap->sysmsg_result);
384 case SYSLINK_CMD_REM:
385 slrouter = slrouter_rb_tree_RB_LOOKUP(&slrouter_rb_root,
389 sldata = sldata_rb_tree_RB_LOOKUP(&slrouter->sldata_rb_root, info.linkid);
392 error = syslink_rem(slrouter, sldata, &info);
400 case SYSLINK_CMD_FIND:
401 slrouter = slrouter_rb_tree_RB_LOOKUP(&slrouter_rb_root, info.sysid);
402 info.flags |= SLIF_ERROR;
405 n = sldata_rb_tree_RB_SCAN(
406 &slrouter->sldata_rb_root,
407 syslink_cmd_find_cmp, syslink_cmd_find_callback,
409 if (info.flags & SLIF_ERROR)
426 slrouter_rels(slrouter);
432 syslink_destroy_callback(struct sldata *sldata, void *data __unused)
435 if ((sldata->flags & SLIF_RQUIT) == 0) {
436 sldata->flags |= SLIF_RQUIT;
437 wakeup(&sldata->rthread);
439 if ((sldata->flags & SLIF_WQUIT) == 0) {
440 sldata->flags |= SLIF_WQUIT;
441 wakeup(&sldata->wthread);
448 * Shutdown all the connections going into this syslink.
450 * Try to wait for completion, but return after 1 second
455 syslink_destroy(struct slrouter *slrouter)
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);
463 tsleep(&retries, 0, "syslnk", hz / 10);
465 if (RB_EMPTY(&slrouter->sldata_rb_root))
473 syslink_add(struct slrouter *slrouter, struct syslink_info *info,
476 struct sldata *sldata;
484 maxphys = 1 << slrouter->bits;
485 numphys = info->bits ? (1 << info->bits) : 1;
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.
492 sldata = kmalloc(sizeof(struct sldata), M_SYSLINK, M_WAITOK|M_ZERO);
494 linkid = alist_alloc(slrouter->bitmap, numphys);
495 if (linkid == ALIST_BLOCK_NONE) {
496 kfree(sldata, M_SYSLINK);
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
505 sldata->linkid = linkid;
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);
513 * Complete initialization of the physical route node. Setting
514 * sldata->router activates the node.
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);
524 * We create a direct syslink descriptor. No helper threads
527 error = falloc(curproc, &fp, &info->fd);
529 fp->f_type = DTYPE_SYSLINK;
530 fp->f_flag = FREAD | FWRITE;
531 fp->f_ops = &syslinkops;
533 /* one ref: the fp descriptor */
535 sldata->flags |= SLIF_WQUIT | SLIF_WDONE;
536 sldata->flags |= SLIF_RQUIT | SLIF_RDONE;
537 fsetfd(curproc, fp, info->fd);
542 sldata->xfp = holdfp(curproc->p_fd, info->fd, -1);
543 if (sldata->xfp != NULL) {
544 /* two refs: reader thread and writer thread */
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,
551 lwkt_create(syslink_wthread_so, sldata,
552 &sldata->wthread, NULL,
555 lwkt_create(syslink_rthread_fp, sldata,
556 &sldata->rthread, NULL,
558 lwkt_create(syslink_wthread_fp, sldata,
559 &sldata->wthread, NULL,
566 sldata->router = slrouter;
573 syslink_rem(struct slrouter *slrouter, struct sldata *sldata,
574 struct syslink_info *info)
576 int error = EINPROGRESS;
578 if ((sldata->flags & SLIF_RQUIT) == 0) {
579 sldata->flags |= SLIF_RQUIT;
580 wakeup(&sldata->rthread);
583 if ((sldata->flags & SLIF_WQUIT) == 0) {
584 sldata->flags |= SLIF_WQUIT;
585 wakeup(&sldata->wthread);
592 * This thread reads from an external descriptor into rbuf, then parses and
593 * dispatches syslink messages from rbuf.
597 syslink_rthread_so(void *arg)
599 struct sldata *sldata = arg;
606 while ((sldata->flags & SLIF_RQUIT) == 0) {
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.
614 error = so_pru_soreceive(sldata->xso,
615 (sldata->bits ? &sa : NULL),
618 linkid = sldata->linkid;
619 if (sldata->bits && sa) {
620 linkid += syslink_getsubnet(sa) &
621 ((1 << sldata->bits) - 1);
627 if (sldata->flags & SLIF_PACKET) {
631 m = sldata->sio.sb_mb;
632 sbinit(&sldata->sio, SYSLINK_SIOBUFSIZE);
634 syslink_route(sldata->router, linkid, m);
636 while ((m = syslink_parse_stream(&sldata->sio)) != NULL) {
637 syslink_route(sldata->router, linkid, m);
643 * Mark us as done and deref sldata. Tell the writer to terminate as
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);
652 wakeup(&sldata->rthread);
653 wakeup(&sldata->wthread);
659 syslink_rthread_fp(void *arg)
661 struct sldata *sldata = arg;
663 sldata->flags |= SLIF_RDONE;
664 if ((sldata->flags & SLIF_WDONE) == 0) {
665 sldata->flags |= SLIF_WQUIT;
666 wakeup(&sldata->wthread);
668 wakeup(&sldata->rthread);
669 wakeup(&sldata->wthread);
675 syslink_parse_stream(struct sockbuf *sio)
682 syslink_route(struct slrouter *slrouter, int linkid, struct mbuf *m)
695 * Calculate contiguous space available to read and read as
698 * If the entire buffer is used there's probably a format
699 * error of some sort and we terminate the link.
701 used = slbuf->windex - slbuf->rindex;
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.
710 count = slbuf->bufsize -
711 (slbuf->windex & slbuf->bufmask);
712 if (count > slbuf->bufsize - used)
713 count = slbuf->bufsize - used;
716 error = fp_read(sldata->xfp,
718 (slbuf->windex & slbuf->bufmask),
719 count, &count, 0, UIO_SYSSPACE);
724 slbuf->windex += count;
727 tsleep(slbuf, 0, "fiford", 0);
731 * Process as many syslink messages as we can. The record
732 * length must be at least a minimal PAD record (8 bytes).
734 while (slbuf->windex - slbuf->rindex >= min_msg_size) {
737 head = (void *)(slbuf->buf +
738 (slbuf->rindex & slbuf->bufmask));
739 if (head->sm_bytes < min_msg_size) {
743 aligned_reclen = SLMSG_ALIGN(head->sm_bytes);
748 if ((slbuf->rindex & slbuf->bufmask) >
749 ((slbuf->rindex + aligned_reclen) & slbuf->bufmask)
756 * Insufficient data read
758 if (slbuf->windex - slbuf->rindex < aligned_reclen)
762 * Process non-pad messages. Non-pad messages have
763 * to be at least the size of the syslink_msg
766 * A PAD message's sm_cmd field contains 0.
769 if (head->sm_bytes < sizeof(*head)) {
773 error = process_syslink_msg(sldata, head);
778 slbuf->rindex += aligned_reclen;
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.
795 syslink_wthread_so(void *arg)
797 struct sldata *sldata = arg;
799 struct slbuf *slbuf = &sldata->wbuf;
800 struct syslink_msg *head;
803 while ((sldata->flags & SLIF_WQUIT) == 0) {
810 used = slbuf->windex - slbuf->rindex;
811 if (used < SL_MIN_MESSAGE_SIZE)
814 head = (void *)(slbuf->buf +
815 (slbuf->rindex & slbuf->bufmask));
816 if (head->sm_bytes < SL_MIN_MESSAGE_SIZE) {
820 aligned_reclen = SLMSG_ALIGN(head->sm_bytes);
825 if ((slbuf->rindex & slbuf->bufmask) >
826 ((slbuf->rindex + aligned_reclen) & slbuf->bufmask)
833 * Insufficient data read
835 if (used < aligned_reclen)
839 * Write it out whether it is PAD or not.
840 * XXX re-PAD for output here.
842 error = fp_write(sldata->xfp, head,
846 if (error && error != ENOBUFS)
848 if (count != aligned_reclen) {
852 slbuf->rindex += aligned_reclen;
856 tsleep(slbuf, 0, "fifowt", 0);
859 sldata->flags |= SLIF_WDONE;
865 syslink_wthread_fp(void *arg)
867 struct sldata *sldata = arg;
869 sldata->flags |= SLIF_WDONE;
875 slbuf_alloc(struct slbuf *slbuf, int bytes)
877 bzero(slbuf, sizeof(*slbuf));
878 slbuf->buf = kmalloc(bytes, M_SYSLINK, M_WAITOK);
879 slbuf->bufsize = bytes;
880 slbuf->bufmask = bytes - 1;
885 slbuf_free(struct slbuf *slbuf)
887 kfree(slbuf->buf, M_SYSLINK);
893 sldata_rels(struct sldata *sldata)
895 struct slrouter *slrouter;
897 if (--sldata->refs == 0) {
898 slrouter = sldata->router;
899 KKASSERT(slrouter != NULL);
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);
911 slrouter_rels(struct slrouter *slrouter)
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);
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.
932 syslink_getsubnet(struct sockaddr *sa)
938 switch(sa->sa_family) {
940 i4 = &((struct sockaddr_in *)sa)->sin_addr;
941 linkid = (int)ntohl(i4->s_addr);
944 i6 = &((struct sockaddr_in6 *)sa)->sin6_addr;
945 linkid = (int)ntohl(i6->s6_addr32[0]); /* XXX */
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
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).
968 syslink_read(struct file *fp, struct uio *uio, struct ucred *cred, int flags)
970 struct sldata *sldata = fp->f_data;
972 struct syslink_msg *head;
979 if (flags & O_FBLOCKING)
981 else if (flags & O_FNONBLOCKING)
983 else if (fp->f_flag & O_NONBLOCK)
988 lockmgr(&sldata->wlock, LK_EXCLUSIVE | LK_RETRY);
993 * Calculate the number of bytes we can transfer in one shot. Transfers
994 * do not wrap the FIFO.
996 contig = slbuf->bufsize - (slbuf->rindex & slbuf->bufmask);
998 bytes = slbuf->windex - slbuf->rindex;
1001 if (sldata->flags & SLIF_RDONE) {
1009 tsleep(slbuf, 0, "fiford", 0);
1015 * The uio must be able to accomodate the transfer.
1017 if (uio->uio_resid < bytes) {
1023 * Copy the data to userland and update rindex.
1025 head = (void *)(slbuf->buf + (slbuf->rindex & slbuf->bufmask));
1026 error = uiomove((caddr_t)head, bytes, uio);
1028 slbuf->rindex += bytes;
1035 lockmgr(&sldata->wlock, LK_RELEASE);
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.
1046 syslink_write (struct file *fp, struct uio *uio, struct ucred *cred, int flags)
1048 struct sldata *sldata = fp->f_data;
1050 struct slbuf *slbuf = &sldata->rbuf;
1051 struct syslink_msg *head;
1058 if (flags & O_FBLOCKING)
1060 else if (flags & O_FNONBLOCKING)
1062 else if (fp->f_flag & O_NONBLOCK)
1067 lockmgr(&sldata->rlock, LK_EXCLUSIVE | LK_RETRY);
1072 * Calculate the maximum number of contiguous bytes that may be
1073 * available. Caller is required to not wrap our FIFO.
1075 contig = slbuf->bufsize - (slbuf->windex & slbuf->bufmask);
1076 if (uio->uio_resid > contig) {
1082 * Truncate based on actual unused space available in the FIFO. If
1083 * the uio does not fit, block and loop.
1086 bytes = slbuf->bufsize - (slbuf->windex - slbuf->rindex);
1089 if (uio->uio_resid <= bytes)
1091 if (sldata->flags & SLIF_RDONE) {
1099 tsleep(slbuf, 0, "fifowr", 0);
1101 bytes = uio->uio_resid;
1102 head = (void *)(slbuf->buf + (slbuf->windex & slbuf->bufmask));
1103 error = uiomove((caddr_t)head, bytes, uio);
1105 error = syslink_validate(head, bytes);
1107 slbuf->windex += bytes;
1112 lockmgr(&sldata->rlock, LK_RELEASE);
1118 syslink_close (struct file *fp)
1120 struct sldata *sldata;
1122 sldata = fp->f_data;
1123 if ((sldata->flags & SLIF_RQUIT) == 0) {
1124 sldata->flags |= SLIF_RQUIT;
1125 wakeup(&sldata->rthread);
1127 if ((sldata->flags & SLIF_WQUIT) == 0) {
1128 sldata->flags |= SLIF_WQUIT;
1129 wakeup(&sldata->wthread);
1132 sldata_rels(sldata);
1138 syslink_stat (struct file *fp, struct stat *sb, struct ucred *cred)
1145 syslink_shutdown (struct file *fp, int how)
1152 syslink_ioctl (struct file *fp, u_long cmd, caddr_t data, struct ucred *cred)
1159 syslink_poll (struct file *fp, int events, struct ucred *cred)
1166 syslink_kqfilter(struct file *fp, struct knote *kn)
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.
1177 process_syslink_msg(struct sldata *sldata, struct syslink_msg *head)
1179 kprintf("process syslink msg %08x\n", head->sm_cmd);
1184 * Validate that the syslink message header(s) are correctly sized.
1188 syslink_validate(struct syslink_msg *head, int bytes)
1190 const int min_msg_size = SL_MIN_MESSAGE_SIZE;
1195 * Message size and alignment
1197 if (bytes < min_msg_size)
1199 if (bytes & SL_ALIGNMASK)
1201 if (head->sm_cmd && bytes < sizeof(struct syslink_msg))
1205 * Buffer must contain entire record
1207 aligned_reclen = SLMSG_ALIGN(head->sm_bytes);
1208 if (bytes < aligned_reclen)
1210 bytes -= aligned_reclen;
1211 head = (void *)((char *)head + aligned_reclen);