2 * sys-bsd.c - System-dependent procedures for setting up
3 * PPP interfaces on bsd-4.4-ish systems (including 386BSD, NetBSD, etc.)
5 * Copyright (c) 1989 Carnegie Mellon University.
8 * Redistribution and use in source and binary forms are permitted
9 * provided that the above copyright notice and this paragraph are
10 * duplicated in all such forms and that any documentation,
11 * advertising materials, and other materials related to such
12 * distribution and use acknowledge that the software was developed
13 * by Carnegie Mellon University. The name of the
14 * University may not be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22 static char rcsid[] = "$Id: sys-bsd.c,v 1.3 1994/04/11 07:16:50 paulus Exp $";
30 #include <sys/ioctl.h>
31 #include <sys/types.h>
32 #include <sys/socket.h>
34 #include <sys/errno.h>
38 #include <net/if_ppp.h>
39 #include <net/route.h>
40 #include <net/if_dl.h>
41 #include <netinet/in.h>
46 static int initdisc; /* Initial TTY discipline */
50 * establish_ppp - Turn the serial port into a ppp interface.
55 int pppdisc = PPPDISC;
57 if (ioctl(fd, TIOCGETD, &initdisc) < 0) {
58 syslog(LOG_ERR, "ioctl(TIOCGETD): %m");
61 if (ioctl(fd, TIOCSETD, &pppdisc) < 0) {
62 syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
67 * Find out which interface we were given.
69 if (ioctl(fd, PPPIOCGUNIT, &ifunit) < 0) {
70 syslog(LOG_ERR, "ioctl(PPPIOCGUNIT): %m");
77 * disestablish_ppp - Restore the serial port to normal operation.
78 * This shouldn't call die() because it's called from die().
83 if (ioctl(fd, TIOCSETD, &initdisc) < 0)
84 syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
89 * output - Output PPP packet.
98 MAINDEBUG((LOG_WARNING, "output: unit != 0!"));
100 log_packet(p, len, "sent ");
102 if (write(fd, p, len) < 0) {
103 syslog(LOG_ERR, "write: %m");
110 * read_packet - get a PPP packet from the serial device.
118 if ((len = read(fd, buf, MTU + DLLHEADERLEN)) < 0) {
119 if (errno == EWOULDBLOCK) {
120 MAINDEBUG((LOG_DEBUG, "read(fd): EWOULDBLOCK"));
123 syslog(LOG_ERR, "read(fd): %m");
131 * ppp_send_config - configure the transmit characteristics of
135 ppp_send_config(unit, mtu, asyncmap, pcomp, accomp)
143 strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
145 if (ioctl(s, SIOCSIFMTU, (caddr_t) &ifr) < 0) {
146 syslog(LOG_ERR, "ioctl(SIOCSIFMTU): %m");
150 if (ioctl(fd, PPPIOCSASYNCMAP, (caddr_t) &asyncmap) < 0) {
151 syslog(LOG_ERR, "ioctl(PPPIOCSASYNCMAP): %m");
155 if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
156 syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
159 x = pcomp? x | SC_COMP_PROT: x &~ SC_COMP_PROT;
160 x = accomp? x | SC_COMP_AC: x &~ SC_COMP_AC;
161 if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
162 syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
168 * ppp_recv_config - configure the receive-side characteristics of
169 * the ppp interface. At present this does nothing.
172 ppp_recv_config(unit, mru, asyncmap, pcomp, accomp)
179 if (ioctl(fd, PPPIOCSMRU, (caddr_t) &mru) < 0) {
180 syslog(LOG_ERR, "ioctl(PPPIOCSMRU): %m");
183 if (ioctl(fd, PPPIOCSRASYNCMAP, (caddr_t) &asyncmap) < 0) {
184 syslog(LOG_ERR, "ioctl(PPPIOCSRASYNCMAP): %m");
187 if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
188 syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
191 x = !accomp? x | SC_REJ_COMP_AC: x &~ SC_REJ_COMP_AC;
192 if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
193 syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
199 * sifvjcomp - config tcp header compression
202 sifvjcomp(u, vjcomp, cidcomp, maxcid)
203 int u, vjcomp, cidcomp, maxcid;
207 if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
208 syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
211 x = vjcomp ? x | SC_COMP_TCP: x &~ SC_COMP_TCP;
212 x = cidcomp? x & ~SC_NO_TCP_CCID: x | SC_NO_TCP_CCID;
213 if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
214 syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
217 if (ioctl(fd, PPPIOCSMAXCID, (caddr_t) &maxcid) < 0) {
218 syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
225 * sifup - Config the interface up.
231 strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
232 if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
233 syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
236 ifr.ifr_flags |= IFF_UP;
237 if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
238 syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
245 * sifdown - Config the interface down.
251 strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
252 if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
253 syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
256 ifr.ifr_flags &= ~IFF_UP;
257 if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
258 syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
265 * SET_SA_FAMILY - set the sa_family field of a struct sockaddr,
268 #define SET_SA_FAMILY(addr, family) \
269 BZERO((char *) &(addr), sizeof(addr)); \
270 addr.sa_family = (family); \
271 addr.sa_len = sizeof(addr);
274 * sifaddr - Config the interface IP addresses and netmask.
279 struct ifaliasreq ifra;
281 strncpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name));
282 SET_SA_FAMILY(ifra.ifra_addr, AF_INET);
283 ((struct sockaddr_in *) &ifra.ifra_addr)->sin_addr.s_addr = o;
284 SET_SA_FAMILY(ifra.ifra_broadaddr, AF_INET);
285 ((struct sockaddr_in *) &ifra.ifra_broadaddr)->sin_addr.s_addr = h;
287 SET_SA_FAMILY(ifra.ifra_mask, AF_INET);
288 ((struct sockaddr_in *) &ifra.ifra_mask)->sin_addr.s_addr = m;
290 BZERO(&ifra.ifra_mask, sizeof(ifra.ifra_mask));
291 if (ioctl(s, SIOCAIFADDR, (caddr_t) &ifra) < 0) {
292 if (errno != EEXIST) {
293 syslog(LOG_ERR, "ioctl(SIOCAIFADDR): %m");
296 syslog(LOG_WARNING, "ioctl(SIOCAIFADDR): Address already exists");
302 * cifaddr - Clear the interface IP addresses, and delete routes
303 * through the interface if possible.
308 struct ifaliasreq ifra;
310 strncpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name));
311 SET_SA_FAMILY(ifra.ifra_addr, AF_INET);
312 ((struct sockaddr_in *) &ifra.ifra_addr)->sin_addr.s_addr = o;
313 SET_SA_FAMILY(ifra.ifra_broadaddr, AF_INET);
314 ((struct sockaddr_in *) &ifra.ifra_broadaddr)->sin_addr.s_addr = h;
315 BZERO(&ifra.ifra_mask, sizeof(ifra.ifra_mask));
316 if (ioctl(s, SIOCDIFADDR, (caddr_t) &ifra) < 0) {
317 syslog(LOG_WARNING, "ioctl(SIOCDIFADDR): %m");
324 * sifdefaultroute - assign a default route through the address given.
327 sifdefaultroute(u, g)
331 SET_SA_FAMILY(rt.rt_dst, AF_INET);
332 SET_SA_FAMILY(rt.rt_gateway, AF_INET);
333 ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = g;
334 rt.rt_flags = RTF_GATEWAY;
335 if (ioctl(s, SIOCADDRT, &rt) < 0) {
336 syslog(LOG_ERR, "default route ioctl(SIOCADDRT): %m");
343 * cifdefaultroute - delete a default route through the address given.
346 cifdefaultroute(u, g)
350 SET_SA_FAMILY(rt.rt_dst, AF_INET);
351 SET_SA_FAMILY(rt.rt_gateway, AF_INET);
352 ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = g;
353 rt.rt_flags = RTF_GATEWAY;
354 if (ioctl(s, SIOCDELRT, &rt) < 0)
355 syslog(LOG_WARNING, "default route ioctl(SIOCDELRT): %m");
359 * sifproxyarp - Make a proxy ARP entry for the peer.
362 sifproxyarp(unit, hisaddr)
366 struct arpreq arpreq;
368 BZERO(&arpreq, sizeof(arpreq));
371 * Get the hardware address of an interface on the same subnet
372 * as our local address.
374 if (!get_ether_addr(hisaddr, &arpreq.arp_ha)) {
375 syslog(LOG_ERR, "Cannot determine ethernet address for proxy ARP");
379 SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
380 ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
381 arpreq.arp_flags = ATF_PERM | ATF_PUBL;
382 if (ioctl(s, SIOCSARP, (caddr_t)&arpreq) < 0) {
383 syslog(LOG_ERR, "ioctl(SIOCSARP): %m");
391 * cifproxyarp - Delete the proxy ARP entry for the peer.
394 cifproxyarp(unit, hisaddr)
398 struct arpreq arpreq;
400 BZERO(&arpreq, sizeof(arpreq));
401 SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
402 ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
403 if (ioctl(s, SIOCDARP, (caddr_t)&arpreq) < 0) {
404 syslog(LOG_WARNING, "ioctl(SIOCDARP): %m");
411 * get_ether_addr - get the hardware address of an interface on the
412 * the same subnet as ipaddr.
417 get_ether_addr(ipaddr, hwaddr)
419 struct sockaddr *hwaddr;
421 struct ifreq *ifr, *ifend, *ifp;
423 struct sockaddr_dl *dla;
426 struct ifreq ifs[MAX_IFS];
428 ifc.ifc_len = sizeof(ifs);
430 if (ioctl(s, SIOCGIFCONF, &ifc) < 0) {
431 syslog(LOG_ERR, "ioctl(SIOCGIFCONF): %m");
436 * Scan through looking for an interface with an Internet
437 * address on the same subnet as `ipaddr'.
439 ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
440 for (ifr = ifc.ifc_req; ifr < ifend; ) {
441 if (ifr->ifr_addr.sa_family == AF_INET) {
442 ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
443 strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
445 * Check that the interface is up, and not point-to-point
448 if (ioctl(s, SIOCGIFFLAGS, &ifreq) < 0)
450 if ((ifreq.ifr_flags &
451 (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP))
452 != (IFF_UP|IFF_BROADCAST))
455 * Get its netmask and check that it's on the right subnet.
457 if (ioctl(s, SIOCGIFNETMASK, &ifreq) < 0)
459 mask = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
460 if ((ipaddr & mask) != (ina & mask))
465 ifr = (struct ifreq *) ((char *)&ifr->ifr_addr + ifr->ifr_addr.sa_len);
470 syslog(LOG_INFO, "found interface %s for proxy arp", ifr->ifr_name);
473 * Now scan through again looking for a link-level address
474 * for this interface.
477 for (ifr = ifc.ifc_req; ifr < ifend; ) {
478 if (strcmp(ifp->ifr_name, ifr->ifr_name) == 0
479 && ifr->ifr_addr.sa_family == AF_LINK) {
481 * Found the link-level address - copy it out
483 dla = (struct sockaddr_dl *)&ifr->ifr_addr;
484 hwaddr->sa_len = sizeof(struct sockaddr);
485 hwaddr->sa_family = AF_UNSPEC;
486 BCOPY(LLADDR(dla), hwaddr->sa_data, dla->sdl_alen);
489 ifr = (struct ifreq *) ((char *)&ifr->ifr_addr + ifr->ifr_addr.sa_len);
496 * ppp_available - check whether the system has any ppp interfaces
497 * (in fact we check whether we can do an ioctl on ppp0).
506 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
507 return 1; /* can't tell - maybe we're not root */
509 strncpy(ifr.ifr_name, "ppp0", sizeof (ifr.ifr_name));
510 ok = ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) >= 0;
517 * run-program - execute a program with given arguments.
518 * Returns the exit status, or -1 if an error occurred.
519 * If the program can't be executed, logs an error unless
520 * must_exist is 0 and the program file doesn't exist.
524 run_program(prog, args, must_exist)
534 syslog(LOG_ERR, "can't fork to run %s: %m", prog);
539 if (must_exist || errno != ENOENT)
540 syslog(LOG_WARNING, "can't execute %s: %m", prog);
543 if (waitpid(pid, &status, 0) == -1) {
544 syslog(LOG_ERR, "waitpid: %m");
547 if (WIFSIGNALED(status)) {
548 syslog(LOG_INFO, "%s terminated with signal %d", prog,
552 return WEXITSTATUS(status);