]> git.ozlabs.org Git - ppp.git/blobdiff - pppd/sys-svr4.c
add packet filtering support; set netmask before interface addr
[ppp.git] / pppd / sys-svr4.c
index 4e4006d0af095fdd7529be8d2c07b472227851d3..d5c83b3b47c6e244728d7ddf1dad3c0ab2ae729c 100644 (file)
@@ -26,7 +26,7 @@
  */
 
 #ifndef lint
-static char rcsid[] = "$Id: sys-svr4.c,v 1.7 1995/10/27 03:52:56 paulus Exp $";
+static char rcsid[] = "$Id: sys-svr4.c,v 1.10 1996/04/04 04:07:30 paulus Exp $";
 #endif
 
 #include <limits.h>
@@ -78,6 +78,8 @@ static struct termiox inittermiox;
 static struct winsize wsinfo;  /* Initial window size info */
 static pid_t   tty_sid;        /* original session ID for terminal */
 
+extern u_char  inpacket_buf[]; /* borrowed from main.c */
+
 static int     link_mtu, link_mru;
 
 #define NMODULES       32
@@ -104,6 +106,15 @@ static int strioctl __P((int, int, void *, int, int));
 void
 sys_init()
 {
+    int ifd, x;
+#ifndef sun
+    struct ifreq ifr;
+    struct {
+       union DL_primitives prim;
+       char space[64];
+    } reply;
+#endif
+
     openlog("pppd", LOG_PID | LOG_NDELAY, LOG_PPP);
     setlogmask(LOG_UPTO(LOG_INFO));
     if (debug)
@@ -114,6 +125,70 @@ sys_init()
        syslog(LOG_ERR, "Couldn't open IP device: %m");
        die(1);
     }
+
+    if (default_device)
+       tty_sid = getsid((pid_t)0);
+
+    pppfd = open("/dev/ppp", O_RDWR | O_NONBLOCK, 0);
+    if (pppfd < 0) {
+       syslog(LOG_ERR, "Can't open /dev/ppp: %m");
+       die(1);
+    }
+    if (kdebugflag) {
+       x = PPPDBG_LOG + PPPDBG_DRIVER;
+       strioctl(pppfd, PPPIO_DEBUG, &x, sizeof(int), 0);
+    }
+
+    /* Assign a new PPA and get its unit number. */
+    if (strioctl(pppfd, PPPIO_NEWPPA, &ifunit, 0, sizeof(int)) < 0) {
+       syslog(LOG_ERR, "Can't create new PPP interface: %m");
+       die(1);
+    }
+
+    /*
+     * Open the ppp device again and link it under the ip multiplexor.
+     * IP will assign a unit number which hopefully is the same as ifunit.
+     * I don't know any way to be certain they will be the same. :-(
+     */
+    ifd = open("/dev/ppp", O_RDWR, 0);
+    if (ifd < 0) {
+       syslog(LOG_ERR, "Can't open /dev/ppp (2): %m");
+       die(1);
+    }
+    if (kdebugflag) {
+       x = PPPDBG_LOG + PPPDBG_DRIVER;
+       strioctl(ifd, PPPIO_DEBUG, &x, sizeof(int), 0);
+    }
+#ifdef sun
+    if (ioctl(ifd, I_PUSH, "ip") < 0) {
+       syslog(LOG_ERR, "Can't push IP module: %m");
+       close(ifd);
+       die(1);
+    }
+#else
+    if (dlpi_attach(ifd, ifunit) < 0 ||
+       dlpi_get_reply(ifd, &reply.prim, DL_OK_ACK, sizeof(reply)) < 0) {
+       syslog(LOG_ERR, "Can't attach to ppp%d: %m", ifunit);
+       close(ifd);
+       die(1);
+    }
+#endif
+    ipmuxid = ioctl(ipfd, I_LINK, ifd);
+    close(ifd);
+    if (ipmuxid < 0) {
+       syslog(LOG_ERR, "Can't link PPP device to IP: %m");
+       die(1);
+    }
+
+#ifndef sun
+    /* Set the interface name for the link. */
+    (void) sprintf (ifr.ifr_name, "ppp%d", ifunit);
+    ifr.ifr_metric = ipmuxid;
+    if (strioctl(ipfd, SIOCSIFNAME, (char *)&ifr, sizeof ifr, 0) < 0) {
+       syslog(LOG_ERR, "Can't set interface name %s: %m", ifr.ifr_name);
+       die(1);
+    }
+#endif
 }
 
 /*
@@ -134,6 +209,27 @@ sys_cleanup()
        cifproxyarp(0, proxy_arp_addr);
 }
 
+/*
+ * sys_close - Clean up in a child process before execing.
+ */
+void
+sys_close()
+{
+    close(ipfd);
+    if (pppfd >= 0)
+       close(pppfd);
+    closelog();
+}
+
+/*
+ * sys_check_options - check the options that the user specified
+ */
+void
+sys_check_options()
+{
+}
+
+
 /*
  * daemon - Detach us from controlling terminal session.
  */
