From: Matthew Dillon Date: Sat, 14 Nov 2015 01:39:46 +0000 (-0800) Subject: kernel - Fixes for usb modems X-Git-Tag: v4.5.0~96 X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/commitdiff_plain/c90f12497dbc1e422d61a2e201b251ea9b87477d kernel - Fixes for usb modems * 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. --- diff --git a/sys/bus/u4b/serial/usb_serial.c b/sys/bus/u4b/serial/usb_serial.c index dd3b5db2e0..ec1d7307a0 100644 --- a/sys/bus/u4b/serial/usb_serial.c +++ b/sys/bus/u4b/serial/usb_serial.c @@ -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; diff --git a/sys/net/ppp_layer/ppp_tty.c b/sys/net/ppp_layer/ppp_tty.c index 3a5f87c18f..9ae185562c 100644 --- a/sys/net/ppp_layer/ppp_tty.c +++ b/sys/net/ppp_layer/ppp_tty.c @@ -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; diff --git a/sys/net/sl/if_sl.c b/sys/net/sl/if_sl.c index 44b2586fd5..cbf18bfb78 100644 --- a/sys/net/sl/if_sl.c +++ b/sys/net/sl/if_sl.c @@ -80,6 +80,7 @@ #include #include #include +#include #include #include @@ -106,6 +107,12 @@ 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; diff --git a/sys/sys/tty.h b/sys/sys/tty.h index 502e405b1f..eef1c8a2d4 100644 --- a/sys/sys/tty.h +++ b/sys/sys/tty.h @@ -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. */