kernel - Fixes for usb modems
authorMatthew Dillon <dillon@apollo.backplane.com>
Sat, 14 Nov 2015 01:39:46 +0000 (17:39 -0800)
committerMatthew Dillon <dillon@apollo.backplane.com>
Sat, 14 Nov 2015 01:39:46 +0000 (17:39 -0800)
* Separate t_sc into t_sc and t_slsc to allow line disciplines to
  coexsist with USB serial.  This allows SLIP to work.  Please don't
  ask me why I still need to use SLIP.

* Fix several panics in usb_serial.c.  Missing initializations,
  deadlocks due to locks held during blocking operations,
  missing unlocks, etc.

* Fix improper signed-char promotion to int causing high-bits to be
  set in calls to linesw[].l_rint(), which prevented SLIP from recognizing
  packets.

* Allow flags to be adjusted for SLIPs sl%d interfaces, in particular
  allow them to be setup as broadcast interfaces instead of point-to-point
  interfaces if desired.  Settable via /boot/loader.conf.

* Still TODO: Bugs present related to detection of modem control bits.

sys/bus/u4b/serial/usb_serial.c
sys/net/ppp_layer/ppp_tty.c
sys/net/sl/if_sl.c
sys/sys/tty.h

index dd3b5db..ec1d730 100644 (file)
@@ -498,6 +498,10 @@ ucom_attach_tty(struct ucom_super_softc *ssc, struct ucom_softc *sc)
        sc->sc_cdev_init->si_drv1 = sc;
        sc->sc_cdev_lock->si_drv1 = sc;
 
+       sc->sc_cdev2->si_tty = tp;
+       sc->sc_cdev2_init->si_tty = tp;
+       sc->sc_cdev2_lock->si_tty = tp;
+
        sc->sc_cdev2->si_drv1 = sc;
        sc->sc_cdev2_init->si_drv1 = sc;
        sc->sc_cdev2_lock->si_drv1 = sc;
@@ -789,11 +793,10 @@ ucom_dev_open(struct dev_open_args *ap)
        error = 0;
        mynor = minor(dev);
 
-       if (!(mynor & CALLOUT_MASK)) {
-               UCOM_MTX_LOCK(sc);
-               error = ucom_open(sc);
-               UCOM_MTX_UNLOCK(sc);
-       }
+       UCOM_MTX_LOCK(sc);
+       error = ucom_open(sc);
+       UCOM_MTX_UNLOCK(sc);
+
        return error;   
 }
 
@@ -1049,9 +1052,10 @@ ucom_dev_read(struct dev_read_args *ap)
 
         DPRINTF("tp = %p, flag = 0x%x\n", tp, ap->a_ioflag);
 
-       UCOM_MTX_LOCK(sc);
+       /* must not be locked in case it blocks */
+       /*UCOM_MTX_LOCK(sc);*/
         error = (*linesw[tp->t_line].l_read)(tp, ap->a_uio, ap->a_ioflag);
-       UCOM_MTX_UNLOCK(sc);
+       /*UCOM_MTX_UNLOCK(sc);*/
 
         DPRINTF("error = %d\n", error);
 
@@ -1075,9 +1079,10 @@ ucom_dev_write(struct dev_write_args *ap)
 
         DPRINTF("tp = %p, flag = 0x%x\n", tp, ap->a_ioflag);
 
-       UCOM_MTX_LOCK(sc);
+       /* must not be locked in case it blocks */
+       /*UCOM_MTX_LOCK(sc);*/
         error = (*linesw[tp->t_line].l_write)(tp, ap->a_uio, ap->a_ioflag);
-       UCOM_MTX_UNLOCK(sc);
+       /*UCOM_MTX_UNLOCK(sc);*/
 
         DPRINTF("ucomwrite: error = %d\n", error);
 
@@ -1104,6 +1109,7 @@ ucom_dev_ioctl(struct dev_ioctl_args *ap)
 
        if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
                lwkt_reltoken(&tty_token);
+               UCOM_MTX_UNLOCK(sc);
                return (EIO);
        }
        DPRINTF("cmd = 0x%08lx\n", cmd);
@@ -1119,6 +1125,7 @@ ucom_dev_ioctl(struct dev_ioctl_args *ap)
                         break;
                 default:
                         lwkt_reltoken(&tty_token);
