xref: /openbsd-src/usr.sbin/mopd/common/loop-bsd.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /*	$OpenBSD: loop-bsd.c,v 1.12 2006/10/11 20:56:59 deraadt Exp $ */
2 
3 /*
4  * Copyright (c) 1993-95 Mats O Jansson.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #ifndef lint
28 static const char rcsid[] =
29     "$OpenBSD: loop-bsd.c,v 1.12 2006/10/11 20:56:59 deraadt Exp $";
30 #endif
31 
32 #include <errno.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <unistd.h>
36 #if defined(__bsdi__) || defined(__FreeBSD__)
37 #include <sys/time.h>
38 #endif
39 #include <net/bpf.h>
40 #include <sys/ioctl.h>
41 
42 #include "os.h"
43 #include "common/common.h"
44 #include "common/mopdef.h"
45 
46 int
47 mopOpenRC(struct if_info *p, int trans)
48 {
49 #ifndef NORC
50 	return (*(p->iopen))(p->if_name, O_RDWR, MOP_K_PROTO_RC, trans);
51 #else
52 	return (-1);
53 #endif
54 }
55 
56 int
57 mopOpenDL(struct if_info *p, int trans)
58 {
59 #ifndef NODL
60 	return (*(p->iopen))(p->if_name, O_RDWR, MOP_K_PROTO_DL, trans);
61 #else
62 	return (-1);
63 #endif
64 }
65 
66 void
67 mopReadRC(void)
68 {
69 }
70 
71 void
72 mopReadDL(void)
73 {
74 }
75 
76 /*
77  * The list of all interfaces that are being listened to.  loop()
78  * "selects" on the descriptors in this list.
79  */
80 struct if_info *iflist;
81 
82 void   mopProcess(struct if_info *, u_char *);
83 
84 /*
85  * Loop indefinitely listening for MOP requests on the
86  * interfaces in 'iflist'.
87  */
88 void
89 Loop(void)
90 {
91 	u_char		*buf, *bp, *ep;
92 	int		 cc;
93 	fd_set		 fds, listeners;
94 	int		 bufsize, maxfd = 0;
95 	struct if_info	*ii;
96 
97 	if (iflist == 0) {
98 		syslog(LOG_ERR, "no interfaces");
99 		exit(0);
100 	}
101 	if (iflist->fd != -1)
102 		if (ioctl(iflist->fd, BIOCGBLEN, (caddr_t)&bufsize) < 0) {
103 			syslog(LOG_ERR, "BIOCGBLEN: %m");
104 			exit(0);
105 		}
106 
107 	buf = malloc(bufsize);
108 	if (buf == 0) {
109 		syslog(LOG_ERR, "malloc: %m");
110 		exit(0);
111 	}
112 	/*
113          * Find the highest numbered file descriptor for select().
114          * Initialize the set of descriptors to listen to.
115          */
116 	FD_ZERO(&fds);
117 	for (ii = iflist; ii; ii = ii->next)
118 		if (ii->fd != -1) {
119 			FD_SET(ii->fd, &fds);
120 			if (ii->fd > maxfd)
121 				maxfd = ii->fd;
122 		}
123 
124 	while (1) {
125 		listeners = fds;
126 		if (select(maxfd + 1, &listeners, NULL, NULL, NULL) < 0) {
127 			syslog(LOG_ERR, "select: %m");
128 			exit(0);
129 		}
130 		for (ii = iflist; ii; ii = ii->next)
131 			if (ii->fd != -1) {
132 				if (!FD_ISSET(ii->fd, &listeners))
133 					continue;
134 again:
135 			cc = read(ii->fd, buf, bufsize);
136 			/* Don't choke when we get ptraced */
137 			if (cc < 0 && errno == EINTR)
138 				goto again;
139 			/* Due to a SunOS bug, after 2^31 bytes, the file
140 			 * offset overflows and read fails with EINVAL.  The
141 			 * lseek() to 0 will fix things. */
142 			if (cc < 0) {
143 				if (errno == EINVAL && (lseek(ii->fd, 0,
144 				    SEEK_CUR) + bufsize) < 0) {
145 					lseek(ii->fd, 0, SEEK_SET);
146 					goto again;
147 				}
148 				syslog(LOG_ERR, "read: %m");
149 				exit(0);
150 			}
151 			/* Loop through the packet(s) */
152 #define bhp ((struct bpf_hdr *)bp)
153 			bp = buf;
154 			ep = bp + cc;
155 			while (bp < ep) {
156 				int caplen, hdrlen;
157 
158 				caplen = bhp->bh_caplen;
159 				hdrlen = bhp->bh_hdrlen;
160 				mopProcess(ii, bp + hdrlen);
161 				bp += BPF_WORDALIGN(hdrlen + caplen);
162 			}
163 		}
164 	}
165 }
166