@@ -165,7 +261,6 @@ void
 note_debug_level()
 {
     if (debug) {
-       syslog(LOG_INFO, "Debug turned ON, Level %d", debug);
        setlogmask(LOG_UPTO(LOG_DEBUG));
     } else {
        setlogmask(LOG_UPTO(LOG_WARNING));
@@ -187,80 +282,10 @@ ppp_available()
  * establish_ppp - Turn the serial port into a ppp interface.
  */
 void
-establish_ppp()
+establish_ppp(fd)
+    int fd;
 {
-    int i, ifd, x;
-#ifndef sun
-    struct ifreq ifr;
-    struct {
-       union DL_primitives prim;
-       char space[64];
-    } reply;
-#endif
-
-    if (default_device)
-       tty_sid = getsid((pid_t)0);
-
-    pppfd = open("/dev/ppp", O_RDWR | O_NONBLOCK, 0);
-    if (pppfd < 0) {
-       syslog(LOG_ERR, "Can't open /dev/ppp: %m");
-       die(1);
-    }
-    if (kdebugflag) {
-       x = PPPDBG_LOG + PPPDBG_DRIVER;
-       strioctl(pppfd, PPPIO_DEBUG, &x, sizeof(int), 0);
-    }
-
-    /* Assign a new PPA and get its unit number. */
-    if (strioctl(pppfd, PPPIO_NEWPPA, &ifunit, 0, sizeof(int)) < 0) {
-       syslog(LOG_ERR, "Can't create new PPP interface: %m");
-       die(1);
-    }
-
-    /*
-     * Open the ppp device again and link it under the ip multiplexor.
-     * IP will assign a unit number which hopefully is the same as ifunit.
-     * I don't know any way to be certain they will be the same. :-(
-     */
-    ifd = open("/dev/ppp", O_RDWR, 0);
-    if (ifd < 0) {
-       syslog(LOG_ERR, "Can't open /dev/ppp (2): %m");
-       die(1);
-    }
-    if (kdebugflag) {
-       x = PPPDBG_LOG + PPPDBG_DRIVER;
-       strioctl(ifd, PPPIO_DEBUG, &x, sizeof(int), 0);
-    }
-#ifdef sun
-    if (ioctl(ifd, I_PUSH, "ip") < 0) {
-       syslog(LOG_ERR, "Can't push IP module: %m");
-       close(ifd);
-       die(1);
-    }
-#else
-    if (dlpi_attach(ifd, ifunit) < 0 ||
-       dlpi_get_reply(ifd, &reply.prim, DL_OK_ACK, sizeof(reply)) < 0) {
-       syslog(LOG_ERR, "Can't attach to ppp%d: %m", ifunit);
-       close(ifd);
-       die(1);
-    }
-#endif
-    ipmuxid = ioctl(ipfd, I_LINK, ifd);
-    close(ifd);
-    if (ipmuxid < 0) {
-       syslog(LOG_ERR, "Can't link PPP device to IP: %m");
-       die(1);
-    }
-
-#ifndef sun
-    /* Set the interface name for the link. */
-    (void) sprintf (ifr.ifr_name, "ppp%d", ifunit);
-    ifr.ifr_metric = ipmuxid;
-    if (strioctl(ipfd, SIOCSIFNAME, (char *)&ifr, sizeof ifr, 0) < 0) {
-       syslog(LOG_ERR, "Can't set interface name %s: %m", ifr.ifr_name);
-       die(1);
-    }
-#endif
+    int i;
 
     /* Pop any existing modules off the tty stream. */
     for (i = 0;; ++i)
@@ -286,22 +311,26 @@ establish_ppp()
     }
 }
 
+/*
+ * restore_loop - reattach the ppp unit to the loopback.
+ * This doesn't need to do anything because disestablish_ppp does it.
+ */
+void
+restore_loop()
+{
+}
+
 /*
  * disestablish_ppp - Restore the serial port to normal operation.
- * This shouldn't call die() because it's called from die().
+ * It attempts to reconstruct the stream with the previously popped
+ * modules.  This shouldn't call die() because it's called from die().
  */
 void
-disestablish_ppp()
+disestablish_ppp(fd)
+    int fd;
 {
     int i;
 
-    if (ipmuxid > 0) {
-        if (ioctl(ipfd, I_UNLINK, ipmuxid) < 0) {
-           if (!hungup)
-               syslog(LOG_ERR, "Can't unlink PPP from IP: %m");
-        }
-    }
-
     if (fdmuxid >= 0) {
        if (ioctl(pppfd, I_UNLINK, fdmuxid) < 0) {
            if (!hungup)
@@ -330,6 +359,38 @@ disestablish_ppp()
     }
 }
 
+/*
+ * Check whether the link seems not to be 8-bit clean.
+ */
+void
+clean_check()
+{
+    int x;
+    char *s;
+
+    if (strioctl(pppfd, PPPIO_GCLEAN, &x, 0, sizeof(x)) < 0)
+       return;
+    s = NULL;
+    switch (~x) {
+    case RCV_B7_0:
+       s = "bit 7 set to 1";
+       break;
+    case RCV_B7_1:
+       s = "bit 7 set to 0";
+       break;
+    case RCV_EVNP:
+       s = "odd parity";
+       break;
+    case RCV_ODDP:
+       s = "even parity";
+       break;
+    }
+    if (s != NULL) {
+       syslog(LOG_WARNING, "Serial link is not 8-bit clean:");
+       syslog(LOG_WARNING, "All received characters had %s", s);
+    }
+}
+
 /*
  * List of valid speeds.
  */
@@ -542,7 +603,8 @@ set_up_tty(fd, local)
  * restore_tty - restore the terminal to the saved settings.
  */
 void
-restore_tty()
+restore_tty(fd)
+    int fd;
 {
     if (restore_term) {
        if (!default_device) {
@@ -581,6 +643,16 @@ int fd, on;
     ioctl(fd, (on? TIOCMBIS: TIOCMBIC), &modembits);
 }
 
+/*
+ * open_loopback - open the device we use for getting packets
+ * in demand mode.  Under Solaris 2, we use our existing fd
+ * to the ppp driver.
+ */
+void
+open_ppp_loopback()
+{
+}
+
 /*
  * output - Output PPP packet.
  */
@@ -606,12 +678,13 @@ output(unit, p, len)
                syslog(LOG_ERR, "Couldn't send packet: %m");
            break;
        }
-       pfd.fd = fd;
+       pfd.fd = pppfd;
        pfd.events = POLLOUT;
        poll(&pfd, 1, 250);     /* wait for up to 0.25 seconds */
     }
 }
 
+
 /*
  * wait_input - wait until there is data available on fd,
  * for the length of time specified by *timo (indefinite
@@ -633,6 +706,36 @@ wait_input(timo)
     }
 }
 
+/*
+ * wait_loop_output - wait until there is data available on the
+ * loopback, for the length of time specified by *timo (indefinite
+ * if timo is NULL).
+ */
+void
+wait_loop_output(timo)
+    struct timeval *timo;
+{
+    wait_input(timo);
+}
+
+/*
+ * wait_time - wait for a given length of time or until a
+ * signal is received.
+ */
+void
+wait_time(timo)
+    struct timeval *timo;
+{
+    int n;
+
+    n = select(0, NULL, NULL, NULL, timo);
+    if (n < 0 && errno != EINTR) {
+       syslog(LOG_ERR, "select: %m");
+       die(1);
+    }
+}
+
+
 /*
  * read_packet - get a PPP packet from the serial device.
  */
@@ -663,7 +766,7 @@ read_packet(buf)
 
        /*
         * Got a M_PROTO or M_PCPROTO message.  Interpret it
-        * as a DLPI primitive.
+        * as a DLPI primitive??
         */
        if (debug)
            syslog(LOG_DEBUG, "got dlpi prim 0x%x, len=%d",
@@ -672,6 +775,24 @@ read_packet(buf)
     }
 }
 