+                       UCOM_MTX_UNLOCK(sc);
                         return (ENODEV);        /* /dev/nodev */
                 }
                 switch (ap->a_cmd) {
@@ -1126,25 +1133,31 @@ ucom_dev_ioctl(struct dev_ioctl_args *ap)
                         error = priv_check_cred(ap->a_cred, PRIV_ROOT, 0);
                         if (error != 0) {
                                 lwkt_reltoken(&tty_token);
+                               UCOM_MTX_UNLOCK(sc);
                                 return (error);
                         }
                         *ct = *(struct termios *)data;
                         lwkt_reltoken(&tty_token);
+                       UCOM_MTX_UNLOCK(sc);
                         return (0);
                 case TIOCGETA:
                         *(struct termios *)data = *ct;
                         lwkt_reltoken(&tty_token);
+                       UCOM_MTX_UNLOCK(sc);
                         return (0);
                 case TIOCGETD:
                         *(int *)data = TTYDISC;
                         lwkt_reltoken(&tty_token);
+                       UCOM_MTX_UNLOCK(sc);
                         return (0);
                 case TIOCGWINSZ:
                         bzero(data, sizeof(struct winsize));
                         lwkt_reltoken(&tty_token);
+                       UCOM_MTX_UNLOCK(sc);
                         return (0);
                 default:
                         lwkt_reltoken(&tty_token);
+                       UCOM_MTX_UNLOCK(sc);
                         return (ENOTTY);
                 }
        }
@@ -1208,6 +1221,7 @@ ucom_dev_ioctl(struct dev_ioctl_args *ap)
                d = ucom_modem(tp, 0, 0);
                DPRINTF("ucomioctl: TIOCMGET, 0x%x\n", d);
                *(int *)ap->a_data = ucom_totio(d);
+               ucom_status_change(sc);
                break;
        case TIOCMBIS:
                d = *(int *)ap->a_data;
@@ -1719,13 +1733,23 @@ static void
 ucom_start(struct tty *tp)
 {
        struct ucom_softc *sc = (struct ucom_softc *)tp->t_sc;
+       int didlock;
 
-       UCOM_MTX_ASSERT(sc, MA_OWNED);
+       /* may be called locked or unlocked */
+       if (lockowned(sc->sc_lock)) {
+               didlock = 0;
+       } else {
+               UCOM_MTX_LOCK(sc);
+               didlock = 1;
+       }
+       /* UCOM_MTX_ASSERT(sc, MA_OWNED); */
 
        DPRINTF("sc = %p\n", sc);
 
        if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) {
                /* The higher layer is not ready */
+               if (didlock)
+                       UCOM_MTX_UNLOCK(sc);
                return;
        }
 
@@ -1777,6 +1801,8 @@ ucom_start(struct tty *tp)
 out:
        crit_exit();
        lwkt_reltoken(&tty_token);
+       if (didlock)
+               UCOM_MTX_UNLOCK(sc);
 }
 
 static void
