On Tue, Feb 04, 2020 at 09:16:34AM +0100, Gerhard Roth wrote: > The updated patch below introduces a UMBFLG_NO_INET6 which is set on > receipt of a MBIM_STATUS_NO_DEVICE_SUPPORT in response to a > MBIM_CID_CONNECT. The code will then retry the connect operation in > IPv4-only mode. > > That won't give you any IPv6 support, but at least it won't break > your setup.
OK bluhm@ Now it works: umb0: state going up from 'open' to 'radio on' umb0: packet service changed from unknown to detached, class none, speed: 0 up / 0 down umb0: none state unlocked (-1 attempts left) umb0: set/qry MBIM_CID_SUBSCRIBER_READY_STATUS failed: BUSY umb0: SIM initialized umb0: state going up from 'radio on' to 'SIM is ready' umb0: set/qry MBIM_CID_PACKET_SERVICE failed: FAILURE umb0: packet service changed from detached to attaching, class none, speed: 0 up / 0 down umb0: packet service changed from attaching to attached, class HSPA, speed: 5760000 up / 14400000 down umb0: state going up from 'SIM is ready' to 'attached' umb0: connecting ... umb0: device does not support IPv6 umb0: connecting ... umb0: connection activating umb0: network connected umb0: connection activated umb0: state going up from 'attached' to 'connected' umb0: IPv4 addr 100.67.244.231, mask 255.255.255.240, gateway 100.67.244.226 umb0: IPv4 nameserver 139.7.30.126 umb0: IPv4 nameserver 139.7.30.125 umb0: ISP or WWAN module offers no IPv6 support umb0: MTU 1500 umb0: state going up from 'connected' to 'up' umb0: link state changed from down to up umb0: packet service attached, class custom, speed: 5760000 up / 21000000 down umb0: unable to set IPv4 default route, error 17 umb0: IPv4 addr 100.67.244.231, mask 255.255.255.240, gateway 100.67.244.226 umb0: IPv4 nameserver 139.7.30.126 umb0: IPv4 nameserver 139.7.30.125 umb0: ISP or WWAN module offers no IPv6 support > Index: sbin/ifconfig/ifconfig.c > =================================================================== > RCS file: /cvs/src/sbin/ifconfig/ifconfig.c,v > retrieving revision 1.417 > diff -u -p -u -p -r1.417 ifconfig.c > --- sbin/ifconfig/ifconfig.c 27 Dec 2019 14:34:46 -0000 1.417 > +++ sbin/ifconfig/ifconfig.c 28 Jan 2020 12:16:23 -0000 > @@ -5666,6 +5666,7 @@ umb_status(void) > char apn[UMB_APN_MAXLEN+1]; > char pn[UMB_PHONENR_MAXLEN+1]; > int i, n; > + char astr[INET6_ADDRSTRLEN]; > > memset((char *)&mi, 0, sizeof(mi)); > ifr.ifr_data = (caddr_t)&mi; > @@ -5830,7 +5831,15 @@ umb_status(void) > for (i = 0, n = 0; i < UMB_MAX_DNSSRV; i++) { > if (mi.ipv4dns[i].s_addr == INADDR_ANY) > break; > - printf("%s %s", n++ ? "" : "\tdns", inet_ntoa(mi.ipv4dns[i])); > + printf("%s %s", n++ ? "" : "\tdns", > + inet_ntop(AF_INET, &mi.ipv4dns[i], astr, sizeof (astr))); > + } > + for (i = 0; i < UMB_MAX_DNSSRV; i++) { > + if (memcmp(&mi.ipv6dns[i], &in6addr_any, > + sizeof (mi.ipv6dns[i])) == 0) > + break; > + printf("%s %s", n++ ? "" : "\tdns", > + inet_ntop(AF_INET6, &mi.ipv6dns[i], astr, sizeof (astr))); > } > if (n) > printf("\n"); > Index: share/man/man4/umb.4 > =================================================================== > RCS file: /cvs/src/share/man/man4/umb.4,v > retrieving revision 1.9 > diff -u -p -u -p -r1.9 umb.4 > --- share/man/man4/umb.4 23 Nov 2017 20:47:26 -0000 1.9 > +++ share/man/man4/umb.4 28 Jan 2020 12:16:23 -0000 > @@ -40,6 +40,11 @@ will remain in this state until the MBIM > In case the device is connected to an "always-on" USB port, > it may be possible to connect to a provider without entering the > PIN again even if the system was rebooted. > +.Pp > +If the kernel has been compiled with INET6, the driver will try to > +obtain an IPv6 address from the provider. To succeed with the IPv6 > +configuration, both the ISP and the MBIM device have to offer IPv6 > +support. > .Sh HARDWARE > The following devices should work: > .Pp > @@ -64,10 +69,6 @@ The following devices should work: > .%U http://www.usb.org/developers/docs/devclass_docs/MBIM10Errata1_073013.zip > .Re > .Sh CAVEATS > -The > -.Nm > -driver does not support IPv6. > -.Pp > Devices which fail to provide a conforming MBIM implementation will > probably be attached as some other driver, such as > .Xr umsm 4 . > Index: sys/dev/usb/if_umb.c > =================================================================== > RCS file: /cvs/src/sys/dev/usb/if_umb.c,v > retrieving revision 1.31 > diff -u -p -u -p -r1.31 if_umb.c > --- sys/dev/usb/if_umb.c 26 Nov 2019 23:04:28 -0000 1.31 > +++ sys/dev/usb/if_umb.c 4 Feb 2020 07:50:30 -0000 > @@ -43,6 +43,14 @@ > #include <netinet/in_var.h> > #include <netinet/ip.h> > > +#ifdef INET6 > +#include <netinet/ip6.h> > +#include <netinet6/in6_var.h> > +#include <netinet6/ip6_var.h> > +#include <netinet6/in6_ifattach.h> > +#include <netinet6/nd6.h> > +#endif > + > #include <machine/bus.h> > > #include <dev/usb/usb.h> > @@ -158,7 +166,9 @@ int umb_decode_connect_info(struct umb > void umb_clear_addr(struct umb_softc *); > int umb_add_inet_config(struct umb_softc *, struct in_addr, u_int, > struct in_addr); > -void umb_send_inet_proposal(struct umb_softc *); > +int umb_add_inet6_config(struct umb_softc *, struct in6_addr *, > + u_int, struct in6_addr *); > +void umb_send_inet_proposal(struct umb_softc *, int); > int umb_decode_ip_configuration(struct umb_softc *, void *, int); > void umb_rx(struct umb_softc *); > void umb_rxeof(struct usbd_xfer *, void *, usbd_status); > @@ -800,8 +810,8 @@ umb_input(struct ifnet *ifp, struct mbuf > #endif /* INET6 */ > default: > ifp->if_ierrors++; > - DPRINTFN(4, "%s: dropping packet with bad IP version (%d)\n", > - __func__, ipv); > + DPRINTFN(4, "%s: dropping packet with bad IP version (af %d)\n", > + __func__, af); > m_freem(m); > return 1; > } > @@ -902,7 +912,10 @@ umb_rtrequest(struct ifnet *ifp, int req > struct umb_softc *sc = ifp->if_softc; > > if (req == RTM_PROPOSAL) { > - umb_send_inet_proposal(sc); > + umb_send_inet_proposal(sc, AF_INET); > +#ifdef INET6 > + umb_send_inet_proposal(sc, AF_INET6); > +#endif > return; > } > > @@ -1596,11 +1609,6 @@ umb_decode_connect_info(struct umb_softc > if (ifp->if_flags & IFF_DEBUG) > log(LOG_INFO, "%s: connection %s\n", DEVNAM(sc), > umb_activation(act)); > - if ((ifp->if_flags & IFF_DEBUG) && > - letoh32(ci->iptype) != MBIM_CONTEXT_IPTYPE_DEFAULT && > - letoh32(ci->iptype) != MBIM_CONTEXT_IPTYPE_IPV4) > - log(LOG_DEBUG, "%s: got iptype %d connection\n", > - DEVNAM(sc), letoh32(ci->iptype)); > > sc->sc_info.activation = act; > sc->sc_info.nwerror = letoh32(ci->nwerror); > @@ -1621,9 +1629,16 @@ umb_clear_addr(struct umb_softc *sc) > struct ifnet *ifp = GET_IFP(sc); > > memset(sc->sc_info.ipv4dns, 0, sizeof (sc->sc_info.ipv4dns)); > - umb_send_inet_proposal(sc); > + memset(sc->sc_info.ipv6dns, 0, sizeof (sc->sc_info.ipv6dns)); > + umb_send_inet_proposal(sc, AF_INET); > +#ifdef INET6 > + umb_send_inet_proposal(sc, AF_INET6); > +#endif > NET_LOCK(); > in_ifdetach(ifp); > +#ifdef INET6 > + in6_ifdetach(ifp); > +#endif > NET_UNLOCK(); > } > > @@ -1698,29 +1713,125 @@ umb_add_inet_config(struct umb_softc *sc > sockaddr_ntop(sintosa(&ifra.ifra_dstaddr), str[2], > sizeof(str[2]))); > } > - return rv; > + return 0; > +} > + > +#ifdef INET6 > +int > +umb_add_inet6_config(struct umb_softc *sc, struct in6_addr *ip, u_int > prefixlen, > + struct in6_addr *gw) > +{ > + struct ifnet *ifp = GET_IFP(sc); > + struct in6_aliasreq ifra; > + struct sockaddr_in6 *sin6, default_sin6; > + struct rt_addrinfo info; > + struct rtentry *rt; > + int rv; > + > + memset(&ifra, 0, sizeof (ifra)); > + sin6 = &ifra.ifra_addr; > + sin6->sin6_family = AF_INET6; > + sin6->sin6_len = sizeof (*sin6); > + memcpy(&sin6->sin6_addr, ip, sizeof (sin6->sin6_addr)); > + > + sin6 = &ifra.ifra_dstaddr; > + sin6->sin6_family = AF_INET6; > + sin6->sin6_len = sizeof (*sin6); > + memcpy(&sin6->sin6_addr, gw, sizeof (sin6->sin6_addr)); > + > + /* XXX: in6_update_ifa() accepts only 128 bits for P2P interfaces. */ > + prefixlen = 128; > + > + sin6 = &ifra.ifra_prefixmask; > + sin6->sin6_family = AF_INET6; > + sin6->sin6_len = sizeof (*sin6); > + in6_prefixlen2mask(&sin6->sin6_addr, prefixlen); > + > + ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; > + ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; > + > + rv = in6_ioctl(SIOCAIFADDR_IN6, (caddr_t)&ifra, ifp, 1); > + if (rv != 0) { > + printf("%s: unable to set IPv6 address, error %d\n", > + DEVNAM(ifp->if_softc), rv); > + return rv; > + } > + > + memset(&default_sin6, 0, sizeof(default_sin6)); > + default_sin6.sin6_family = AF_INET6; > + default_sin6.sin6_len = sizeof (default_sin6); > + > + memset(&info, 0, sizeof(info)); > + info.rti_flags = RTF_GATEWAY /* maybe | RTF_STATIC */; > + info.rti_ifa = ifa_ifwithaddr(sin6tosa(&ifra.ifra_addr), > + ifp->if_rdomain); > + info.rti_info[RTAX_DST] = sin6tosa(&default_sin6); > + info.rti_info[RTAX_NETMASK] = sin6tosa(&default_sin6); > + info.rti_info[RTAX_GATEWAY] = sin6tosa(&ifra.ifra_dstaddr); > + > + NET_LOCK(); > + rv = rtrequest(RTM_ADD, &info, 0, &rt, ifp->if_rdomain); > + NET_UNLOCK(); > + if (rv) { > + printf("%s: unable to set IPv6 default route, " > + "error %d\n", DEVNAM(ifp->if_softc), rv); > + rtm_miss(RTM_MISS, &info, 0, RTP_NONE, 0, rv, > + ifp->if_rdomain); > + } else { > + /* Inform listeners of the new route */ > + rtm_send(rt, RTM_ADD, rv, ifp->if_rdomain); > + rtfree(rt); > + } > + > + if (ifp->if_flags & IFF_DEBUG) { > + char str[3][INET6_ADDRSTRLEN]; > + log(LOG_INFO, "%s: IPv6 addr %s, mask %s, gateway %s\n", > + DEVNAM(ifp->if_softc), > + sockaddr_ntop(sin6tosa(&ifra.ifra_addr), str[0], > + sizeof(str[0])), > + sockaddr_ntop(sin6tosa(&ifra.ifra_prefixmask), str[1], > + sizeof(str[1])), > + sockaddr_ntop(sin6tosa(&ifra.ifra_dstaddr), str[2], > + sizeof(str[2]))); > + } > + return 0; > } > +#endif > > void > -umb_send_inet_proposal(struct umb_softc *sc) > +umb_send_inet_proposal(struct umb_softc *sc, int af) > { > struct ifnet *ifp = GET_IFP(sc); > struct sockaddr_rtdns rtdns; > struct rt_addrinfo info; > int i, flag = 0; > + size_t sz = 0; > > memset(&rtdns, 0, sizeof(rtdns)); > memset(&info, 0, sizeof(info)); > > for (i = 0; i < UMB_MAX_DNSSRV; i++) { > - if (sc->sc_info.ipv4dns[i].s_addr == INADDR_ANY) > - break; > - memcpy(rtdns.sr_dns + i * sizeof(struct in_addr), > - &sc->sc_info.ipv4dns[i], sizeof(struct in_addr)); > - flag = RTF_UP; > + if (af == AF_INET) { > + sz = sizeof (sc->sc_info.ipv4dns[i]); > + if (sc->sc_info.ipv4dns[i].s_addr == INADDR_ANY) > + break; > + memcpy(rtdns.sr_dns + i * sz, &sc->sc_info.ipv4dns[i], > + sz); > + flag = RTF_UP; > +#ifdef INET6 > + } if (af == AF_INET6) { > + sz = sizeof (sc->sc_info.ipv6dns[i]); > + if (IN6_ARE_ADDR_EQUAL(&sc->sc_info.ipv6dns[i], > + &in6addr_any)) > + break; > + memcpy(rtdns.sr_dns + i * sz, &sc->sc_info.ipv6dns[i], > + sz); > + flag = RTF_UP; > +#endif > + } > } > - rtdns.sr_family = AF_INET; > - rtdns.sr_len = 2 + i * sizeof(struct in_addr); > + rtdns.sr_family = af; > + rtdns.sr_len = 2 + i * sz; > info.rti_info[RTAX_DNS] = srtdnstosa(&rtdns); > > rtm_proposal(ifp, &info, flag, RTP_PROPOSAL_UMB); > @@ -1732,7 +1843,7 @@ umb_decode_ip_configuration(struct umb_s > struct mbim_cid_ip_configuration_info *ic = data; > struct ifnet *ifp = GET_IFP(sc); > int s; > - uint32_t avail; > + uint32_t avail_v4; > uint32_t val; > int n, i; > int off; > @@ -1740,6 +1851,12 @@ umb_decode_ip_configuration(struct umb_s > struct in_addr addr, gw; > int state = -1; > int rv; > + int hasmtu = 0; > +#ifdef INET6 > + uint32_t avail_v6; > + struct mbim_cid_ipv6_element ipv6elem; > + struct in6_addr addr6, gw6; > +#endif > > if (len < sizeof (*ic)) > return 0; > @@ -1750,17 +1867,20 @@ umb_decode_ip_configuration(struct umb_s > } > s = splnet(); > > + memset(sc->sc_info.ipv4dns, 0, sizeof (sc->sc_info.ipv4dns)); > + memset(sc->sc_info.ipv6dns, 0, sizeof (sc->sc_info.ipv6dns)); > + > /* > * IPv4 configuation > */ > - avail = letoh32(ic->ipv4_available); > - if ((avail & (MBIM_IPCONF_HAS_ADDRINFO | MBIM_IPCONF_HAS_GWINFO)) == > + avail_v4 = letoh32(ic->ipv4_available); > + if ((avail_v4 & (MBIM_IPCONF_HAS_ADDRINFO | MBIM_IPCONF_HAS_GWINFO)) == > (MBIM_IPCONF_HAS_ADDRINFO | MBIM_IPCONF_HAS_GWINFO)) { > n = letoh32(ic->ipv4_naddr); > off = letoh32(ic->ipv4_addroffs); > > if (n == 0 || off + sizeof (ipv4elem) > len) > - goto done; > + goto tryv6; > if (n != 1 && ifp->if_flags & IFF_DEBUG) > log(LOG_INFO, "%s: more than one IPv4 addr: %d\n", > DEVNAM(ifp->if_softc), n); > @@ -1771,6 +1891,8 @@ umb_decode_ip_configuration(struct umb_s > addr.s_addr = ipv4elem.addr; > > off = letoh32(ic->ipv4_gwoffs); > + if (off + sizeof (gw) > len) > + goto done; > memcpy(&gw, data + off, sizeof(gw)); > > rv = umb_add_inet_config(sc, addr, ipv4elem.prefixlen, gw); > @@ -1780,12 +1902,12 @@ umb_decode_ip_configuration(struct umb_s > } > > memset(sc->sc_info.ipv4dns, 0, sizeof (sc->sc_info.ipv4dns)); > - if (avail & MBIM_IPCONF_HAS_DNSINFO) { > + if (avail_v4 & MBIM_IPCONF_HAS_DNSINFO) { > n = letoh32(ic->ipv4_ndnssrv); > off = letoh32(ic->ipv4_dnssrvoffs); > i = 0; > while (n-- > 0) { > - if (off + sizeof (uint32_t) > len) > + if (off + sizeof (addr) > len) > break; > memcpy(&addr, data + off, sizeof(addr)); > if (i < UMB_MAX_DNSSRV) > @@ -1798,29 +1920,95 @@ umb_decode_ip_configuration(struct umb_s > &addr, str, sizeof(str))); > } > } > - umb_send_inet_proposal(sc); > + umb_send_inet_proposal(sc, AF_INET); > } > - > - if ((avail & MBIM_IPCONF_HAS_MTUINFO)) { > + if ((avail_v4 & MBIM_IPCONF_HAS_MTUINFO)) { > val = letoh32(ic->ipv4_mtu); > if (ifp->if_hardmtu != val && val <= sc->sc_maxpktlen) { > + hasmtu = 1; > ifp->if_hardmtu = val; > if (ifp->if_mtu > val) > ifp->if_mtu = val; > - if (ifp->if_flags & IFF_DEBUG) > - log(LOG_INFO, "%s: MTU %d\n", DEVNAM(sc), val); > } > } > > - avail = letoh32(ic->ipv6_available); > - if ((ifp->if_flags & IFF_DEBUG) && avail & MBIM_IPCONF_HAS_ADDRINFO) { > - /* XXX FIXME: IPv6 configuation missing */ > - log(LOG_INFO, "%s: ignoring IPv6 configuration\n", DEVNAM(sc)); > +tryv6:; > +#ifdef INET6 > + /* > + * IPv6 configuation > + */ > + avail_v6 = letoh32(ic->ipv6_available); > + if (avail_v6 == 0) { > + if (ifp->if_flags & IFF_DEBUG) > + log(LOG_INFO, "%s: ISP or WWAN module offers no IPv6 " > + "support\n", DEVNAM(ifp->if_softc)); > + goto done; > + } > + > + if ((avail_v4 & (MBIM_IPCONF_HAS_ADDRINFO | MBIM_IPCONF_HAS_GWINFO)) == > + (MBIM_IPCONF_HAS_ADDRINFO | MBIM_IPCONF_HAS_GWINFO)) { > + n = letoh32(ic->ipv6_naddr); > + off = letoh32(ic->ipv6_addroffs); > + > + if (n == 0 || off + sizeof (ipv6elem) > len) > + goto done; > + if (n != 1 && ifp->if_flags & IFF_DEBUG) > + log(LOG_INFO, "%s: more than one IPv6 addr: %d\n", > + DEVNAM(ifp->if_softc), n); > + > + /* Only pick the first one */ > + memcpy(&ipv6elem, data + off, sizeof (ipv6elem)); > + memcpy(&addr6, ipv6elem.addr, sizeof (addr6)); > + > + off = letoh32(ic->ipv6_gwoffs); > + if (off + sizeof (gw6) > len) > + goto done; > + memcpy(&gw6, data + off, sizeof (gw6)); > + > + rv = umb_add_inet6_config(sc, &addr6, ipv6elem.prefixlen, &gw6); > + if (rv == 0) > + state = UMB_S_UP; > + } > + > + if (avail_v6 & MBIM_IPCONF_HAS_DNSINFO) { > + n = letoh32(ic->ipv6_ndnssrv); > + off = letoh32(ic->ipv6_dnssrvoffs); > + i = 0; > + while (n-- > 0) { > + if (off + sizeof (addr6) > len) > + break; > + memcpy(&addr6, data + off, sizeof(addr6)); > + if (i < UMB_MAX_DNSSRV) > + sc->sc_info.ipv6dns[i++] = addr6; > + off += sizeof(addr6); > + if (ifp->if_flags & IFF_DEBUG) { > + char str[INET6_ADDRSTRLEN]; > + log(LOG_INFO, "%s: IPv6 nameserver %s\n", > + DEVNAM(ifp->if_softc), inet_ntop(AF_INET6, > + &addr6, str, sizeof(str))); > + } > + } > + umb_send_inet_proposal(sc, AF_INET6); > + } > + > + if ((avail_v6 & MBIM_IPCONF_HAS_MTUINFO)) { > + val = letoh32(ic->ipv6_mtu); > + if (ifp->if_hardmtu != val && val <= sc->sc_maxpktlen) { > + hasmtu = 1; > + ifp->if_hardmtu = val; > + if (ifp->if_mtu > val) > + ifp->if_mtu = val; > + } > } > +#endif > + > +done: > + if (hasmtu && (ifp->if_flags & IFF_DEBUG)) > + log(LOG_INFO, "%s: MTU %d\n", DEVNAM(sc), ifp->if_hardmtu); > + > if (state != -1) > umb_newstate(sc, state, 0); > > -done: > splx(s); > return 1; > } > @@ -2393,6 +2581,11 @@ umb_send_connect(struct umb_softc *sc, i > c->authprot = htole32(MBIM_AUTHPROT_NONE); > c->compression = htole32(MBIM_COMPRESSION_NONE); > c->iptype = htole32(MBIM_CONTEXT_IPTYPE_IPV4); > +#ifdef INET6 > + /* XXX FIXME: support IPv6-only mode, too */ > + if ((sc->sc_flags & UMBFLG_NO_INET6) == 0) > + c->iptype = htole32(MBIM_CONTEXT_IPTYPE_IPV4V6); > +#endif > memcpy(c->context, umb_uuid_context_internet, sizeof (c->context)); > umb_cmd(sc, MBIM_CID_CONNECT, MBIM_CMDOP_SET, c, off); > done: > @@ -2476,6 +2669,20 @@ umb_command_done(struct umb_softc *sc, v > switch (status) { > case MBIM_STATUS_SUCCESS: > break; > +#ifdef INET6 > + case MBIM_STATUS_NO_DEVICE_SUPPORT: > + if ((cid == MBIM_CID_CONNECT) && > + (sc->sc_flags & UMBFLG_NO_INET6) == 0) { > + sc->sc_flags |= UMBFLG_NO_INET6; > + if (ifp->if_flags & IFF_DEBUG) > + log(LOG_ERR, > + "%s: device does not support IPv6\n", > + DEVNAM(sc)); > + } > + /* Re-trigger the connect, this time IPv4 only */ > + usb_add_task(sc->sc_udev, &sc->sc_umb_task); > + return; > +#endif > case MBIM_STATUS_NOT_INITIALIZED: > if (ifp->if_flags & IFF_DEBUG) > log(LOG_ERR, "%s: SIM not initialized (PIN missing)\n", > Index: sys/dev/usb/if_umb.h > =================================================================== > RCS file: /cvs/src/sys/dev/usb/if_umb.h,v > retrieving revision 1.5 > diff -u -p -u -p -r1.5 if_umb.h > --- sys/dev/usb/if_umb.h 26 Aug 2019 15:23:01 -0000 1.5 > +++ sys/dev/usb/if_umb.h 4 Feb 2020 07:30:43 -0000 > @@ -321,6 +321,7 @@ struct umb_info { > > #define UMB_MAX_DNSSRV 2 > struct in_addr ipv4dns[UMB_MAX_DNSSRV]; > + struct in6_addr ipv6dns[UMB_MAX_DNSSRV]; > }; > > #ifdef _KERNEL > @@ -345,6 +346,7 @@ struct umb_softc { > int sc_ndp_remainder; > > #define UMBFLG_FCC_AUTH_REQUIRED 0x0001 > +#define UMBFLG_NO_INET6 0x0002 > uint32_t sc_flags; > int sc_cid; > > @@ -380,6 +382,6 @@ struct umb_softc { > > #define sc_state sc_info.state > #define sc_roaming sc_info.enable_roaming > - struct umb_info sc_info; > + struct umb_info sc_info; > }; > #endif /* _KERNEL */