+/*
+ * get_loop_output - get outgoing packets from the ppp device,
+ * and detect when we want to bring the real link up.
+ * Return value is 1 if we need to bring up the link, 0 otherwise.
+ */
+int
+get_loop_output()
+{
+    int len;
+    int rv = 0;
+
+    while ((len = read_packet(inpacket_buf)) > 0) {
+       if (loop_frame(inpacket_buf, len))
+           rv = 1;
+    }
+    return rv;
+}
+
 /*
  * ppp_send_config - configure the transmit characteristics of
  * the ppp interface.
@@ -774,6 +895,45 @@ ccp_flags_set(unit, isopen, isup)
     }
 }
 
+/*
+ * get_idle_time - return how long the link has been idle.
+ */
+int
+get_idle_time(u, ip)
+    int u;
+    struct ppp_idle *ip;
+{
+    return strioctl(pppfd, PPPIO_GIDLE, ip, 0, sizeof(struct ppp_idle)) >= 0;
+}
+
+
+/*
+ * set_filters - transfer the pass and active filters to the kernel.
+ */
+int
+set_filters(pass, active)
+    struct bpf_program *pass, *active;
+{
+    int ret = 1;
+
+    if (pass->bf_len > 0) {
+       if (strioctl(pppfd, PPPIO_PASSFILT, pass,
+                    sizeof(struct bpf_program), 0) < 0) {
+           syslog(LOG_ERR, "Couldn't set pass-filter in kernel: %m");
+           ret = 0;
+       }
+    }
+    if (active->bf_len > 0) {
+       if (strioctl(pppfd, PPPIO_ACTIVEFILT, active,
+                    sizeof(struct bpf_program), 0) < 0) {
+           syslog(LOG_ERR, "Couldn't set active-filter in kernel: %m");
+           ret = 0;
+       }
+    }
+    return ret;
+}
+
+
 /*
  * ccp_fatal_error - returns 1 if decompression was disabled as a
  * result of an error detected after decompression of a packet,
@@ -871,6 +1031,26 @@ sifdown(u)
     return 1;
 }
 
+/*
+ * sifnpmode - Set the mode for handling packets for a given NP.
+ */
+int
+sifnpmode(u, proto, mode)
+    int u;
+    int proto;
+    enum NPmode mode;
+{
+    int npi[2];
+
+    npi[0] = proto;
+    npi[1] = (int) mode;
+    if (strioctl(pppfd, PPPIO_NPMODE, &npi, 2 * sizeof(int), 0) < 0) {
+       syslog(LOG_ERR, "ioctl(set NP %d mode to %d): %m", proto, mode);
+       return 0;
+    }
+    return 1;
+}
+
 #define INET_ADDR(x)   (((struct sockaddr_in *) &(x))->sin_addr.s_addr)
 
 /*
@@ -886,6 +1066,11 @@ sifaddr(u, o, h, m)
     memset(&ifr, 0, sizeof(ifr));
     strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
     ifr.ifr_addr.sa_family = AF_INET;
+    INET_ADDR(ifr.ifr_addr) = m;
+    if (ioctl(ipfd, SIOCSIFNETMASK, &ifr) < 0) {
+       syslog(LOG_ERR, "Couldn't set IP netmask: %m");
+    }
+    ifr.ifr_addr.sa_family = AF_INET;
     INET_ADDR(ifr.ifr_addr) = o;
     if (ioctl(ipfd, SIOCSIFADDR, &ifr) < 0) {
        syslog(LOG_ERR, "Couldn't set local IP address: %m");
@@ -895,11 +1080,6 @@ sifaddr(u, o, h, m)
     if (ioctl(ipfd, SIOCSIFDSTADDR, &ifr) < 0) {
        syslog(LOG_ERR, "Couldn't set remote IP address: %m");
     }
-    ifr.ifr_addr.sa_family = AF_INET;
-    INET_ADDR(ifr.ifr_addr) = m;
-    if (ioctl(ipfd, SIOCSIFNETMASK, &ifr) < 0) {
-       syslog(LOG_ERR, "Couldn't set IP netmask: %m");
-    }
     ifr.ifr_metric = link_mtu;
     if (ioctl(ipfd, SIOCSIFMTU, &ifr) < 0) {
        syslog(LOG_ERR, "Couldn't set IP MTU: %m");
@@ -939,6 +1119,7 @@ sifdefaultroute(u, g)
 {
     struct rtentry rt;
 
+    memset(&rt, 0, sizeof(rt));
     rt.rt_dst.sa_family = AF_INET;
     INET_ADDR(rt.rt_dst) = 0;
     rt.rt_gateway.sa_family = AF_INET;
@@ -964,6 +1145,7 @@ cifdefaultroute(u, g)
 {
     struct rtentry rt;
 
+    memset(&rt, 0, sizeof(rt));
     rt.rt_dst.sa_family = AF_INET;
     INET_ADDR(rt.rt_dst) = 0;
     rt.rt_gateway.sa_family = AF_INET;
@@ -1143,10 +1325,12 @@ get_hw_addr(name, hwaddr)
 
     adrlen = reply.prim.info_ack.dl_addr_length;
     adrp = (unsigned char *)&reply + reply.prim.info_ack.dl_addr_offset;
+#if DL_CURRENT_VERSION >= 2
     if (reply.prim.info_ack.dl_sap_length < 0)
        adrlen += reply.prim.info_ack.dl_sap_length;
     else
        adrp += reply.prim.info_ack.dl_sap_length;
+#endif
     hwaddr->sa_family = AF_UNSPEC;
     memcpy(hwaddr->sa_data, adrp, adrlen);