@@ -2052,7 +2078,7 @@ ucom_put_data(struct ucom_softc *sc, struct usb_page_cache *pc,
                /* need to loop */
                        for (cnt = 0; cnt != res.length; cnt++) {
                                if (sc->sc_jitterbuf_in != sc->sc_jitterbuf_out ||
-                                   (*linesw[tp->t_line].l_rint)(buf[cnt], tp) == -1) {
+                                   (*linesw[tp->t_line].l_rint)((unsigned char)buf[cnt], tp) == -1) {
                                        uint16_t end;
                                        uint16_t pos;
 
index 3a5f87c..9ae1855 100644 (file)
@@ -186,7 +186,7 @@ pppopen(cdev_t dev, struct tty *tp)
     lwkt_gettoken(&tty_token);
 
     if (tp->t_line == PPPDISC) {
-       sc = (struct ppp_softc *) tp->t_sc;
+       sc = (struct ppp_softc *) tp->t_slsc;
        if (sc != NULL && sc->sc_devp == (void *) tp) {
            lwkt_reltoken(&tty_token);
            crit_exit();
@@ -220,7 +220,7 @@ pppopen(cdev_t dev, struct tty *tp)
     getmicrotime(&sc->sc_if.if_lastchange);
     sc->sc_if.if_baudrate = tp->t_ospeed;
 
-    tp->t_sc = (caddr_t) sc;
+    tp->t_slsc = (caddr_t) sc;
     ttyflush(tp, FREAD | FWRITE);
 
     /*
@@ -256,9 +256,9 @@ pppclose(struct tty *tp, int flag)
     clist_free_cblocks(&tp->t_canq);
     clist_free_cblocks(&tp->t_outq);
     tp->t_line = 0;
-    sc = (struct ppp_softc *) tp->t_sc;
+    sc = (struct ppp_softc *) tp->t_slsc;
     if (sc != NULL) {
-       tp->t_sc = NULL;
+       tp->t_slsc = NULL;
        if (tp == (struct tty *) sc->sc_devp) {
            pppasyncrelinq(sc);
            pppdealloc(sc);
@@ -320,7 +320,7 @@ pppasyncsetmtu(struct ppp_softc *sc)
 static int
 pppread(struct tty *tp, struct uio *uio, int flag)
 {
-    struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
+    struct ppp_softc *sc = (struct ppp_softc *)tp->t_slsc;
     struct mbuf *m, *m0;
     int error = 0;
 
@@ -381,7 +381,7 @@ pppread(struct tty *tp, struct uio *uio, int flag)
 static int
 pppwrite(struct tty *tp, struct uio *uio, int flag)
 {
-    struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
+    struct ppp_softc *sc = (struct ppp_softc *)tp->t_slsc;
     struct mbuf *m, *m0, **mp;
     struct sockaddr dst;
     int len, error;
@@ -455,7 +455,7 @@ pppwrite(struct tty *tp, struct uio *uio, int flag)
 static int
 ppptioctl(struct tty *tp, u_long cmd, caddr_t data, int flag, struct ucred *cr)
 {
-    struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
+    struct ppp_softc *sc = (struct ppp_softc *) tp->t_slsc;
     int error;
 
     lwkt_gettoken(&tty_token);
@@ -773,7 +773,7 @@ pppasyncctlp(struct ppp_softc *sc)
 static int
 pppstart(struct tty *tp)
 {
-    struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
+    struct ppp_softc *sc = (struct ppp_softc *) tp->t_slsc;
 
     lwkt_gettoken(&tty_token);
     /*
@@ -869,7 +869,7 @@ pppinput(int c, struct tty *tp)
     int ilen;
 
     lwkt_gettoken(&tty_token);
-    sc = (struct ppp_softc *) tp->t_sc;
+    sc = (struct ppp_softc *) tp->t_slsc;
     if (sc == NULL || tp != (struct tty *) sc->sc_devp) {
        lwkt_reltoken(&tty_token);
        return 0;
index 44b2586..cbf18bf 100644 (file)
@@ -80,6 +80,7 @@
 #include <sys/tty.h>
 #include <sys/clist.h>
 #include <sys/kernel.h>
+#include <sys/sysctl.h>
 #include <sys/conf.h>
 #include <sys/thread2.h>
 
 static void slattach (void *);
 PSEUDO_SET(slattach, if_sl);
 
+/* Set to 0xC002 for broadcast instead of p-to-p */
+static int sliffopts = IFF_POINTOPOINT | SC_AUTOCOMP | IFF_MULTICAST;
+SYSCTL_INT(_net, OID_AUTO, sliffopts, CTLFLAG_RW,
+           &sliffopts, 0, "");
+TUNABLE_INT("net.sliffopts", &sliffopts);
+
 /*
  * SLRMAX is a hard limit on input packet size.  To simplify the code
  * and improve performance, we require that packets fit in an mbuf
@@ -207,12 +214,7 @@ slattach(void *dummy)
        for (sc = sl_softc; i < NSL; sc++) {
                if_initname(&(sc->sc_if), "sl", i++);
                sc->sc_if.if_mtu = SLMTU;
-               sc->sc_if.if_flags =
-#ifdef SLIP_IFF_OPTS
-                   SLIP_IFF_OPTS;
-#else
-                   IFF_POINTOPOINT | SC_AUTOCOMP | IFF_MULTICAST;
-#endif
+               sc->sc_if.if_flags = sliffopts;
                sc->sc_if.if_type = IFT_SLIP;
                sc->sc_if.if_ioctl = slioctl;
                sc->sc_if.if_output = sloutput;
@@ -271,7 +273,7 @@ slopen(cdev_t dev, struct tty *tp)
                                lwkt_reltoken(&tty_token);
                                return (ENOBUFS);
                        }
-                       tp->t_sc = (caddr_t)sc;
+                       tp->t_slsc = (caddr_t)sc;
                        sc->sc_ttyp = tp;
                        sc->sc_if.if_baudrate = tp->t_ospeed;
                        ttyflush(tp, FREAD | FWRITE);
@@ -318,7 +320,7 @@ slclose(struct tty *tp, int flag)
 
        clist_free_cblocks(&tp->t_outq);
        tp->t_line = 0;
-       sc = (struct sl_softc *)tp->t_sc;
+       sc = (struct sl_softc *)tp->t_slsc;
        if (sc != NULL) {
                if (sc->sc_outfill) {
                        sc->sc_outfill = 0;
@@ -331,7 +333,7 @@ slclose(struct tty *tp, int flag)
                if_down(&sc->sc_if);
                sc->sc_flags &= SC_STATIC;
                sc->sc_ttyp = NULL;
-               tp->t_sc = NULL;
+               tp->t_slsc = NULL;
                if (sc->sc_ep) {
                        kfree(sc->sc_ep, M_DEVBUF);
                        sc->sc_ep = NULL;
@@ -352,7 +354,7 @@ slclose(struct tty *tp, int flag)
 static int
 sltioctl(struct tty *tp, u_long cmd, caddr_t data, int flag, struct ucred *cred)
 {
-       struct sl_softc *sc = (struct sl_softc *)tp->t_sc, *nc, *tmpnc;
+       struct sl_softc *sc = (struct sl_softc *)tp->t_slsc, *nc, *tmpnc;
        int nsl;
 
        crit_enter();
@@ -385,7 +387,7 @@ sltioctl(struct tty *tp, u_long cmd, caddr_t data, int flag, struct ucred *cred)
                                                if_down(&nc->sc_if);
                                        sc->sc_flags &= ~SC_STATIC;
                                        sc->sc_flags |= (nc->sc_flags & SC_STATIC);
-                                       tp->t_sc = sc = nc;
+                                       tp->t_slsc = sc = nc;
                                        clist_alloc_cblocks(&tp->t_outq,
                                            SLIP_HIWAT + 2 * sc->sc_if.if_mtu + 1,
                                            SLIP_HIWAT + 2 * sc->sc_if.if_mtu + 1);
@@ -537,7 +539,7 @@ sloutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
 static int
 slstart(struct tty *tp)
 {
-       struct sl_softc *sc = (struct sl_softc *)tp->t_sc;
+       struct sl_softc *sc = (struct sl_softc *)tp->t_slsc;
        struct ifaltq_subque *ifsq = ifq_get_subq_default(&sc->sc_if.if_snd);
        struct mbuf *m;
        u_char *cp;
@@ -785,16 +787,28 @@ slinput(int c, struct tty *tp)
        int len;
        u_char chdr[CHDR_LEN];
 
+#if 0
+       kprintf(" %02x", (unsigned char)c);
+       if ((unsigned char)c == 0xC0)
+               kprintf("\n");
+#endif
+
        lwkt_gettoken(&tty_token);
        tk_nin++;
-       sc = (struct sl_softc *)tp->t_sc;
+       sc = (struct sl_softc *)tp->t_slsc;
        if (sc == NULL) {
                lwkt_reltoken(&tty_token);
+#if 0
+               kprintf("X");
+#endif
                return 0;
        }
        if (c & TTY_ERRORMASK || (tp->t_state & TS_CONNECTED) == 0) {
                sc->sc_flags |= SC_ERROR;
                lwkt_reltoken(&tty_token);
+#if 0
+               kprintf("Y");
+#endif
                return 0;
        }
        c &= TTY_CHARMASK;
index 502e405..eef1c8a 100644 (file)
@@ -105,8 +105,8 @@ struct tty {
                                        /* Set hardware state. */
        int     (*t_param) (struct tty *, struct termios *);
        void    (*t_unhold) (struct tty *); /* callback to pty after unhold */
-       void    *t_sc;                  /* XXX: net/if_sl.c:sl_softc. Also 
-                                                used by u4b ucom */
+       void    *t_sc;                  /* generic driver (u4b com) */
+       void    *t_slsc;                /* if_sl.c, ppp_tty.c (disc) */
        int     t_column;               /* Tty output column. */
        int     t_rocount, t_rocol;     /* Tty. */
        int     t_ififosize;            /* Total size of upstream fifos. */