summaryrefslogtreecommitdiff
path: root/libexec/pppd/sys-bsd.c
diff options
context:
space:
mode:
authorsvn2git <svn2git@FreeBSD.org>1994-07-01 08:00:00 +0000
committersvn2git <svn2git@FreeBSD.org>1994-07-01 08:00:00 +0000
commit5e0e9b99dc3fc0ecd49d929db0d57c784b66f481 (patch)
treee779b5a6edddbb949b7990751b12d6f25304ba86 /libexec/pppd/sys-bsd.c
parenta16f65c7d117419bd266c28a1901ef129a337569 (diff)
Diffstat (limited to 'libexec/pppd/sys-bsd.c')
-rw-r--r--libexec/pppd/sys-bsd.c503
1 files changed, 503 insertions, 0 deletions
diff --git a/libexec/pppd/sys-bsd.c b/libexec/pppd/sys-bsd.c
new file mode 100644
index 000000000000..314af4447ebf
--- /dev/null
+++ b/libexec/pppd/sys-bsd.c
@@ -0,0 +1,503 @@
+/*
+ * sys-bsd.c - System-dependent procedures for setting up
+ * PPP interfaces on bsd-4.4-ish systems (including 386BSD, NetBSD, etc.)
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: sys-bsd.c,v 1.1 1994/03/30 09:38:18 jkh Exp $";
+#endif
+
+/*
+ * TODO:
+ */
+
+#include <syslog.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/errno.h>
+
+#include <net/if.h>
+#include <net/if_ppp.h>
+#include <net/route.h>
+#include <net/if_dl.h>
+#include <netinet/in.h>
+
+#include "pppd.h"
+#include "ppp.h"
+
+static int initdisc; /* Initial TTY discipline */
+
+
+/*
+ * establish_ppp - Turn the serial port into a ppp interface.
+ */
+void
+establish_ppp()
+{
+ int pppdisc = PPPDISC;
+
+ if (ioctl(fd, TIOCGETD, &initdisc) < 0) {
+ syslog(LOG_ERR, "ioctl(TIOCGETD): %m");
+ die(1);
+ }
+ if (ioctl(fd, TIOCSETD, &pppdisc) < 0) {
+ syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
+ die(1);
+ }
+
+ /*
+ * Find out which interface we were given.
+ */
+ if (ioctl(fd, PPPIOCGUNIT, &ifunit) < 0) {
+ syslog(LOG_ERR, "ioctl(PPPIOCGUNIT): %m");
+ die(1);
+ }
+}
+
+
+/*
+ * disestablish_ppp - Restore the serial port to normal operation.
+ * This shouldn't call die() because it's called from die().
+ */
+void
+disestablish_ppp()
+{
+ if (ioctl(fd, TIOCSETD, &initdisc) < 0)
+ syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
+}
+
+
+/*
+ * output - Output PPP packet.
+ */
+void
+output(unit, p, len)
+ int unit;
+ u_char *p;
+ int len;
+{
+ if (unit != 0)
+ MAINDEBUG((LOG_WARNING, "output: unit != 0!"));
+
+ if (write(fd, p, len) < 0) {
+ syslog(LOG_ERR, "write: %m");
+ die(1);
+ }
+}
+
+
+/*
+ * read_packet - get a PPP packet from the serial device.
+ */
+int
+read_packet(buf)
+ u_char *buf;
+{
+ int len;
+
+ if ((len = read(fd, buf, MTU + DLLHEADERLEN)) < 0) {
+ if (errno == EWOULDBLOCK) {
+ MAINDEBUG((LOG_DEBUG, "read(fd): EWOULDBLOCK"));
+ return -1;
+ }
+ syslog(LOG_ERR, "read(fd): %m");
+ die(1);
+ }
+ return len;
+}
+
+
+/*
+ * ppp_send_config - configure the transmit characteristics of
+ * the ppp interface.
+ */
+void
+ppp_send_config(unit, mtu, asyncmap, pcomp, accomp)
+ int unit, mtu;
+ u_long asyncmap;
+ int pcomp, accomp;
+{
+ u_int x;
+ struct ifreq ifr;
+
+ strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ ifr.ifr_mtu = mtu;
+ if (ioctl(s, SIOCSIFMTU, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFMTU): %m");
+ quit();
+ }
+
+ if (ioctl(fd, PPPIOCSASYNCMAP, (caddr_t) &asyncmap) < 0) {
+ syslog(LOG_ERR, "ioctl(PPPIOCSASYNCMAP): %m");
+ quit();
+ }
+
+ if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
+ syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
+ quit();
+ }
+ x = pcomp? x | SC_COMP_PROT: x &~ SC_COMP_PROT;
+ x = accomp? x | SC_COMP_AC: x &~ SC_COMP_AC;
+ if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
+ syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
+ quit();
+ }
+}
+
+/*
+ * ppp_recv_config - configure the receive-side characteristics of
+ * the ppp interface. At present this does nothing.
+ */
+void
+ppp_recv_config(unit, mru, asyncmap, pcomp, accomp)
+ int unit, mru;
+ u_long asyncmap;
+ int pcomp, accomp;
+{
+#ifdef notyet
+ if (ioctl(fd, PPPIOCSRASYNCMAP, (caddr_t) &asyncmap) < 0) {
+ syslog(LOG_ERR, "ioctl(PPPIOCSRASYNCMAP): %m");
+ quit();
+ }
+
+ if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
+ syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
+ quit();
+ }
+ x = !accomp? x | SC_REJ_COMP_AC: x &~ SC_REJ_COMP_AC;
+ if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
+ syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
+ quit();
+ }
+#endif /* notyet */
+}
+
+/*
+ * sifvjcomp - config tcp header compression
+ */
+int
+sifvjcomp(u, vjcomp, cidcomp)
+{
+ u_int x;
+
+ if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
+ syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
+ return 0;
+ }
+ x = vjcomp ? x | SC_COMP_TCP: x &~ SC_COMP_TCP;
+ x = cidcomp? x & ~SC_NO_TCP_CCID: x | SC_NO_TCP_CCID;
+ if(ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
+ syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * sifup - Config the interface up.
+ */
+int
+sifup(u)
+{
+ struct ifreq ifr;
+ strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
+ return 0;
+ }
+ ifr.ifr_flags |= IFF_UP;
+ if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * sifdown - Config the interface down.
+ */
+int
+sifdown(u)
+{
+ struct ifreq ifr;
+ strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
+ return 0;
+ }
+ ifr.ifr_flags &= ~IFF_UP;
+ if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * SET_SA_FAMILY - set the sa_family field of a struct sockaddr,
+ * if it exists.
+ */
+#define SET_SA_FAMILY(addr, family) \
+ BZERO((char *) &(addr), sizeof(addr)); \
+ addr.sa_family = (family); \
+ addr.sa_len = sizeof(addr);
+
+/*
+ * sifaddr - Config the interface IP addresses and netmask.
+ */
+int
+sifaddr(u, o, h, m)
+{
+ struct ifaliasreq ifra;
+
+ strncpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name));
+ SET_SA_FAMILY(ifra.ifra_addr, AF_INET);
+ ((struct sockaddr_in *) &ifra.ifra_addr)->sin_addr.s_addr = o;
+ SET_SA_FAMILY(ifra.ifra_broadaddr, AF_INET);
+ ((struct sockaddr_in *) &ifra.ifra_broadaddr)->sin_addr.s_addr = h;
+ if (m != 0) {
+ SET_SA_FAMILY(ifra.ifra_mask, AF_INET);
+ ((struct sockaddr_in *) &ifra.ifra_mask)->sin_addr.s_addr = m;
+ } else
+ BZERO(&ifra.ifra_mask, sizeof(ifra.ifra_mask));
+ if (ioctl(s, SIOCAIFADDR, (caddr_t) &ifra) < 0) {
+ if (errno != EEXIST) {
+ syslog(LOG_ERR, "ioctl(SIOCAIFADDR): %m");
+ return 0;
+ }
+ syslog(LOG_WARNING, "ioctl(SIOCAIFADDR): Address already exists");
+ }
+ return 1;
+}
+
+/*
+ * cifaddr - Clear the interface IP addresses, and delete routes
+ * through the interface if possible.
+ */
+int
+cifaddr(u, o, h)
+{
+ struct ifaliasreq ifra;
+
+ strncpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name));
+ SET_SA_FAMILY(ifra.ifra_addr, AF_INET);
+ ((struct sockaddr_in *) &ifra.ifra_addr)->sin_addr.s_addr = o;
+ SET_SA_FAMILY(ifra.ifra_broadaddr, AF_INET);
+ ((struct sockaddr_in *) &ifra.ifra_broadaddr)->sin_addr.s_addr = h;
+ BZERO(&ifra.ifra_mask, sizeof(ifra.ifra_mask));
+ if (ioctl(s, SIOCDIFADDR, (caddr_t) &ifra) < 0) {
+ syslog(LOG_WARNING, "ioctl(SIOCDIFADDR): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * sifdefaultroute - assign a default route through the address given.
+ */
+int
+sifdefaultroute(u, g)
+{
+ struct ortentry rt;
+
+ SET_SA_FAMILY(rt.rt_dst, AF_INET);
+ SET_SA_FAMILY(rt.rt_gateway, AF_INET);
+ ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = g;
+ rt.rt_flags = RTF_GATEWAY;
+ if (ioctl(s, SIOCADDRT, &rt) < 0) {
+ syslog(LOG_ERR, "default route ioctl(SIOCADDRT): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * cifdefaultroute - delete a default route through the address given.
+ */
+int
+cifdefaultroute(u, g)
+{
+ struct ortentry rt;
+
+ SET_SA_FAMILY(rt.rt_dst, AF_INET);
+ SET_SA_FAMILY(rt.rt_gateway, AF_INET);
+ ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = g;
+ rt.rt_flags = RTF_GATEWAY;
+ if (ioctl(s, SIOCDELRT, &rt) < 0)
+ syslog(LOG_WARNING, "default route ioctl(SIOCDELRT): %m");
+}
+
+/*
+ * sifproxyarp - Make a proxy ARP entry for the peer.
+ */
+int
+sifproxyarp(unit, hisaddr)
+ int unit;
+ u_long hisaddr;
+{
+ struct arpreq arpreq;
+
+ BZERO(&arpreq, sizeof(arpreq));
+
+ /*
+ * Get the hardware address of an interface on the same subnet
+ * as our local address.
+ */
+ if (!get_ether_addr(hisaddr, &arpreq.arp_ha)) {
+ syslog(LOG_ERR, "Cannot determine ethernet address for proxy ARP");
+ return 0;
+ }
+
+ SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
+ ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
+ arpreq.arp_flags = ATF_PERM | ATF_PUBL;
+ if (ioctl(s, SIOCSARP, (caddr_t)&arpreq) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSARP): %m");
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * cifproxyarp - Delete the proxy ARP entry for the peer.
+ */
+int
+cifproxyarp(unit, hisaddr)
+ int unit;
+ u_long hisaddr;
+{
+ struct arpreq arpreq;
+
+ BZERO(&arpreq, sizeof(arpreq));
+ SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
+ ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
+ if (ioctl(s, SIOCDARP, (caddr_t)&arpreq) < 0) {
+ syslog(LOG_WARNING, "ioctl(SIOCDARP): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * get_ether_addr - get the hardware address of an interface on the
+ * the same subnet as ipaddr.
+ */
+#define MAX_IFS 32
+
+int
+get_ether_addr(ipaddr, hwaddr)
+ u_long ipaddr;
+ struct sockaddr *hwaddr;
+{
+ struct ifreq *ifr, *ifend, *ifp;
+ u_long ina, mask;
+ struct sockaddr_dl *dla;
+ struct ifreq ifreq;
+ struct ifconf ifc;
+ struct ifreq ifs[MAX_IFS];
+
+ ifc.ifc_len = sizeof(ifs);
+ ifc.ifc_req = ifs;
+ if (ioctl(s, SIOCGIFCONF, &ifc) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCGIFCONF): %m");
+ return 0;
+ }
+
+ /*
+ * Scan through looking for an interface with an Internet
+ * address on the same subnet as `ipaddr'.
+ */
+ ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
+ for (ifr = ifc.ifc_req; ifr < ifend; ) {
+ if (ifr->ifr_addr.sa_family == AF_INET) {
+ ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
+ strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
+ /*
+ * Check that the interface is up, and not point-to-point
+ * or loopback.
+ */
+ if (ioctl(s, SIOCGIFFLAGS, &ifreq) < 0)
+ continue;
+ if ((ifreq.ifr_flags &
+ (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP))
+ != (IFF_UP|IFF_BROADCAST))
+ continue;
+ /*
+ * Get its netmask and check that it's on the right subnet.
+ */
+ if (ioctl(s, SIOCGIFNETMASK, &ifreq) < 0)
+ continue;
+ mask = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
+ if ((ipaddr & mask) != (ina & mask))
+ continue;
+
+ break;
+ }
+ ifr = (struct ifreq *) ((char *)&ifr->ifr_addr + ifr->ifr_addr.sa_len);
+ }
+
+ if (ifr >= ifend)
+ return 0;
+ syslog(LOG_INFO, "found interface %s for proxy arp", ifr->ifr_name);
+
+ /*
+ * Now scan through again looking for a link-level address
+ * for this interface.
+ */
+ ifp = ifr;
+ for (ifr = ifc.ifc_req; ifr < ifend; ) {
+ if (strcmp(ifp->ifr_name, ifr->ifr_name) == 0
+ && ifr->ifr_addr.sa_family == AF_LINK) {
+ /*
+ * Found the link-level address - copy it out
+ */
+ dla = (struct sockaddr_dl *)&ifr->ifr_addr;
+ hwaddr->sa_len = sizeof(struct sockaddr);
+ hwaddr->sa_family = AF_UNSPEC;
+ BCOPY(LLADDR(dla), hwaddr->sa_data, dla->sdl_alen);
+ return 1;
+ }
+ ifr = (struct ifreq *) ((char *)&ifr->ifr_addr + ifr->ifr_addr.sa_len);
+ }
+
+ return 0;
+}
+
+/*
+ * ppp_available - check whether the system has any ppp interfaces
+ * (in fact we check whether we can do an ioctl on ppp0).
+ */
+
+int
+ppp_available()
+{
+ int s, ok;
+ struct ifreq ifr;
+
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ return 1; /* can't tell - maybe we're not root */
+
+ strncpy(ifr.ifr_name, "ppp0", sizeof (ifr.ifr_name));
+ ok = ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) >= 0;
+ close(s);
+
+ return ok;
+}