1 |
|
|
/* $OpenBSD: sys-bsd.c,v 1.27 2015/09/12 12:42:36 miod Exp $ */ |
2 |
|
|
|
3 |
|
|
/* |
4 |
|
|
* sys-bsd.c - System-dependent procedures for setting up |
5 |
|
|
* PPP interfaces on bsd-4.4-ish systems (including 386BSD, NetBSD, etc.) |
6 |
|
|
* |
7 |
|
|
* Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. |
8 |
|
|
* |
9 |
|
|
* Redistribution and use in source and binary forms, with or without |
10 |
|
|
* modification, are permitted provided that the following conditions |
11 |
|
|
* are met: |
12 |
|
|
* |
13 |
|
|
* 1. Redistributions of source code must retain the above copyright |
14 |
|
|
* notice, this list of conditions and the following disclaimer. |
15 |
|
|
* |
16 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
17 |
|
|
* notice, this list of conditions and the following disclaimer in |
18 |
|
|
* the documentation and/or other materials provided with the |
19 |
|
|
* distribution. |
20 |
|
|
* |
21 |
|
|
* 3. The name "Carnegie Mellon University" must not be used to |
22 |
|
|
* endorse or promote products derived from this software without |
23 |
|
|
* prior written permission. For permission or any legal |
24 |
|
|
* details, please contact |
25 |
|
|
* Office of Technology Transfer |
26 |
|
|
* Carnegie Mellon University |
27 |
|
|
* 5000 Forbes Avenue |
28 |
|
|
* Pittsburgh, PA 15213-3890 |
29 |
|
|
* (412) 268-4387, fax: (412) 268-7395 |
30 |
|
|
* tech-transfer@andrew.cmu.edu |
31 |
|
|
* |
32 |
|
|
* 4. Redistributions of any form whatsoever must retain the following |
33 |
|
|
* acknowledgment: |
34 |
|
|
* "This product includes software developed by Computing Services |
35 |
|
|
* at Carnegie Mellon University (http://www.cmu.edu/computing/)." |
36 |
|
|
* |
37 |
|
|
* CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO |
38 |
|
|
* THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY |
39 |
|
|
* AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE |
40 |
|
|
* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
41 |
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN |
42 |
|
|
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING |
43 |
|
|
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
44 |
|
|
* |
45 |
|
|
* Copyright (c) 1989-2002 Paul Mackerras. All rights reserved. |
46 |
|
|
* |
47 |
|
|
* Redistribution and use in source and binary forms, with or without |
48 |
|
|
* modification, are permitted provided that the following conditions |
49 |
|
|
* are met: |
50 |
|
|
* |
51 |
|
|
* 1. Redistributions of source code must retain the above copyright |
52 |
|
|
* notice, this list of conditions and the following disclaimer. |
53 |
|
|
* |
54 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
55 |
|
|
* notice, this list of conditions and the following disclaimer in |
56 |
|
|
* the documentation and/or other materials provided with the |
57 |
|
|
* distribution. |
58 |
|
|
* |
59 |
|
|
* 3. The name(s) of the authors of this software must not be used to |
60 |
|
|
* endorse or promote products derived from this software without |
61 |
|
|
* prior written permission. |
62 |
|
|
* |
63 |
|
|
* 4. Redistributions of any form whatsoever must retain the following |
64 |
|
|
* acknowledgment: |
65 |
|
|
* "This product includes software developed by Paul Mackerras |
66 |
|
|
* <paulus@samba.org>". |
67 |
|
|
* |
68 |
|
|
* THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO |
69 |
|
|
* THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY |
70 |
|
|
* AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY |
71 |
|
|
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
72 |
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN |
73 |
|
|
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING |
74 |
|
|
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
75 |
|
|
*/ |
76 |
|
|
|
77 |
|
|
/* |
78 |
|
|
* TODO: |
79 |
|
|
*/ |
80 |
|
|
|
81 |
|
|
#include <stdio.h> |
82 |
|
|
#include <syslog.h> |
83 |
|
|
#include <string.h> |
84 |
|
|
#include <stdlib.h> |
85 |
|
|
#include <unistd.h> |
86 |
|
|
#include <err.h> |
87 |
|
|
#include <errno.h> |
88 |
|
|
#include <fcntl.h> |
89 |
|
|
#include <termios.h> |
90 |
|
|
#include <signal.h> |
91 |
|
|
#include <util.h> |
92 |
|
|
#include <sys/ioctl.h> |
93 |
|
|
#include <sys/types.h> |
94 |
|
|
#include <sys/socket.h> |
95 |
|
|
#include <sys/time.h> |
96 |
|
|
#include <sys/stat.h> |
97 |
|
|
#include <ifaddrs.h> |
98 |
|
|
|
99 |
|
|
#ifdef PPP_FILTER |
100 |
|
|
#include <net/bpf.h> |
101 |
|
|
#endif |
102 |
|
|
#include <net/if.h> |
103 |
|
|
#include <net/ppp_defs.h> |
104 |
|
|
#include <net/if_ppp.h> |
105 |
|
|
#include <net/route.h> |
106 |
|
|
#include <net/if_dl.h> |
107 |
|
|
#include <netinet/in.h> |
108 |
|
|
|
109 |
|
|
#if RTM_VERSION >= 3 |
110 |
|
|
#include <sys/param.h> |
111 |
|
|
#if defined(NetBSD) && (NetBSD >= 199703) |
112 |
|
|
#include <netinet/if_inarp.h> |
113 |
|
|
#else /* NetBSD 1.2D or later */ |
114 |
|
|
#if defined(__FreeBSD__) || defined(__OpenBSD__) |
115 |
|
|
#include <netinet/if_ether.h> |
116 |
|
|
#else |
117 |
|
|
#include <net/if_ether.h> |
118 |
|
|
#endif |
119 |
|
|
#endif |
120 |
|
|
#endif |
121 |
|
|
|
122 |
|
|
#include "pppd.h" |
123 |
|
|
#include "fsm.h" |
124 |
|
|
#include "ipcp.h" |
125 |
|
|
|
126 |
|
|
#define ok_error(num) ((num)==EIO) |
127 |
|
|
|
128 |
|
|
static int initdisc = -1; /* Initial TTY discipline for ppp_fd */ |
129 |
|
|
static int initfdflags = -1; /* Initial file descriptor flags for ppp_fd */ |
130 |
|
|
static int ppp_fd = -1; /* fd which is set to PPP discipline */ |
131 |
|
|
static int rtm_seq; |
132 |
|
|
|
133 |
|
|
static int restore_term; /* 1 => we've munged the terminal */ |
134 |
|
|
static struct termios inittermios; /* Initial TTY termios */ |
135 |
|
|
static struct winsize wsinfo; /* Initial window size info */ |
136 |
|
|
|
137 |
|
|
static char *lock_file; /* name of lock file created */ |
138 |
|
|
|
139 |
|
|
static int loop_slave = -1; |
140 |
|
|
static int loop_master; |
141 |
|
|
static char loop_name[20]; |
142 |
|
|
|
143 |
|
|
static unsigned char inbuf[512]; /* buffer for chars read from loopback */ |
144 |
|
|
|
145 |
|
|
static int sockfd; /* socket for doing interface ioctls */ |
146 |
|
|
|
147 |
|
|
static int if_is_up; /* the interface is currently up */ |
148 |
|
|
static u_int32_t ifaddrs[2]; /* local and remote addresses we set */ |
149 |
|
|
static u_int32_t default_route_gateway; /* gateway addr for default route */ |
150 |
|
|
static u_int32_t proxy_arp_addr; /* remote addr for proxy arp */ |
151 |
|
|
|
152 |
|
|
/* Prototypes for procedures local to this file. */ |
153 |
|
|
static int dodefaultroute(u_int32_t, int); |
154 |
|
|
static int get_ether_addr(u_int32_t, struct sockaddr_dl *); |
155 |
|
|
|
156 |
|
|
|
157 |
|
|
/* |
158 |
|
|
* sys_init - System-dependent initialization. |
159 |
|
|
*/ |
160 |
|
|
void |
161 |
|
|
sys_init() |
162 |
|
|
{ |
163 |
|
|
/* Get an internet socket for doing socket ioctl's on. */ |
164 |
|
|
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { |
165 |
|
|
syslog(LOG_ERR, "Couldn't create IP socket: %m"); |
166 |
|
|
die(1); |
167 |
|
|
} |
168 |
|
|
} |
169 |
|
|
|
170 |
|
|
/* |
171 |
|
|
* sys_cleanup - restore any system state we modified before exiting: |
172 |
|
|
* mark the interface down, delete default route and/or proxy arp entry. |
173 |
|
|
* This should call die() because it's called from die(). |
174 |
|
|
*/ |
175 |
|
|
void |
176 |
|
|
sys_cleanup() |
177 |
|
|
{ |
178 |
|
|
struct ifreq ifr; |
179 |
|
|
|
180 |
|
|
if (if_is_up) { |
181 |
|
|
strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); |
182 |
|
|
if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) >= 0 |
183 |
|
|
&& ((ifr.ifr_flags & IFF_UP) != 0)) { |
184 |
|
|
ifr.ifr_flags &= ~IFF_UP; |
185 |
|
|
ioctl(sockfd, SIOCSIFFLAGS, &ifr); |
186 |
|
|
} |
187 |
|
|
} |
188 |
|
|
if (ifaddrs[0] != 0) |
189 |
|
|
cifaddr(0, ifaddrs[0], ifaddrs[1]); |
190 |
|
|
if (default_route_gateway) |
191 |
|
|
cifdefaultroute(0, 0, default_route_gateway); |
192 |
|
|
if (proxy_arp_addr) |
193 |
|
|
cifproxyarp(0, proxy_arp_addr); |
194 |
|
|
} |
195 |
|
|
|
196 |
|
|
/* |
197 |
|
|
* sys_close - Clean up in a child process before execing. |
198 |
|
|
*/ |
199 |
|
|
void |
200 |
|
|
sys_close() |
201 |
|
|
{ |
202 |
|
|
close(sockfd); |
203 |
|
|
if (loop_slave >= 0) { |
204 |
|
|
close(loop_slave); |
205 |
|
|
close(loop_master); |
206 |
|
|
} |
207 |
|
|
} |
208 |
|
|
|
209 |
|
|
/* |
210 |
|
|
* sys_check_options - check the options that the user specified |
211 |
|
|
*/ |
212 |
|
|
void |
213 |
|
|
sys_check_options() |
214 |
|
|
{ |
215 |
|
|
} |
216 |
|
|
|
217 |
|
|
/* |
218 |
|
|
* ppp_available - check whether the system has any ppp interfaces |
219 |
|
|
* (in fact we check whether we can do an ioctl on ppp0). |
220 |
|
|
*/ |
221 |
|
|
int |
222 |
|
|
ppp_available() |
223 |
|
|
{ |
224 |
|
|
int s, ok; |
225 |
|
|
struct ifreq ifr; |
226 |
|
|
extern char *no_ppp_msg; |
227 |
|
|
|
228 |
|
|
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) |
229 |
|
|
return 1; /* can't tell */ |
230 |
|
|
|
231 |
|
|
strlcpy(ifr.ifr_name, "ppp0", sizeof(ifr.ifr_name)); |
232 |
|
|
ok = ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) >= 0; |
233 |
|
|
close(s); |
234 |
|
|
|
235 |
|
|
no_ppp_msg = "\ |
236 |
|
|
PPP device not available. Make sure the device is created with\n\ |
237 |
|
|
ifconfig and that the kernel supports PPP. See ifconfig(8) and ppp(4)."; |
238 |
|
|
return ok; |
239 |
|
|
} |
240 |
|
|
|
241 |
|
|
/* |
242 |
|
|
* establish_ppp - Turn the serial port into a ppp interface. |
243 |
|
|
*/ |
244 |
|
|
void |
245 |
|
|
establish_ppp(fd) |
246 |
|
|
int fd; |
247 |
|
|
{ |
248 |
|
|
int pppdisc = PPPDISC; |
249 |
|
|
int x; |
250 |
|
|
|
251 |
|
|
if (demand) { |
252 |
|
|
/* |
253 |
|
|
* Demand mode - prime the old ppp device to relinquish the unit. |
254 |
|
|
*/ |
255 |
|
|
if (ioctl(ppp_fd, PPPIOCXFERUNIT, 0) < 0) { |
256 |
|
|
syslog(LOG_ERR, "ioctl(transfer ppp unit): %m"); |
257 |
|
|
die(1); |
258 |
|
|
} |
259 |
|
|
} |
260 |
|
|
|
261 |
|
|
/* |
262 |
|
|
* Save the old line discipline of fd, and set it to PPP. |
263 |
|
|
*/ |
264 |
|
|
if (ioctl(fd, TIOCGETD, &initdisc) < 0) { |
265 |
|
|
syslog(LOG_ERR, "ioctl(TIOCGETD): %m"); |
266 |
|
|
die(1); |
267 |
|
|
} |
268 |
|
|
if (ioctl(fd, TIOCSETD, &pppdisc) < 0) { |
269 |
|
|
syslog(LOG_ERR, "ioctl(TIOCSETD): %m"); |
270 |
|
|
die(1); |
271 |
|
|
} |
272 |
|
|
|
273 |
|
|
if (!demand) { |
274 |
|
|
/* |
275 |
|
|
* Find out which interface we were given. |
276 |
|
|
*/ |
277 |
|
|
if (ioctl(fd, PPPIOCGUNIT, &ifunit) < 0) { |
278 |
|
|
syslog(LOG_ERR, "ioctl(PPPIOCGUNIT): %m"); |
279 |
|
|
die(1); |
280 |
|
|
} |
281 |
|
|
} else { |
282 |
|
|
/* |
283 |
|
|
* Check that we got the same unit again. |
284 |
|
|
*/ |
285 |
|
|
if (ioctl(fd, PPPIOCGUNIT, &x) < 0) { |
286 |
|
|
syslog(LOG_ERR, "ioctl(PPPIOCGUNIT): %m"); |
287 |
|
|
die(1); |
288 |
|
|
} |
289 |
|
|
if (x != ifunit) { |
290 |
|
|
syslog(LOG_ERR, "transfer_ppp failed: wanted unit %d, got %d", |
291 |
|
|
ifunit, x); |
292 |
|
|
die(1); |
293 |
|
|
} |
294 |
|
|
x = TTYDISC; |
295 |
|
|
ioctl(loop_slave, TIOCSETD, &x); |
296 |
|
|
} |
297 |
|
|
|
298 |
|
|
ppp_fd = fd; |
299 |
|
|
|
300 |
|
|
/* |
301 |
|
|
* Enable debug in the driver if requested. |
302 |
|
|
*/ |
303 |
|
|
if (kdebugflag) { |
304 |
|
|
if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) { |
305 |
|
|
syslog(LOG_WARNING, "ioctl (PPPIOCGFLAGS): %m"); |
306 |
|
|
} else { |
307 |
|
|
x |= (kdebugflag & 0xFF) * SC_DEBUG; |
308 |
|
|
if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) |
309 |
|
|
syslog(LOG_WARNING, "ioctl(PPPIOCSFLAGS): %m"); |
310 |
|
|
} |
311 |
|
|
} |
312 |
|
|
|
313 |
|
|
/* |
314 |
|
|
* Set device for non-blocking reads. |
315 |
|
|
*/ |
316 |
|
|
if ((initfdflags = fcntl(fd, F_GETFL)) == -1 |
317 |
|
|
|| fcntl(fd, F_SETFL, initfdflags | O_NONBLOCK) == -1) { |
318 |
|
|
syslog(LOG_WARNING, "Couldn't set device to non-blocking mode: %m"); |
319 |
|
|
} |
320 |
|
|
} |
321 |
|
|
|
322 |
|
|
/* |
323 |
|
|
* restore_loop - reattach the ppp unit to the loopback. |
324 |
|
|
*/ |
325 |
|
|
void |
326 |
|
|
restore_loop() |
327 |
|
|
{ |
328 |
|
|
int x; |
329 |
|
|
|
330 |
|
|
/* |
331 |
|
|
* Transfer the ppp interface back to the loopback. |
332 |
|
|
*/ |
333 |
|
|
if (ioctl(ppp_fd, PPPIOCXFERUNIT, 0) < 0) { |
334 |
|
|
syslog(LOG_ERR, "ioctl(transfer ppp unit): %m"); |
335 |
|
|
die(1); |
336 |
|
|
} |
337 |
|
|
x = PPPDISC; |
338 |
|
|
if (ioctl(loop_slave, TIOCSETD, &x) < 0) { |
339 |
|
|
syslog(LOG_ERR, "ioctl(TIOCSETD): %m"); |
340 |
|
|
die(1); |
341 |
|
|
} |
342 |
|
|
|
343 |
|
|
/* |
344 |
|
|
* Check that we got the same unit again. |
345 |
|
|
*/ |
346 |
|
|
if (ioctl(loop_slave, PPPIOCGUNIT, &x) < 0) { |
347 |
|
|
syslog(LOG_ERR, "ioctl(PPPIOCGUNIT): %m"); |
348 |
|
|
die(1); |
349 |
|
|
} |
350 |
|
|
if (x != ifunit) { |
351 |
|
|
syslog(LOG_ERR, "transfer_ppp failed: wanted unit %d, got %d", |
352 |
|
|
ifunit, x); |
353 |
|
|
die(1); |
354 |
|
|
} |
355 |
|
|
ppp_fd = loop_slave; |
356 |
|
|
} |
357 |
|
|
|
358 |
|
|
/* |
359 |
|
|
* disestablish_ppp - Restore the serial port to normal operation. |
360 |
|
|
* This shouldn't call die() because it's called from die(). |
361 |
|
|
*/ |
362 |
|
|
void |
363 |
|
|
disestablish_ppp(fd) |
364 |
|
|
int fd; |
365 |
|
|
{ |
366 |
|
|
/* Reset non-blocking mode on fd. */ |
367 |
|
|
if (initfdflags != -1 && fcntl(fd, F_SETFL, initfdflags) < 0) |
368 |
|
|
syslog(LOG_WARNING, "Couldn't restore device fd flags: %m"); |
369 |
|
|
initfdflags = -1; |
370 |
|
|
|
371 |
|
|
/* Restore old line discipline. */ |
372 |
|
|
if (initdisc >= 0 && ioctl(fd, TIOCSETD, &initdisc) < 0) |
373 |
|
|
syslog(LOG_ERR, "ioctl(TIOCSETD): %m"); |
374 |
|
|
initdisc = -1; |
375 |
|
|
|
376 |
|
|
if (fd == ppp_fd) |
377 |
|
|
ppp_fd = -1; |
378 |
|
|
} |
379 |
|
|
|
380 |
|
|
/* |
381 |
|
|
* Check whether the link seems not to be 8-bit clean. |
382 |
|
|
*/ |
383 |
|
|
void |
384 |
|
|
clean_check() |
385 |
|
|
{ |
386 |
|
|
int x; |
387 |
|
|
char *s; |
388 |
|
|
|
389 |
|
|
if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) == 0) { |
390 |
|
|
s = NULL; |
391 |
|
|
switch (~x & (SC_RCV_B7_0|SC_RCV_B7_1|SC_RCV_EVNP|SC_RCV_ODDP)) { |
392 |
|
|
case SC_RCV_B7_0: |
393 |
|
|
s = "bit 7 set to 1"; |
394 |
|
|
break; |
395 |
|
|
case SC_RCV_B7_1: |
396 |
|
|
s = "bit 7 set to 0"; |
397 |
|
|
break; |
398 |
|
|
case SC_RCV_EVNP: |
399 |
|
|
s = "odd parity"; |
400 |
|
|
break; |
401 |
|
|
case SC_RCV_ODDP: |
402 |
|
|
s = "even parity"; |
403 |
|
|
break; |
404 |
|
|
} |
405 |
|
|
if (s != NULL) { |
406 |
|
|
syslog(LOG_WARNING, "Serial link is not 8-bit clean:"); |
407 |
|
|
syslog(LOG_WARNING, "All received characters had %s", s); |
408 |
|
|
} |
409 |
|
|
} |
410 |
|
|
} |
411 |
|
|
|
412 |
|
|
/* |
413 |
|
|
* set_up_tty: Set up the serial port on `fd' for 8 bits, no parity, |
414 |
|
|
* at the requested speed, etc. If `local' is true, set CLOCAL |
415 |
|
|
* regardless of whether the modem option was specified. |
416 |
|
|
* |
417 |
|
|
* For *BSD, we assume that speed_t values numerically equal bits/second. |
418 |
|
|
*/ |
419 |
|
|
void |
420 |
|
|
set_up_tty(fd, local) |
421 |
|
|
int fd, local; |
422 |
|
|
{ |
423 |
|
|
struct termios tios; |
424 |
|
|
|
425 |
|
|
if (tcgetattr(fd, &tios) < 0) { |
426 |
|
|
syslog(LOG_ERR, "tcgetattr: %m"); |
427 |
|
|
die(1); |
428 |
|
|
} |
429 |
|
|
|
430 |
|
|
if (!restore_term) { |
431 |
|
|
inittermios = tios; |
432 |
|
|
ioctl(fd, TIOCGWINSZ, &wsinfo); |
433 |
|
|
} |
434 |
|
|
|
435 |
|
|
tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CLOCAL); |
436 |
|
|
if (crtscts > 0 && modem) |
437 |
|
|
tios.c_cflag |= CRTSCTS; |
438 |
|
|
else if (crtscts < 0) |
439 |
|
|
tios.c_cflag &= ~CRTSCTS; |
440 |
|
|
|
441 |
|
|
tios.c_cflag |= CS8 | CREAD | HUPCL; |
442 |
|
|
if (local || !modem) |
443 |
|
|
tios.c_cflag |= CLOCAL; |
444 |
|
|
tios.c_iflag = IGNBRK | IGNPAR; |
445 |
|
|
tios.c_oflag = 0; |
446 |
|
|
tios.c_lflag = 0; |
447 |
|
|
tios.c_cc[VMIN] = 1; |
448 |
|
|
tios.c_cc[VTIME] = 0; |
449 |
|
|
|
450 |
|
|
if (crtscts == -2) { |
451 |
|
|
tios.c_iflag |= IXON | IXOFF; |
452 |
|
|
tios.c_cc[VSTOP] = 0x13; /* DC3 = XOFF = ^S */ |
453 |
|
|
tios.c_cc[VSTART] = 0x11; /* DC1 = XON = ^Q */ |
454 |
|
|
} |
455 |
|
|
|
456 |
|
|
if (inspeed) { |
457 |
|
|
cfsetospeed(&tios, inspeed); |
458 |
|
|
cfsetispeed(&tios, inspeed); |
459 |
|
|
} else { |
460 |
|
|
inspeed = cfgetospeed(&tios); |
461 |
|
|
/* |
462 |
|
|
* We can't proceed if the serial port speed is 0, |
463 |
|
|
* since that implies that the serial port is disabled. |
464 |
|
|
*/ |
465 |
|
|
if (inspeed == 0) { |
466 |
|
|
syslog(LOG_ERR, "Baud rate for %s is 0; need explicit baud rate", |
467 |
|
|
devnam); |
468 |
|
|
die(1); |
469 |
|
|
} |
470 |
|
|
} |
471 |
|
|
baud_rate = inspeed; |
472 |
|
|
|
473 |
|
|
if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) { |
474 |
|
|
syslog(LOG_ERR, "tcsetattr: %m"); |
475 |
|
|
die(1); |
476 |
|
|
} |
477 |
|
|
|
478 |
|
|
restore_term = 1; |
479 |
|
|
} |
480 |
|
|
|
481 |
|
|
/* |
482 |
|
|
* restore_tty - restore the terminal to the saved settings. |
483 |
|
|
*/ |
484 |
|
|
void |
485 |
|
|
restore_tty(fd) |
486 |
|
|
int fd; |
487 |
|
|
{ |
488 |
|
|
if (restore_term) { |
489 |
|
|
if (!default_device) { |
490 |
|
|
/* |
491 |
|
|
* Turn off echoing, because otherwise we can get into |
492 |
|
|
* a loop with the tty and the modem echoing to each other. |
493 |
|
|
* We presume we are the sole user of this tty device, so |
494 |
|
|
* when we close it, it will revert to its defaults anyway. |
495 |
|
|
*/ |
496 |
|
|
inittermios.c_lflag &= ~(ECHO | ECHONL); |
497 |
|
|
} |
498 |
|
|
if (tcsetattr(fd, TCSAFLUSH, &inittermios) < 0) |
499 |
|
|
if (errno != ENXIO) |
500 |
|
|
syslog(LOG_WARNING, "tcsetattr: %m"); |
501 |
|
|
ioctl(fd, TIOCSWINSZ, &wsinfo); |
502 |
|
|
restore_term = 0; |
503 |
|
|
} |
504 |
|
|
} |
505 |
|
|
|
506 |
|
|
/* |
507 |
|
|
* setdtr - control the DTR line on the serial port. |
508 |
|
|
* This is called from die(), so it shouldn't call die(). |
509 |
|
|
*/ |
510 |
|
|
void |
511 |
|
|
setdtr(fd, on) |
512 |
|
|
int fd, on; |
513 |
|
|
{ |
514 |
|
|
int modembits = TIOCM_DTR; |
515 |
|
|
|
516 |
|
|
ioctl(fd, (on? TIOCMBIS: TIOCMBIC), &modembits); |
517 |
|
|
} |
518 |
|
|
|
519 |
|
|
|
520 |
|
|
/* |
521 |
|
|
* open_ppp_loopback - open the device we use for getting |
522 |
|
|
* packets in demand mode, and connect it to a ppp interface. |
523 |
|
|
* Here we use a pty. |
524 |
|
|
*/ |
525 |
|
|
void |
526 |
|
|
open_ppp_loopback() |
527 |
|
|
{ |
528 |
|
|
int flags; |
529 |
|
|
struct termios tios; |
530 |
|
|
int pppdisc = PPPDISC; |
531 |
|
|
|
532 |
|
|
if (openpty(&loop_master, &loop_slave, loop_name, NULL, NULL) < 0) { |
533 |
|
|
syslog(LOG_ERR, "No free pty for loopback"); |
534 |
|
|
die(1); |
535 |
|
|
} |
536 |
|
|
SYSDEBUG((LOG_DEBUG, "using %s for loopback", loop_name)); |
537 |
|
|
|
538 |
|
|
if (tcgetattr(loop_slave, &tios) == 0) { |
539 |
|
|
tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB); |
540 |
|
|
tios.c_cflag |= CS8 | CREAD; |
541 |
|
|
tios.c_iflag = IGNPAR; |
542 |
|
|
tios.c_oflag = 0; |
543 |
|
|
tios.c_lflag = 0; |
544 |
|
|
if (tcsetattr(loop_slave, TCSAFLUSH, &tios) < 0) |
545 |
|
|
syslog(LOG_WARNING, "couldn't set attributes on loopback: %m"); |
546 |
|
|
} |
547 |
|
|
|
548 |
|
|
if ((flags = fcntl(loop_master, F_GETFL)) != -1) |
549 |
|
|
if (fcntl(loop_master, F_SETFL, flags | O_NONBLOCK) == -1) |
550 |
|
|
syslog(LOG_WARNING, "couldn't set loopback to nonblock: %m"); |
551 |
|
|
|
552 |
|
|
ppp_fd = loop_slave; |
553 |
|
|
if (ioctl(ppp_fd, TIOCSETD, &pppdisc) < 0) { |
554 |
|
|
syslog(LOG_ERR, "ioctl(TIOCSETD): %m"); |
555 |
|
|
die(1); |
556 |
|
|
} |
557 |
|
|
|
558 |
|
|
/* |
559 |
|
|
* Find out which interface we were given. |
560 |
|
|
*/ |
561 |
|
|
if (ioctl(ppp_fd, PPPIOCGUNIT, &ifunit) < 0) { |
562 |
|
|
syslog(LOG_ERR, "ioctl(PPPIOCGUNIT): %m"); |
563 |
|
|
die(1); |
564 |
|
|
} |
565 |
|
|
|
566 |
|
|
/* |
567 |
|
|
* Enable debug in the driver if requested. |
568 |
|
|
*/ |
569 |
|
|
if (kdebugflag) { |
570 |
|
|
if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &flags) < 0) { |
571 |
|
|
syslog(LOG_WARNING, "ioctl (PPPIOCGFLAGS): %m"); |
572 |
|
|
} else { |
573 |
|
|
flags |= (kdebugflag & 0xFF) * SC_DEBUG; |
574 |
|
|
if (ioctl(ppp_fd, PPPIOCSFLAGS, (caddr_t) &flags) < 0) |
575 |
|
|
syslog(LOG_WARNING, "ioctl(PPPIOCSFLAGS): %m"); |
576 |
|
|
} |
577 |
|
|
} |
578 |
|
|
|
579 |
|
|
} |
580 |
|
|
|
581 |
|
|
|
582 |
|
|
/* |
583 |
|
|
* output - Output PPP packet. |
584 |
|
|
*/ |
585 |
|
|
void |
586 |
|
|
output(unit, p, len) |
587 |
|
|
int unit; |
588 |
|
|
u_char *p; |
589 |
|
|
int len; |
590 |
|
|
{ |
591 |
|
|
if (debug) |
592 |
|
|
log_packet(p, len, "sent ", LOG_DEBUG); |
593 |
|
|
|
594 |
|
|
if (write(ttyfd, p, len) < 0) { |
595 |
|
|
if (errno != EIO) |
596 |
|
|
syslog(LOG_ERR, "write: %m"); |
597 |
|
|
} |
598 |
|
|
} |
599 |
|
|
|
600 |
|
|
|
601 |
|
|
/* |
602 |
|
|
* wait_input - wait until there is data available on ttyfd, |
603 |
|
|
* for the length of time specified by *timo (indefinite |
604 |
|
|
* if timo is NULL). |
605 |
|
|
*/ |
606 |
|
|
void |
607 |
|
|
wait_input(timo) |
608 |
|
|
struct timeval *timo; |
609 |
|
|
{ |
610 |
|
|
fd_set *fdsp = NULL; |
611 |
|
|
int fdsn; |
612 |
|
|
int n; |
613 |
|
|
|
614 |
|
|
fdsn = howmany(ttyfd+1, NFDBITS) * sizeof(fd_mask); |
615 |
|
|
if ((fdsp = (fd_set *)malloc(fdsn)) == NULL) |
616 |
|
|
err(1, "malloc"); |
617 |
|
|
memset(fdsp, 0, fdsn); |
618 |
|
|
FD_SET(ttyfd, fdsp); |
619 |
|
|
|
620 |
|
|
n = select(ttyfd+1, fdsp, NULL, fdsp, timo); |
621 |
|
|
if (n < 0 && errno != EINTR) { |
622 |
|
|
syslog(LOG_ERR, "select: %m"); |
623 |
|
|
free(fdsp); |
624 |
|
|
die(1); |
625 |
|
|
} |
626 |
|
|
free(fdsp); |
627 |
|
|
} |
628 |
|
|
|
629 |
|
|
|
630 |
|
|
/* |
631 |
|
|
* wait_loop_output - wait until there is data available on the |
632 |
|
|
* loopback, for the length of time specified by *timo (indefinite |
633 |
|
|
* if timo is NULL). |
634 |
|
|
*/ |
635 |
|
|
void |
636 |
|
|
wait_loop_output(timo) |
637 |
|
|
struct timeval *timo; |
638 |
|
|
{ |
639 |
|
|
fd_set *fdsp = NULL; |
640 |
|
|
int fdsn; |
641 |
|
|
int n; |
642 |
|
|
|
643 |
|
|
fdsn = howmany(loop_master+1, NFDBITS) * sizeof(fd_mask); |
644 |
|
|
if ((fdsp = (fd_set *)malloc(fdsn)) == NULL) |
645 |
|
|
err(1, "malloc"); |
646 |
|
|
memset(fdsp, 0, fdsn); |
647 |
|
|
FD_SET(loop_master, fdsp); |
648 |
|
|
|
649 |
|
|
n = select(loop_master + 1, fdsp, NULL, fdsp, timo); |
650 |
|
|
if (n < 0 && errno != EINTR) { |
651 |
|
|
syslog(LOG_ERR, "select: %m"); |
652 |
|
|
free(fdsp); |
653 |
|
|
die(1); |
654 |
|
|
} |
655 |
|
|
free(fdsp); |
656 |
|
|
} |
657 |
|
|
|
658 |
|
|
|
659 |
|
|
/* |
660 |
|
|
* wait_time - wait for a given length of time or until a |
661 |
|
|
* signal is received. |
662 |
|
|
*/ |
663 |
|
|
void |
664 |
|
|
wait_time(timo) |
665 |
|
|
struct timeval *timo; |
666 |
|
|
{ |
667 |
|
|
int n; |
668 |
|
|
|
669 |
|
|
n = select(0, NULL, NULL, NULL, timo); |
670 |
|
|
if (n < 0 && errno != EINTR) { |
671 |
|
|
syslog(LOG_ERR, "select: %m"); |
672 |
|
|
die(1); |
673 |
|
|
} |
674 |
|
|
} |
675 |
|
|
|
676 |
|
|
|
677 |
|
|
/* |
678 |
|
|
* read_packet - get a PPP packet from the serial device. |
679 |
|
|
*/ |
680 |
|
|
int |
681 |
|
|
read_packet(buf) |
682 |
|
|
u_char *buf; |
683 |
|
|
{ |
684 |
|
|
int len; |
685 |
|
|
|
686 |
|
|
if ((len = read(ttyfd, buf, PPP_MTU + PPP_HDRLEN)) < 0) { |
687 |
|
|
if (errno == EWOULDBLOCK || errno == EINTR) |
688 |
|
|
return -1; |
689 |
|
|
syslog(LOG_ERR, "read: %m"); |
690 |
|
|
die(1); |
691 |
|
|
} |
692 |
|
|
return len; |
693 |
|
|
} |
694 |
|
|
|
695 |
|
|
|
696 |
|
|
/* |
697 |
|
|
* get_loop_output - read characters from the loopback, form them |
698 |
|
|
* into frames, and detect when we want to bring the real link up. |
699 |
|
|
* Return value is 1 if we need to bring up the link, 0 otherwise. |
700 |
|
|
*/ |
701 |
|
|
int |
702 |
|
|
get_loop_output() |
703 |
|
|
{ |
704 |
|
|
int rv = 0; |
705 |
|
|
int n; |
706 |
|
|
|
707 |
|
|
while ((n = read(loop_master, inbuf, sizeof(inbuf))) >= 0) { |
708 |
|
|
if (loop_chars(inbuf, n)) |
709 |
|
|
rv = 1; |
710 |
|
|
} |
711 |
|
|
|
712 |
|
|
if (n == 0) { |
713 |
|
|
syslog(LOG_ERR, "eof on loopback"); |
714 |
|
|
die(1); |
715 |
|
|
} else if (errno != EWOULDBLOCK){ |
716 |
|
|
syslog(LOG_ERR, "read from loopback: %m"); |
717 |
|
|
die(1); |
718 |
|
|
} |
719 |
|
|
|
720 |
|
|
return rv; |
721 |
|
|
} |
722 |
|
|
|
723 |
|
|
|
724 |
|
|
/* |
725 |
|
|
* ppp_send_config - configure the transmit characteristics of |
726 |
|
|
* the ppp interface. |
727 |
|
|
*/ |
728 |
|
|
void |
729 |
|
|
ppp_send_config(unit, mtu, asyncmap, pcomp, accomp) |
730 |
|
|
int unit, mtu; |
731 |
|
|
u_int32_t asyncmap; |
732 |
|
|
int pcomp, accomp; |
733 |
|
|
{ |
734 |
|
|
u_int x; |
735 |
|
|
struct ifreq ifr; |
736 |
|
|
|
737 |
|
|
strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); |
738 |
|
|
ifr.ifr_mtu = mtu; |
739 |
|
|
if (ioctl(sockfd, SIOCSIFMTU, (caddr_t) &ifr) < 0) { |
740 |
|
|
syslog(LOG_ERR, "ioctl(SIOCSIFMTU): %m"); |
741 |
|
|
quit(); |
742 |
|
|
} |
743 |
|
|
|
744 |
|
|
if (ioctl(ppp_fd, PPPIOCSASYNCMAP, (caddr_t) &asyncmap) < 0) { |
745 |
|
|
syslog(LOG_ERR, "ioctl(PPPIOCSASYNCMAP): %m"); |
746 |
|
|
quit(); |
747 |
|
|
} |
748 |
|
|
|
749 |
|
|
if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) { |
750 |
|
|
syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m"); |
751 |
|
|
quit(); |
752 |
|
|
} |
753 |
|
|
x = pcomp? x | SC_COMP_PROT: x &~ SC_COMP_PROT; |
754 |
|
|
x = accomp? x | SC_COMP_AC: x &~ SC_COMP_AC; |
755 |
|
|
if (ioctl(ppp_fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) { |
756 |
|
|
syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m"); |
757 |
|
|
quit(); |
758 |
|
|
} |
759 |
|
|
} |
760 |
|
|
|
761 |
|
|
|
762 |
|
|
/* |
763 |
|
|
* ppp_set_xaccm - set the extended transmit ACCM for the interface. |
764 |
|
|
*/ |
765 |
|
|
void |
766 |
|
|
ppp_set_xaccm(unit, accm) |
767 |
|
|
int unit; |
768 |
|
|
ext_accm accm; |
769 |
|
|
{ |
770 |
|
|
if (ioctl(ppp_fd, PPPIOCSXASYNCMAP, accm) < 0 && errno != ENOTTY) |
771 |
|
|
syslog(LOG_WARNING, "ioctl(set extended ACCM): %m"); |
772 |
|
|
} |
773 |
|
|
|
774 |
|
|
|
775 |
|
|
/* |
776 |
|
|
* ppp_recv_config - configure the receive-side characteristics of |
777 |
|
|
* the ppp interface. |
778 |
|
|
*/ |
779 |
|
|
void |
780 |
|
|
ppp_recv_config(unit, mru, asyncmap, pcomp, accomp) |
781 |
|
|
int unit, mru; |
782 |
|
|
u_int32_t asyncmap; |
783 |
|
|
int pcomp, accomp; |
784 |
|
|
{ |
785 |
|
|
int x; |
786 |
|
|
|
787 |
|
|
if (ioctl(ppp_fd, PPPIOCSMRU, (caddr_t) &mru) < 0) { |
788 |
|
|
syslog(LOG_ERR, "ioctl(PPPIOCSMRU): %m"); |
789 |
|
|
quit(); |
790 |
|
|
} |
791 |
|
|
if (ioctl(ppp_fd, PPPIOCSRASYNCMAP, (caddr_t) &asyncmap) < 0) { |
792 |
|
|
syslog(LOG_ERR, "ioctl(PPPIOCSRASYNCMAP): %m"); |
793 |
|
|
quit(); |
794 |
|
|
} |
795 |
|
|
if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) { |
796 |
|
|
syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m"); |
797 |
|
|
quit(); |
798 |
|
|
} |
799 |
|
|
x = !accomp? x | SC_REJ_COMP_AC: x &~ SC_REJ_COMP_AC; |
800 |
|
|
if (ioctl(ppp_fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) { |
801 |
|
|
syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m"); |
802 |
|
|
quit(); |
803 |
|
|
} |
804 |
|
|
} |
805 |
|
|
|
806 |
|
|
/* |
807 |
|
|
* ccp_test - ask kernel whether a given compression method |
808 |
|
|
* is acceptable for use. Returns 1 if the method and parameters |
809 |
|
|
* are OK, 0 if the method is known but the parameters are not OK |
810 |
|
|
* (e.g. code size should be reduced), or -1 if the method is unknown. |
811 |
|
|
*/ |
812 |
|
|
int |
813 |
|
|
ccp_test(unit, opt_ptr, opt_len, for_transmit) |
814 |
|
|
int unit, opt_len, for_transmit; |
815 |
|
|
u_char *opt_ptr; |
816 |
|
|
{ |
817 |
|
|
struct ppp_option_data data; |
818 |
|
|
|
819 |
|
|
data.ptr = opt_ptr; |
820 |
|
|
data.length = opt_len; |
821 |
|
|
data.transmit = for_transmit; |
822 |
|
|
if (ioctl(ttyfd, PPPIOCSCOMPRESS, (caddr_t) &data) >= 0) |
823 |
|
|
return 1; |
824 |
|
|
return (errno == ENOBUFS)? 0: -1; |
825 |
|
|
} |
826 |
|
|
|
827 |
|
|
/* |
828 |
|
|
* ccp_flags_set - inform kernel about the current state of CCP. |
829 |
|
|
*/ |
830 |
|
|
void |
831 |
|
|
ccp_flags_set(unit, isopen, isup) |
832 |
|
|
int unit, isopen, isup; |
833 |
|
|
{ |
834 |
|
|
int x; |
835 |
|
|
|
836 |
|
|
if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) { |
837 |
|
|
syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m"); |
838 |
|
|
return; |
839 |
|
|
} |
840 |
|
|
x = isopen? x | SC_CCP_OPEN: x &~ SC_CCP_OPEN; |
841 |
|
|
x = isup? x | SC_CCP_UP: x &~ SC_CCP_UP; |
842 |
|
|
if (ioctl(ppp_fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) |
843 |
|
|
syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m"); |
844 |
|
|
} |
845 |
|
|
|
846 |
|
|
/* |
847 |
|
|
* ccp_fatal_error - returns 1 if decompression was disabled as a |
848 |
|
|
* result of an error detected after decompression of a packet, |
849 |
|
|
* 0 otherwise. This is necessary because of patent nonsense. |
850 |
|
|
*/ |
851 |
|
|
int |
852 |
|
|
ccp_fatal_error(unit) |
853 |
|
|
int unit; |
854 |
|
|
{ |
855 |
|
|
int x; |
856 |
|
|
|
857 |
|
|
if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) { |
858 |
|
|
syslog(LOG_ERR, "ioctl(PPPIOCGFLAGS): %m"); |
859 |
|
|
return 0; |
860 |
|
|
} |
861 |
|
|
return x & SC_DC_FERROR; |
862 |
|
|
} |
863 |
|
|
|
864 |
|
|
/* |
865 |
|
|
* get_idle_time - return how long the link has been idle. |
866 |
|
|
*/ |
867 |
|
|
int |
868 |
|
|
get_idle_time(u, ip) |
869 |
|
|
int u; |
870 |
|
|
struct ppp_idle *ip; |
871 |
|
|
{ |
872 |
|
|
return ioctl(ppp_fd, PPPIOCGIDLE, ip) >= 0; |
873 |
|
|
} |
874 |
|
|
|
875 |
|
|
|
876 |
|
|
#ifdef PPP_FILTER |
877 |
|
|
/* |
878 |
|
|
* set_filters - transfer the pass and active filters to the kernel. |
879 |
|
|
*/ |
880 |
|
|
int |
881 |
|
|
set_filters(pass, active) |
882 |
|
|
struct bpf_program *pass, *active; |
883 |
|
|
{ |
884 |
|
|
int ret = 1; |
885 |
|
|
|
886 |
|
|
if (pass->bf_len > 0) { |
887 |
|
|
if (ioctl(ppp_fd, PPPIOCSPASS, pass) < 0) { |
888 |
|
|
syslog(LOG_ERR, "Couldn't set pass-filter in kernel: %m"); |
889 |
|
|
ret = 0; |
890 |
|
|
} |
891 |
|
|
} |
892 |
|
|
if (active->bf_len > 0) { |
893 |
|
|
if (ioctl(ppp_fd, PPPIOCSACTIVE, active) < 0) { |
894 |
|
|
syslog(LOG_ERR, "Couldn't set active-filter in kernel: %m"); |
895 |
|
|
ret = 0; |
896 |
|
|
} |
897 |
|
|
} |
898 |
|
|
return ret; |
899 |
|
|
} |
900 |
|
|
#endif |
901 |
|
|
|
902 |
|
|
/* |
903 |
|
|
* sifvjcomp - config tcp header compression |
904 |
|
|
*/ |
905 |
|
|
int |
906 |
|
|
sifvjcomp(u, vjcomp, cidcomp, maxcid) |
907 |
|
|
int u, vjcomp, cidcomp, maxcid; |
908 |
|
|
{ |
909 |
|
|
u_int x; |
910 |
|
|
|
911 |
|
|
if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) { |
912 |
|
|
syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m"); |
913 |
|
|
return 0; |
914 |
|
|
} |
915 |
|
|
x = vjcomp ? x | SC_COMP_TCP: x &~ SC_COMP_TCP; |
916 |
|
|
x = cidcomp? x & ~SC_NO_TCP_CCID: x | SC_NO_TCP_CCID; |
917 |
|
|
if (ioctl(ppp_fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) { |
918 |
|
|
syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m"); |
919 |
|
|
return 0; |
920 |
|
|
} |
921 |
|
|
if (vjcomp && ioctl(ppp_fd, PPPIOCSMAXCID, (caddr_t) &maxcid) < 0) { |
922 |
|
|
syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m"); |
923 |
|
|
return 0; |
924 |
|
|
} |
925 |
|
|
return 1; |
926 |
|
|
} |
927 |
|
|
|
928 |
|
|
/* |
929 |
|
|
* sifup - Config the interface up and enable IP packets to pass. |
930 |
|
|
*/ |
931 |
|
|
int |
932 |
|
|
sifup(u) |
933 |
|
|
int u; |
934 |
|
|
{ |
935 |
|
|
struct ifreq ifr; |
936 |
|
|
|
937 |
|
|
strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); |
938 |
|
|
if (ioctl(sockfd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) { |
939 |
|
|
syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m"); |
940 |
|
|
return 0; |
941 |
|
|
} |
942 |
|
|
ifr.ifr_flags |= IFF_UP; |
943 |
|
|
if (ioctl(sockfd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) { |
944 |
|
|
syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m"); |
945 |
|
|
return 0; |
946 |
|
|
} |
947 |
|
|
if_is_up = 1; |
948 |
|
|
return 1; |
949 |
|
|
} |
950 |
|
|
|
951 |
|
|
/* |
952 |
|
|
* sifnpmode - Set the mode for handling packets for a given NP. |
953 |
|
|
*/ |
954 |
|
|
int |
955 |
|
|
sifnpmode(u, proto, mode) |
956 |
|
|
int u; |
957 |
|
|
int proto; |
958 |
|
|
enum NPmode mode; |
959 |
|
|
{ |
960 |
|
|
struct npioctl npi; |
961 |
|
|
|
962 |
|
|
npi.protocol = proto; |
963 |
|
|
npi.mode = mode; |
964 |
|
|
if (ioctl(ppp_fd, PPPIOCSNPMODE, &npi) < 0) { |
965 |
|
|
syslog(LOG_ERR, "ioctl(set NP %d mode to %d): %m", proto, mode); |
966 |
|
|
return 0; |
967 |
|
|
} |
968 |
|
|
return 1; |
969 |
|
|
} |
970 |
|
|
|
971 |
|
|
/* |
972 |
|
|
* sifdown - Config the interface down and disable IP. |
973 |
|
|
*/ |
974 |
|
|
int |
975 |
|
|
sifdown(u) |
976 |
|
|
int u; |
977 |
|
|
{ |
978 |
|
|
struct ifreq ifr; |
979 |
|
|
int rv; |
980 |
|
|
struct npioctl npi; |
981 |
|
|
|
982 |
|
|
rv = 1; |
983 |
|
|
npi.protocol = PPP_IP; |
984 |
|
|
npi.mode = NPMODE_ERROR; |
985 |
|
|
ioctl(ppp_fd, PPPIOCSNPMODE, (caddr_t) &npi); |
986 |
|
|
/* ignore errors, because ppp_fd might have been closed by now. */ |
987 |
|
|
|
988 |
|
|
strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); |
989 |
|
|
if (ioctl(sockfd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) { |
990 |
|
|
syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m"); |
991 |
|
|
rv = 0; |
992 |
|
|
} else { |
993 |
|
|
ifr.ifr_flags &= ~IFF_UP; |
994 |
|
|
if (ioctl(sockfd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) { |
995 |
|
|
syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m"); |
996 |
|
|
rv = 0; |
997 |
|
|
} else |
998 |
|
|
if_is_up = 0; |
999 |
|
|
} |
1000 |
|
|
return rv; |
1001 |
|
|
} |
1002 |
|
|
|
1003 |
|
|
/* |
1004 |
|
|
* SET_SA_FAMILY - set the sa_family field of a struct sockaddr, |
1005 |
|
|
* if it exists. |
1006 |
|
|
*/ |
1007 |
|
|
#define SET_SA_FAMILY(addr, family) \ |
1008 |
|
|
BZERO((char *) &(addr), sizeof(addr)); \ |
1009 |
|
|
addr.sa_family = (family); \ |
1010 |
|
|
addr.sa_len = sizeof(addr); |
1011 |
|
|
|
1012 |
|
|
/* |
1013 |
|
|
* sifaddr - Config the interface IP addresses and netmask. |
1014 |
|
|
*/ |
1015 |
|
|
int |
1016 |
|
|
sifaddr(u, o, h, m) |
1017 |
|
|
int u; |
1018 |
|
|
u_int32_t o, h, m; |
1019 |
|
|
{ |
1020 |
|
|
struct ifaliasreq ifra; |
1021 |
|
|
struct ifreq ifr; |
1022 |
|
|
char s1[64], s2[64]; |
1023 |
|
|
|
1024 |
|
|
strlcpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name)); |
1025 |
|
|
SET_SA_FAMILY(ifra.ifra_addr, AF_INET); |
1026 |
|
|
((struct sockaddr_in *) &ifra.ifra_addr)->sin_addr.s_addr = o; |
1027 |
|
|
SET_SA_FAMILY(ifra.ifra_broadaddr, AF_INET); |
1028 |
|
|
((struct sockaddr_in *) &ifra.ifra_broadaddr)->sin_addr.s_addr = h; |
1029 |
|
|
if (m != 0) { |
1030 |
|
|
SET_SA_FAMILY(ifra.ifra_mask, AF_INET); |
1031 |
|
|
((struct sockaddr_in *) &ifra.ifra_mask)->sin_addr.s_addr = m; |
1032 |
|
|
} else |
1033 |
|
|
BZERO(&ifra.ifra_mask, sizeof(ifra.ifra_mask)); |
1034 |
|
|
BZERO(&ifr, sizeof(ifr)); |
1035 |
|
|
strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); |
1036 |
|
|
if (ioctl(sockfd, SIOCDIFADDR, (caddr_t) &ifr) < 0) { |
1037 |
|
|
if (errno != EADDRNOTAVAIL) |
1038 |
|
|
syslog(LOG_WARNING, "Couldn't remove interface address: %m"); |
1039 |
|
|
} |
1040 |
|
|
if (ioctl(sockfd, SIOCAIFADDR, (caddr_t) &ifra) < 0) { |
1041 |
|
|
if (errno != EEXIST) { |
1042 |
|
|
syslog(LOG_ERR, "Couldn't set interface address: %m"); |
1043 |
|
|
return 0; |
1044 |
|
|
} |
1045 |
|
|
strlcpy(s1, ip_ntoa(o), sizeof(s1)); |
1046 |
|
|
strlcpy(s2, ip_ntoa(h), sizeof(s2)); |
1047 |
|
|
syslog(LOG_WARNING, |
1048 |
|
|
"Couldn't set interface address: " |
1049 |
|
|
"Address %s or destination %s already exists", s1, s2); |
1050 |
|
|
} |
1051 |
|
|
ifaddrs[0] = o; |
1052 |
|
|
ifaddrs[1] = h; |
1053 |
|
|
return 1; |
1054 |
|
|
} |
1055 |
|
|
|
1056 |
|
|
/* |
1057 |
|
|
* cifaddr - Clear the interface IP addresses, and delete routes |
1058 |
|
|
* through the interface if possible. |
1059 |
|
|
*/ |
1060 |
|
|
int |
1061 |
|
|
cifaddr(u, o, h) |
1062 |
|
|
int u; |
1063 |
|
|
u_int32_t o, h; |
1064 |
|
|
{ |
1065 |
|
|
struct ifaliasreq ifra; |
1066 |
|
|
|
1067 |
|
|
ifaddrs[0] = 0; |
1068 |
|
|
strlcpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name)); |
1069 |
|
|
SET_SA_FAMILY(ifra.ifra_addr, AF_INET); |
1070 |
|
|
((struct sockaddr_in *) &ifra.ifra_addr)->sin_addr.s_addr = o; |
1071 |
|
|
SET_SA_FAMILY(ifra.ifra_broadaddr, AF_INET); |
1072 |
|
|
((struct sockaddr_in *) &ifra.ifra_broadaddr)->sin_addr.s_addr = h; |
1073 |
|
|
BZERO(&ifra.ifra_mask, sizeof(ifra.ifra_mask)); |
1074 |
|
|
if (ioctl(sockfd, SIOCDIFADDR, (caddr_t) &ifra) < 0) { |
1075 |
|
|
if (errno != EADDRNOTAVAIL) |
1076 |
|
|
syslog(LOG_WARNING, "Couldn't delete interface address: %m"); |
1077 |
|
|
return 0; |
1078 |
|
|
} |
1079 |
|
|
return 1; |
1080 |
|
|
} |
1081 |
|
|
|
1082 |
|
|
/* |
1083 |
|
|
* sifdefaultroute - assign a default route through the address given. |
1084 |
|
|
*/ |
1085 |
|
|
int |
1086 |
|
|
sifdefaultroute(u, l, g) |
1087 |
|
|
int u; |
1088 |
|
|
u_int32_t l, g; |
1089 |
|
|
{ |
1090 |
|
|
return dodefaultroute(g, 's'); |
1091 |
|
|
} |
1092 |
|
|
|
1093 |
|
|
/* |
1094 |
|
|
* cifdefaultroute - delete a default route through the address given. |
1095 |
|
|
*/ |
1096 |
|
|
int |
1097 |
|
|
cifdefaultroute(u, l, g) |
1098 |
|
|
int u; |
1099 |
|
|
u_int32_t l, g; |
1100 |
|
|
{ |
1101 |
|
|
return dodefaultroute(g, 'c'); |
1102 |
|
|
} |
1103 |
|
|
|
1104 |
|
|
/* |
1105 |
|
|
* dodefaultroute - talk to a routing socket to add/delete a default route. |
1106 |
|
|
*/ |
1107 |
|
|
static int |
1108 |
|
|
dodefaultroute(g, cmd) |
1109 |
|
|
u_int32_t g; |
1110 |
|
|
int cmd; |
1111 |
|
|
{ |
1112 |
|
|
int routes; |
1113 |
|
|
struct { |
1114 |
|
|
struct rt_msghdr hdr; |
1115 |
|
|
struct sockaddr_in dst; |
1116 |
|
|
struct sockaddr_in gway; |
1117 |
|
|
struct sockaddr_in mask; |
1118 |
|
|
} rtmsg; |
1119 |
|
|
|
1120 |
|
|
if ((routes = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) { |
1121 |
|
|
syslog(LOG_ERR, "Couldn't %s default route: socket: %m", |
1122 |
|
|
cmd=='s'? "add": "delete"); |
1123 |
|
|
return 0; |
1124 |
|
|
} |
1125 |
|
|
|
1126 |
|
|
memset(&rtmsg, 0, sizeof(rtmsg)); |
1127 |
|
|
rtmsg.hdr.rtm_type = cmd == 's'? RTM_ADD: RTM_DELETE; |
1128 |
|
|
rtmsg.hdr.rtm_flags = RTF_UP | RTF_GATEWAY; |
1129 |
|
|
rtmsg.hdr.rtm_version = RTM_VERSION; |
1130 |
|
|
rtmsg.hdr.rtm_seq = ++rtm_seq; |
1131 |
|
|
rtmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; |
1132 |
|
|
rtmsg.dst.sin_len = sizeof(rtmsg.dst); |
1133 |
|
|
rtmsg.dst.sin_family = AF_INET; |
1134 |
|
|
rtmsg.gway.sin_len = sizeof(rtmsg.gway); |
1135 |
|
|
rtmsg.gway.sin_family = AF_INET; |
1136 |
|
|
rtmsg.gway.sin_addr.s_addr = g; |
1137 |
|
|
rtmsg.mask.sin_len = sizeof(rtmsg.dst); |
1138 |
|
|
rtmsg.mask.sin_family = AF_INET; |
1139 |
|
|
|
1140 |
|
|
rtmsg.hdr.rtm_msglen = sizeof(rtmsg); |
1141 |
|
|
if (write(routes, &rtmsg, sizeof(rtmsg)) < 0) { |
1142 |
|
|
syslog(LOG_ERR, "Couldn't %s default route: %m", |
1143 |
|
|
cmd=='s'? "add": "delete"); |
1144 |
|
|
close(routes); |
1145 |
|
|
return 0; |
1146 |
|
|
} |
1147 |
|
|
|
1148 |
|
|
close(routes); |
1149 |
|
|
default_route_gateway = (cmd == 's')? g: 0; |
1150 |
|
|
return 1; |
1151 |
|
|
} |
1152 |
|
|
|
1153 |
|
|
#if RTM_VERSION >= 3 |
1154 |
|
|
|
1155 |
|
|
/* |
1156 |
|
|
* sifproxyarp - Make a proxy ARP entry for the peer. |
1157 |
|
|
*/ |
1158 |
|
|
static struct { |
1159 |
|
|
struct rt_msghdr hdr; |
1160 |
|
|
struct sockaddr_inarp dst; |
1161 |
|
|
struct sockaddr_dl hwa; |
1162 |
|
|
char extra[128]; |
1163 |
|
|
} arpmsg; |
1164 |
|
|
|
1165 |
|
|
static int arpmsg_valid; |
1166 |
|
|
|
1167 |
|
|
int |
1168 |
|
|
sifproxyarp(unit, hisaddr) |
1169 |
|
|
int unit; |
1170 |
|
|
u_int32_t hisaddr; |
1171 |
|
|
{ |
1172 |
|
|
int routes; |
1173 |
|
|
|
1174 |
|
|
/* |
1175 |
|
|
* Get the hardware address of an interface on the same subnet |
1176 |
|
|
* as our local address. |
1177 |
|
|
*/ |
1178 |
|
|
memset(&arpmsg, 0, sizeof(arpmsg)); |
1179 |
|
|
if (!get_ether_addr(hisaddr, &arpmsg.hwa)) { |
1180 |
|
|
syslog(LOG_ERR, "Cannot determine ethernet address for proxy ARP"); |
1181 |
|
|
return 0; |
1182 |
|
|
} |
1183 |
|
|
|
1184 |
|
|
if ((routes = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) { |
1185 |
|
|
syslog(LOG_ERR, "Couldn't add proxy arp entry: socket: %m"); |
1186 |
|
|
return 0; |
1187 |
|
|
} |
1188 |
|
|
|
1189 |
|
|
arpmsg.hdr.rtm_type = RTM_ADD; |
1190 |
|
|
arpmsg.hdr.rtm_flags = RTF_ANNOUNCE | RTF_HOST | RTF_STATIC; |
1191 |
|
|
arpmsg.hdr.rtm_version = RTM_VERSION; |
1192 |
|
|
arpmsg.hdr.rtm_seq = ++rtm_seq; |
1193 |
|
|
arpmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY; |
1194 |
|
|
arpmsg.hdr.rtm_inits = RTV_EXPIRE; |
1195 |
|
|
arpmsg.dst.sin_len = sizeof(struct sockaddr_inarp); |
1196 |
|
|
arpmsg.dst.sin_family = AF_INET; |
1197 |
|
|
arpmsg.dst.sin_addr.s_addr = hisaddr; |
1198 |
|
|
arpmsg.dst.sin_other = SIN_PROXY; |
1199 |
|
|
|
1200 |
|
|
arpmsg.hdr.rtm_msglen = (char *) &arpmsg.hwa - (char *) &arpmsg |
1201 |
|
|
+ arpmsg.hwa.sdl_len; |
1202 |
|
|
if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) < 0) { |
1203 |
|
|
syslog(LOG_ERR, "Couldn't add proxy arp entry: %m"); |
1204 |
|
|
close(routes); |
1205 |
|
|
return 0; |
1206 |
|
|
} |
1207 |
|
|
|
1208 |
|
|
close(routes); |
1209 |
|
|
arpmsg_valid = 1; |
1210 |
|
|
proxy_arp_addr = hisaddr; |
1211 |
|
|
return 1; |
1212 |
|
|
} |
1213 |
|
|
|
1214 |
|
|
/* |
1215 |
|
|
* cifproxyarp - Delete the proxy ARP entry for the peer. |
1216 |
|
|
*/ |
1217 |
|
|
int |
1218 |
|
|
cifproxyarp(unit, hisaddr) |
1219 |
|
|
int unit; |
1220 |
|
|
u_int32_t hisaddr; |
1221 |
|
|
{ |
1222 |
|
|
int routes; |
1223 |
|
|
|
1224 |
|
|
if (!arpmsg_valid) |
1225 |
|
|
return 0; |
1226 |
|
|
arpmsg_valid = 0; |
1227 |
|
|
|
1228 |
|
|
arpmsg.hdr.rtm_type = RTM_DELETE; |
1229 |
|
|
arpmsg.hdr.rtm_seq = ++rtm_seq; |
1230 |
|
|
|
1231 |
|
|
if ((routes = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) { |
1232 |
|
|
syslog(LOG_ERR, "Couldn't delete proxy arp entry: socket: %m"); |
1233 |
|
|
return 0; |
1234 |
|
|
} |
1235 |
|
|
|
1236 |
|
|
if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) < 0) { |
1237 |
|
|
syslog(LOG_ERR, "Couldn't delete proxy arp entry: %m"); |
1238 |
|
|
close(routes); |
1239 |
|
|
return 0; |
1240 |
|
|
} |
1241 |
|
|
|
1242 |
|
|
close(routes); |
1243 |
|
|
proxy_arp_addr = 0; |
1244 |
|
|
return 1; |
1245 |
|
|
} |
1246 |
|
|
|
1247 |
|
|
#else /* RTM_VERSION */ |
1248 |
|
|
|
1249 |
|
|
/* |
1250 |
|
|
* sifproxyarp - Make a proxy ARP entry for the peer. |
1251 |
|
|
*/ |
1252 |
|
|
int |
1253 |
|
|
sifproxyarp(unit, hisaddr) |
1254 |
|
|
int unit; |
1255 |
|
|
u_int32_t hisaddr; |
1256 |
|
|
{ |
1257 |
|
|
struct arpreq arpreq; |
1258 |
|
|
struct { |
1259 |
|
|
struct sockaddr_dl sdl; |
1260 |
|
|
char space[128]; |
1261 |
|
|
} dls; |
1262 |
|
|
|
1263 |
|
|
BZERO(&arpreq, sizeof(arpreq)); |
1264 |
|
|
|
1265 |
|
|
/* |
1266 |
|
|
* Get the hardware address of an interface on the same subnet |
1267 |
|
|
* as our local address. |
1268 |
|
|
*/ |
1269 |
|
|
if (!get_ether_addr(hisaddr, &dls.sdl)) { |
1270 |
|
|
syslog(LOG_ERR, "Cannot determine ethernet address for proxy ARP"); |
1271 |
|
|
return 0; |
1272 |
|
|
} |
1273 |
|
|
|
1274 |
|
|
arpreq.arp_ha.sa_len = sizeof(struct sockaddr); |
1275 |
|
|
arpreq.arp_ha.sa_family = AF_UNSPEC; |
1276 |
|
|
BCOPY(LLADDR(&dls.sdl), arpreq.arp_ha.sa_data, dls.sdl.sdl_alen); |
1277 |
|
|
SET_SA_FAMILY(arpreq.arp_pa, AF_INET); |
1278 |
|
|
((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr; |
1279 |
|
|
arpreq.arp_flags = ATF_PERM | ATF_PUBL; |
1280 |
|
|
if (ioctl(sockfd, SIOCSARP, (caddr_t)&arpreq) < 0) { |
1281 |
|
|
syslog(LOG_ERR, "Couldn't add proxy arp entry: %m"); |
1282 |
|
|
return 0; |
1283 |
|
|
} |
1284 |
|
|
|
1285 |
|
|
proxy_arp_addr = hisaddr; |
1286 |
|
|
return 1; |
1287 |
|
|
} |
1288 |
|
|
|
1289 |
|
|
/* |
1290 |
|
|
* cifproxyarp - Delete the proxy ARP entry for the peer. |
1291 |
|
|
*/ |
1292 |
|
|
int |
1293 |
|
|
cifproxyarp(unit, hisaddr) |
1294 |
|
|
int unit; |
1295 |
|
|
u_int32_t hisaddr; |
1296 |
|
|
{ |
1297 |
|
|
struct arpreq arpreq; |
1298 |
|
|
|
1299 |
|
|
BZERO(&arpreq, sizeof(arpreq)); |
1300 |
|
|
SET_SA_FAMILY(arpreq.arp_pa, AF_INET); |
1301 |
|
|
((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr; |
1302 |
|
|
if (ioctl(sockfd, SIOCDARP, (caddr_t)&arpreq) < 0) { |
1303 |
|
|
syslog(LOG_WARNING, "Couldn't delete proxy arp entry: %m"); |
1304 |
|
|
return 0; |
1305 |
|
|
} |
1306 |
|
|
proxy_arp_addr = 0; |
1307 |
|
|
return 1; |
1308 |
|
|
} |
1309 |
|
|
#endif /* RTM_VERSION */ |
1310 |
|
|
|
1311 |
|
|
|
1312 |
|
|
/* |
1313 |
|
|
* get_ether_addr - get the hardware address of an interface on the |
1314 |
|
|
* the same subnet as ipaddr. |
1315 |
|
|
*/ |
1316 |
|
|
#define MAX_IFS 32 |
1317 |
|
|
|
1318 |
|
|
static int |
1319 |
|
|
get_ether_addr(ipaddr, hwaddr) |
1320 |
|
|
u_int32_t ipaddr; |
1321 |
|
|
struct sockaddr_dl *hwaddr; |
1322 |
|
|
{ |
1323 |
|
|
u_int32_t ina, mask; |
1324 |
|
|
struct sockaddr_dl *dla; |
1325 |
|
|
struct ifaddrs *ifap, *ifa, *ifp; |
1326 |
|
|
|
1327 |
|
|
if (getifaddrs(&ifap) != 0) { |
1328 |
|
|
syslog(LOG_ERR, "getifaddrs: %m"); |
1329 |
|
|
return 0; |
1330 |
|
|
} |
1331 |
|
|
|
1332 |
|
|
/* |
1333 |
|
|
* Scan through looking for an interface with an Internet |
1334 |
|
|
* address on the same subnet as `ipaddr'. |
1335 |
|
|
*/ |
1336 |
|
|
for (ifa = ifap; ifa; ifa = ifa->ifa_next) { |
1337 |
|
|
if (ifa->ifa_addr->sa_family == AF_INET) { |
1338 |
|
|
ina = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr; |
1339 |
|
|
/* |
1340 |
|
|
* Check that the interface is up, and not point-to-point |
1341 |
|
|
* or loopback. |
1342 |
|
|
*/ |
1343 |
|
|
if ((ifa->ifa_flags & |
1344 |
|
|
(IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP)) |
1345 |
|
|
!= (IFF_UP|IFF_BROADCAST)) |
1346 |
|
|
continue; |
1347 |
|
|
/* |
1348 |
|
|
* Get its netmask and check that it's on the right subnet. |
1349 |
|
|
*/ |
1350 |
|
|
mask = ((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr.s_addr; |
1351 |
|
|
if ((ipaddr & mask) != (ina & mask)) |
1352 |
|
|
continue; |
1353 |
|
|
|
1354 |
|
|
break; |
1355 |
|
|
} |
1356 |
|
|
} |
1357 |
|
|
|
1358 |
|
|
if (ifa == NULL) { |
1359 |
|
|
freeifaddrs(ifap); |
1360 |
|
|
return 0; |
1361 |
|
|
} |
1362 |
|
|
syslog(LOG_INFO, "found interface %s for proxy arp", ifa->ifa_name); |
1363 |
|
|
|
1364 |
|
|
/* |
1365 |
|
|
* Now scan through again looking for a link-level address |
1366 |
|
|
* for this interface. |
1367 |
|
|
*/ |
1368 |
|
|
ifp = ifa; |
1369 |
|
|
for (ifa = ifap; ifa; ifa = ifa->ifa_next) { |
1370 |
|
|
if (strcmp(ifp->ifa_name, ifa->ifa_name) == 0 |
1371 |
|
|
&& ifa->ifa_addr->sa_family == AF_LINK) { |
1372 |
|
|
/* |
1373 |
|
|
* Found the link-level address - copy it out |
1374 |
|
|
*/ |
1375 |
|
|
dla = (struct sockaddr_dl *)ifa->ifa_addr; |
1376 |
|
|
BCOPY(dla, hwaddr, dla->sdl_len); |
1377 |
|
|
return 1; |
1378 |
|
|
} |
1379 |
|
|
} |
1380 |
|
|
|
1381 |
|
|
freeifaddrs(ifap); |
1382 |
|
|
return 0; |
1383 |
|
|
} |
1384 |
|
|
|
1385 |
|
|
/* |
1386 |
|
|
* Return user specified netmask, modified by any mask we might determine |
1387 |
|
|
* for address `addr' (in network byte order). |
1388 |
|
|
* Here we scan through the system's list of interfaces, looking for |
1389 |
|
|
* any non-point-to-point interfaces which might appear to be on the same |
1390 |
|
|
* network as `addr'. If we find any, we OR in their netmask to the |
1391 |
|
|
* user-specified netmask. |
1392 |
|
|
*/ |
1393 |
|
|
u_int32_t |
1394 |
|
|
GetMask(addr) |
1395 |
|
|
u_int32_t addr; |
1396 |
|
|
{ |
1397 |
|
|
u_int32_t mask, nmask, ina; |
1398 |
|
|
struct ifaddrs *ifap, *ifa; |
1399 |
|
|
|
1400 |
|
|
addr = ntohl(addr); |
1401 |
|
|
if (IN_CLASSA(addr)) /* determine network mask for address class */ |
1402 |
|
|
nmask = IN_CLASSA_NET; |
1403 |
|
|
else if (IN_CLASSB(addr)) |
1404 |
|
|
nmask = IN_CLASSB_NET; |
1405 |
|
|
else |
1406 |
|
|
nmask = IN_CLASSC_NET; |
1407 |
|
|
/* class D nets are disallowed by bad_ip_adrs */ |
1408 |
|
|
mask = netmask | htonl(nmask); |
1409 |
|
|
|
1410 |
|
|
/* |
1411 |
|
|
* Scan through the system's network interfaces. |
1412 |
|
|
*/ |
1413 |
|
|
if (getifaddrs(&ifap) != 0) { |
1414 |
|
|
syslog(LOG_WARNING, "getifaddrs: %m"); |
1415 |
|
|
return mask; |
1416 |
|
|
} |
1417 |
|
|
for (ifa = ifap; ifa; ifa = ifa->ifa_next) { |
1418 |
|
|
/* |
1419 |
|
|
* Check the interface's internet address. |
1420 |
|
|
*/ |
1421 |
|
|
if (ifa->ifa_addr->sa_family != AF_INET) |
1422 |
|
|
continue; |
1423 |
|
|
ina = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr; |
1424 |
|
|
if ((ntohl(ina) & nmask) != (addr & nmask)) |
1425 |
|
|
continue; |
1426 |
|
|
/* |
1427 |
|
|
* Check that the interface is up, and not point-to-point or loopback. |
1428 |
|
|
*/ |
1429 |
|
|
if ((ifa->ifa_flags & (IFF_UP|IFF_POINTOPOINT|IFF_LOOPBACK)) |
1430 |
|
|
!= IFF_UP) |
1431 |
|
|
continue; |
1432 |
|
|
/* |
1433 |
|
|
* Get its netmask and OR it into our mask. |
1434 |
|
|
*/ |
1435 |
|
|
mask |= ((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr.s_addr; |
1436 |
|
|
} |
1437 |
|
|
|
1438 |
|
|
freeifaddrs(ifap); |
1439 |
|
|
return mask; |
1440 |
|
|
} |
1441 |
|
|
|
1442 |
|
|
/* |
1443 |
|
|
* lock - create a lock file for the named lock device |
1444 |
|
|
*/ |
1445 |
|
|
#define LOCK_PREFIX "/var/spool/lock/LCK.." |
1446 |
|
|
|
1447 |
|
|
int |
1448 |
|
|
lock(dev) |
1449 |
|
|
char *dev; |
1450 |
|
|
{ |
1451 |
|
|
char hdb_lock_buffer[12]; |
1452 |
|
|
int fd, n; |
1453 |
|
|
pid_t pid; |
1454 |
|
|
char *p; |
1455 |
|
|
|
1456 |
|
|
if ((p = strrchr(dev, '/')) != NULL) |
1457 |
|
|
dev = p + 1; |
1458 |
|
|
if (asprintf(&lock_file, "%s%s", LOCK_PREFIX, dev) == -1) |
1459 |
|
|
novm("lock file name"); |
1460 |
|
|
|
1461 |
|
|
while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) { |
1462 |
|
|
if (errno == EEXIST |
1463 |
|
|
&& (fd = open(lock_file, O_RDONLY, 0)) >= 0) { |
1464 |
|
|
/* Read the lock file to find out who has the device locked */ |
1465 |
|
|
n = read(fd, hdb_lock_buffer, 11); |
1466 |
|
|
if (n <= 0) { |
1467 |
|
|
syslog(LOG_ERR, "Can't read pid from lock file %s", lock_file); |
1468 |
|
|
close(fd); |
1469 |
|
|
} else { |
1470 |
|
|
hdb_lock_buffer[n] = 0; |
1471 |
|
|
pid = atoi(hdb_lock_buffer); |
1472 |
|
|
if (kill(pid, 0) == -1 && errno == ESRCH) { |
1473 |
|
|
/* pid no longer exists - remove the lock file */ |
1474 |
|
|
if (unlink(lock_file) == 0) { |
1475 |
|
|
close(fd); |
1476 |
|
|
syslog(LOG_NOTICE, "Removed stale lock on %s (pid %ld)", |
1477 |
|
|
dev, (long)pid); |
1478 |
|
|
continue; |
1479 |
|
|
} else |
1480 |
|
|
syslog(LOG_WARNING, "Couldn't remove stale lock on %s", |
1481 |
|
|
dev); |
1482 |
|
|
} else |
1483 |
|
|
syslog(LOG_NOTICE, "Device %s is locked by pid %ld", |
1484 |
|
|
dev, (long)pid); |
1485 |
|
|
} |
1486 |
|
|
close(fd); |
1487 |
|
|
} else |
1488 |
|
|
syslog(LOG_ERR, "Can't create lock file %s: %m", lock_file); |
1489 |
|
|
free(lock_file); |
1490 |
|
|
lock_file = NULL; |
1491 |
|
|
return -1; |
1492 |
|
|
} |
1493 |
|
|
|
1494 |
|
|
snprintf(hdb_lock_buffer, sizeof hdb_lock_buffer, "%10ld\n", (long)getpid()); |
1495 |
|
|
write(fd, hdb_lock_buffer, 11); |
1496 |
|
|
|
1497 |
|
|
close(fd); |
1498 |
|
|
return 0; |
1499 |
|
|
} |
1500 |
|
|
|
1501 |
|
|
/* |
1502 |
|
|
* unlock - remove our lockfile |
1503 |
|
|
*/ |
1504 |
|
|
void |
1505 |
|
|
unlock() |
1506 |
|
|
{ |
1507 |
|
|
if (lock_file) { |
1508 |
|
|
unlink(lock_file); |
1509 |
|
|
free(lock_file); |
1510 |
|
|
lock_file = NULL; |
1511 |
|
|
} |
1512 |
|
|
} |