| File: | src/usr.sbin/pppd/sys-bsd.c |
| Warning: | line 644, 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 | } |