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