LCOV - code coverage report
Current view: top level - dev/usb - if_umb.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 1319 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 63 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: if_umb.c,v 1.20 2018/09/10 17:00:45 gerhard Exp $ */
       2             : 
       3             : /*
       4             :  * Copyright (c) 2016 genua mbH
       5             :  * All rights reserved.
       6             :  *
       7             :  * Permission to use, copy, modify, and distribute this software for any
       8             :  * purpose with or without fee is hereby granted, provided that the above
       9             :  * copyright notice and this permission notice appear in all copies.
      10             :  *
      11             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      12             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      13             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      14             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      15             :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      16             :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      17             :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      18             :  */
      19             : 
      20             : /*
      21             :  * Mobile Broadband Interface Model specification:
      22             :  * http://www.usb.org/developers/docs/devclass_docs/MBIM10Errata1_073013.zip
      23             :  * Compliance testing guide
      24             :  * http://www.usb.org/developers/docs/devclass_docs/MBIM-Compliance-1.0.pdf
      25             :  */
      26             : #include "bpfilter.h"
      27             : 
      28             : #include <sys/param.h>
      29             : #include <sys/mbuf.h>
      30             : #include <sys/socket.h>
      31             : #include <sys/systm.h>
      32             : #include <sys/syslog.h>
      33             : 
      34             : #if NBPFILTER > 0
      35             : #include <net/bpf.h>
      36             : #endif
      37             : #include <net/if.h>
      38             : #include <net/if_var.h>
      39             : #include <net/if_types.h>
      40             : 
      41             : #include <netinet/in.h>
      42             : #include <netinet/in_var.h>
      43             : #include <netinet/ip.h>
      44             : 
      45             : #include <machine/bus.h>
      46             : 
      47             : #include <dev/usb/usb.h>
      48             : #include <dev/usb/usbdi.h>
      49             : #include <dev/usb/usbdivar.h>
      50             : #include <dev/usb/usbdi_util.h>
      51             : #include <dev/usb/usbdevs.h>
      52             : #include <dev/usb/usbcdc.h>
      53             : 
      54             : #include <dev/usb/mbim.h>
      55             : #include <dev/usb/if_umb.h>
      56             : 
      57             : #ifdef UMB_DEBUG
      58             : #define DPRINTF(x...)                                                   \
      59             :                 do { if (umb_debug) log(LOG_DEBUG, x); } while (0)
      60             : 
      61             : #define DPRINTFN(n, x...)                                               \
      62             :                 do { if (umb_debug >= (n)) log(LOG_DEBUG, x); } while (0)
      63             : 
      64             : #define DDUMPN(n, b, l)                                                 \
      65             :                 do {                                                    \
      66             :                         if (umb_debug >= (n))                                \
      67             :                                 umb_dump((b), (l));                     \
      68             :                 } while (0)
      69             : 
      70             : int      umb_debug = 0;
      71             : char    *umb_uuid2str(uint8_t [MBIM_UUID_LEN]);
      72             : void     umb_dump(void *, int);
      73             : 
      74             : #else
      75             : #define DPRINTF(x...)           do { } while (0)
      76             : #define DPRINTFN(n, x...)       do { } while (0)
      77             : #define DDUMPN(n, b, l)         do { } while (0)
      78             : #endif
      79             : 
      80             : #define DEVNAM(sc)              (((struct umb_softc *)(sc))->sc_dev.dv_xname)
      81             : 
      82             : /*
      83             :  * State change timeout
      84             :  */
      85             : #define UMB_STATE_CHANGE_TIMEOUT        30
      86             : 
      87             : /*
      88             :  * State change flags
      89             :  */
      90             : #define UMB_NS_DONT_DROP        0x0001  /* do not drop below current state */
      91             : #define UMB_NS_DONT_RAISE       0x0002  /* do not raise below current state */
      92             : 
      93             : /*
      94             :  * Diagnostic macros
      95             :  */
      96             : const struct umb_valdescr umb_regstates[] = MBIM_REGSTATE_DESCRIPTIONS;
      97             : const struct umb_valdescr umb_dataclasses[] = MBIM_DATACLASS_DESCRIPTIONS;
      98             : const struct umb_valdescr umb_simstate[] = MBIM_SIMSTATE_DESCRIPTIONS;
      99             : const struct umb_valdescr umb_messages[] = MBIM_MESSAGES_DESCRIPTIONS;
     100             : const struct umb_valdescr umb_status[] = MBIM_STATUS_DESCRIPTIONS;
     101             : const struct umb_valdescr umb_cids[] = MBIM_CID_DESCRIPTIONS;
     102             : const struct umb_valdescr umb_pktstate[] = MBIM_PKTSRV_STATE_DESCRIPTIONS;
     103             : const struct umb_valdescr umb_actstate[] = MBIM_ACTIVATION_STATE_DESCRIPTIONS;
     104             : const struct umb_valdescr umb_error[] = MBIM_ERROR_DESCRIPTIONS;
     105             : const struct umb_valdescr umb_pintype[] = MBIM_PINTYPE_DESCRIPTIONS;
     106             : const struct umb_valdescr umb_istate[] = UMB_INTERNAL_STATE_DESCRIPTIONS;
     107             : 
     108             : #define umb_regstate(c)         umb_val2descr(umb_regstates, (c))
     109             : #define umb_dataclass(c)        umb_val2descr(umb_dataclasses, (c))
     110             : #define umb_simstate(s)         umb_val2descr(umb_simstate, (s))
     111             : #define umb_request2str(m)      umb_val2descr(umb_messages, (m))
     112             : #define umb_status2str(s)       umb_val2descr(umb_status, (s))
     113             : #define umb_cid2str(c)          umb_val2descr(umb_cids, (c))
     114             : #define umb_packet_state(s)     umb_val2descr(umb_pktstate, (s))
     115             : #define umb_activation(s)       umb_val2descr(umb_actstate, (s))
     116             : #define umb_error2str(e)        umb_val2descr(umb_error, (e))
     117             : #define umb_pin_type(t)         umb_val2descr(umb_pintype, (t))
     118             : #define umb_istate(s)           umb_val2descr(umb_istate, (s))
     119             : 
     120             : int              umb_match(struct device *, void *, void *);
     121             : void             umb_attach(struct device *, struct device *, void *);
     122             : int              umb_detach(struct device *, int);
     123             : void             umb_ncm_setup(struct umb_softc *);
     124             : int              umb_alloc_xfers(struct umb_softc *);
     125             : void             umb_free_xfers(struct umb_softc *);
     126             : int              umb_alloc_bulkpipes(struct umb_softc *);
     127             : void             umb_close_bulkpipes(struct umb_softc *);
     128             : int              umb_ioctl(struct ifnet *, u_long, caddr_t);
     129             : int              umb_output(struct ifnet *, struct mbuf *, struct sockaddr *,
     130             :                     struct rtentry *);
     131             : int              umb_input(struct ifnet *, struct mbuf *, void *);
     132             : void             umb_start(struct ifnet *);
     133             : void             umb_watchdog(struct ifnet *);
     134             : void             umb_statechg_timeout(void *);
     135             : 
     136             : void             umb_newstate(struct umb_softc *, enum umb_state, int);
     137             : void             umb_state_task(void *);
     138             : void             umb_up(struct umb_softc *);
     139             : void             umb_down(struct umb_softc *, int);
     140             : 
     141             : void             umb_get_response_task(void *);
     142             : 
     143             : void             umb_decode_response(struct umb_softc *, void *, int);
     144             : void             umb_handle_indicate_status_msg(struct umb_softc *, void *,
     145             :                     int);
     146             : void             umb_handle_opendone_msg(struct umb_softc *, void *, int);
     147             : void             umb_handle_closedone_msg(struct umb_softc *, void *, int);
     148             : int              umb_decode_register_state(struct umb_softc *, void *, int);
     149             : int              umb_decode_devices_caps(struct umb_softc *, void *, int);
     150             : int              umb_decode_subscriber_status(struct umb_softc *, void *, int);
     151             : int              umb_decode_radio_state(struct umb_softc *, void *, int);
     152             : int              umb_decode_pin(struct umb_softc *, void *, int);
     153             : int              umb_decode_packet_service(struct umb_softc *, void *, int);
     154             : int              umb_decode_signal_state(struct umb_softc *, void *, int);
     155             : int              umb_decode_connect_info(struct umb_softc *, void *, int);
     156             : int              umb_decode_ip_configuration(struct umb_softc *, void *, int);
     157             : void             umb_rx(struct umb_softc *);
     158             : void             umb_rxeof(struct usbd_xfer *, void *, usbd_status);
     159             : int              umb_encap(struct umb_softc *);
     160             : void             umb_txeof(struct usbd_xfer *, void *, usbd_status);
     161             : void             umb_decap(struct umb_softc *, struct usbd_xfer *);
     162             : 
     163             : usbd_status      umb_send_encap_command(struct umb_softc *, void *, int);
     164             : int              umb_get_encap_response(struct umb_softc *, void *, int *);
     165             : void             umb_ctrl_msg(struct umb_softc *, uint32_t, void *, int);
     166             : 
     167             : void             umb_open(struct umb_softc *);
     168             : void             umb_close(struct umb_softc *);
     169             : 
     170             : int              umb_setpin(struct umb_softc *, int, int, void *, int, void *,
     171             :                     int);
     172             : void             umb_setdataclass(struct umb_softc *);
     173             : void             umb_radio(struct umb_softc *, int);
     174             : void             umb_allocate_cid(struct umb_softc *);
     175             : void             umb_send_fcc_auth(struct umb_softc *);
     176             : void             umb_packet_service(struct umb_softc *, int);
     177             : void             umb_connect(struct umb_softc *);
     178             : void             umb_disconnect(struct umb_softc *);
     179             : void             umb_send_connect(struct umb_softc *, int);
     180             : 
     181             : void             umb_qry_ipconfig(struct umb_softc *);
     182             : void             umb_cmd(struct umb_softc *, int, int, void *, int);
     183             : void             umb_cmd1(struct umb_softc *, int, int, void *, int, uint8_t *);
     184             : void             umb_command_done(struct umb_softc *, void *, int);
     185             : void             umb_decode_cid(struct umb_softc *, uint32_t, void *, int);
     186             : void             umb_decode_qmi(struct umb_softc *, uint8_t *, int);
     187             : 
     188             : void             umb_intr(struct usbd_xfer *, void *, usbd_status);
     189             : 
     190             : char            *umb_ntop(struct sockaddr *);
     191             : 
     192             : int              umb_xfer_tout = USBD_DEFAULT_TIMEOUT;
     193             : 
     194             : uint8_t          umb_uuid_basic_connect[] = MBIM_UUID_BASIC_CONNECT;
     195             : uint8_t          umb_uuid_context_internet[] = MBIM_UUID_CONTEXT_INTERNET;
     196             : uint8_t          umb_uuid_qmi_mbim[] = MBIM_UUID_QMI_MBIM;
     197             : uint32_t         umb_session_id = 0;
     198             : 
     199             : struct cfdriver umb_cd = {
     200             :         NULL, "umb", DV_DULL
     201             : };
     202             : 
     203             : const struct cfattach umb_ca = {
     204             :         sizeof (struct umb_softc),
     205             :         umb_match,
     206             :         umb_attach,
     207             :         umb_detach,
     208             :         NULL,
     209             : };
     210             : 
     211             : int umb_delay = 4000;
     212             : 
     213             : /*
     214             :  * These devices require an "FCC Authentication" command.
     215             :  */
     216             : const struct usb_devno umb_fccauth_devs[] = {
     217             :         { USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_EM7455 },
     218             : };
     219             : 
     220             : uint8_t umb_qmi_alloc_cid[] = {
     221             :         0x01,
     222             :         0x0f, 0x00,             /* len */
     223             :         0x00,                   /* QMUX flags */
     224             :         0x00,                   /* service "ctl" */
     225             :         0x00,                   /* CID */
     226             :         0x00,                   /* QMI flags */
     227             :         0x01,                   /* transaction */
     228             :         0x22, 0x00,             /* msg "Allocate CID" */
     229             :         0x04, 0x00,             /* TLV len */
     230             :         0x01, 0x01, 0x00, 0x02  /* TLV */
     231             : };
     232             : 
     233             : uint8_t umb_qmi_fcc_auth[] = {
     234             :         0x01,
     235             :         0x0c, 0x00,             /* len */
     236             :         0x00,                   /* QMUX flags */
     237             :         0x02,                   /* service "dms" */
     238             : #define UMB_QMI_CID_OFFS        5
     239             :         0x00,                   /* CID (filled in later) */
     240             :         0x00,                   /* QMI flags */
     241             :         0x01, 0x00,             /* transaction */
     242             :         0x5f, 0x55,             /* msg "Send FCC Authentication" */
     243             :         0x00, 0x00              /* TLV len */
     244             : };
     245             : 
     246             : int
     247           0 : umb_match(struct device *parent, void *match, void *aux)
     248             : {
     249           0 :         struct usb_attach_arg *uaa = aux;
     250             :         usb_interface_descriptor_t *id;
     251             : 
     252           0 :         if (!uaa->iface)
     253           0 :                 return UMATCH_NONE;
     254           0 :         if ((id = usbd_get_interface_descriptor(uaa->iface)) == NULL)
     255           0 :                 return UMATCH_NONE;
     256             : 
     257             :         /*
     258             :          * If this function implements NCM, check if alternate setting
     259             :          * 1 implements MBIM.
     260             :          */
     261           0 :         if (id->bInterfaceClass == UICLASS_CDC &&
     262           0 :             id->bInterfaceSubClass ==
     263             :             UISUBCLASS_NETWORK_CONTROL_MODEL)
     264           0 :                 id = usbd_find_idesc(uaa->device->cdesc, uaa->iface->index, 1);
     265           0 :         if (id == NULL)
     266           0 :                 return UMATCH_NONE;
     267             : 
     268           0 :         if (id->bInterfaceClass == UICLASS_CDC &&
     269           0 :             id->bInterfaceSubClass ==
     270           0 :             UISUBCLASS_MOBILE_BROADBAND_INTERFACE_MODEL &&
     271           0 :             id->bInterfaceProtocol == 0)
     272           0 :                 return UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO;
     273             : 
     274           0 :         return UMATCH_NONE;
     275           0 : }
     276             : 
     277             : void
     278           0 : umb_attach(struct device *parent, struct device *self, void *aux)
     279             : {
     280           0 :         struct umb_softc *sc = (struct umb_softc *)self;
     281           0 :         struct usb_attach_arg *uaa = aux;
     282             :         usbd_status status;
     283           0 :         struct usbd_desc_iter iter;
     284             :         const usb_descriptor_t *desc;
     285             :         int      v;
     286             :         struct usb_cdc_union_descriptor *ud;
     287             :         struct mbim_descriptor *md;
     288             :         int      i;
     289             :         int      ctrl_ep;
     290             :         usb_interface_descriptor_t *id;
     291             :         usb_config_descriptor_t *cd;
     292             :         usb_endpoint_descriptor_t *ed;
     293             :         usb_interface_assoc_descriptor_t *ad;
     294             :         int      current_ifaceno = -1;
     295             :         int      data_ifaceno = -1;
     296             :         int      altnum;
     297             :         int      s;
     298             :         struct ifnet *ifp;
     299             : 
     300           0 :         sc->sc_udev = uaa->device;
     301           0 :         sc->sc_ctrl_ifaceno = uaa->ifaceno;
     302           0 :         ml_init(&sc->sc_tx_ml);
     303             : 
     304             :         /*
     305             :          * Some MBIM hardware does not provide the mandatory CDC Union
     306             :          * Descriptor, so we also look at matching Interface
     307             :          * Association Descriptors to find out the MBIM Data Interface
     308             :          * number.
     309             :          */
     310           0 :         sc->sc_ver_maj = sc->sc_ver_min = -1;
     311           0 :         sc->sc_maxpktlen = MBIM_MAXSEGSZ_MINVAL;
     312           0 :         usbd_desc_iter_init(sc->sc_udev, &iter);
     313           0 :         while ((desc = usbd_desc_iter_next(&iter))) {
     314           0 :                 if (desc->bDescriptorType == UDESC_IFACE_ASSOC) {
     315           0 :                         ad = (usb_interface_assoc_descriptor_t *)desc;
     316           0 :                         if (ad->bFirstInterface == uaa->ifaceno &&
     317           0 :                             ad->bInterfaceCount > 1)
     318           0 :                                 data_ifaceno = uaa->ifaceno + 1;
     319           0 :                         continue;
     320             :                 }
     321           0 :                 if (desc->bDescriptorType == UDESC_INTERFACE) {
     322           0 :                         id = (usb_interface_descriptor_t *)desc;
     323           0 :                         current_ifaceno = id->bInterfaceNumber;
     324           0 :                         continue;
     325             :                 }
     326           0 :                 if (current_ifaceno != uaa->ifaceno)
     327           0 :                         continue;
     328           0 :                 if (desc->bDescriptorType != UDESC_CS_INTERFACE)
     329           0 :                         continue;
     330           0 :                 switch (desc->bDescriptorSubtype) {
     331             :                 case UDESCSUB_CDC_UNION:
     332           0 :                         ud = (struct usb_cdc_union_descriptor *)desc;
     333           0 :                         data_ifaceno = ud->bSlaveInterface[0];
     334           0 :                         break;
     335             :                 case UDESCSUB_MBIM:
     336           0 :                         md = (struct mbim_descriptor *)desc;
     337           0 :                         v = UGETW(md->bcdMBIMVersion);
     338           0 :                         sc->sc_ver_maj = MBIM_VER_MAJOR(v);
     339           0 :                         sc->sc_ver_min = MBIM_VER_MINOR(v);
     340           0 :                         sc->sc_ctrl_len = UGETW(md->wMaxControlMessage);
     341             :                         /* Never trust a USB device! Could try to exploit us */
     342             :                         if (sc->sc_ctrl_len < MBIM_CTRLMSG_MINLEN ||
     343             :                             sc->sc_ctrl_len > MBIM_CTRLMSG_MAXLEN) {
     344             :                                 DPRINTF("%s: control message len %d out of "
     345             :                                     "bounds [%d .. %d]\n", DEVNAM(sc),
     346             :                                     sc->sc_ctrl_len, MBIM_CTRLMSG_MINLEN,
     347             :                                     MBIM_CTRLMSG_MAXLEN);
     348             :                                 /* cont. anyway */
     349             :                         }
     350           0 :                         sc->sc_maxpktlen = UGETW(md->wMaxSegmentSize);
     351             :                         DPRINTFN(2, "%s: ctrl_len=%d, maxpktlen=%d, cap=0x%x\n",
     352             :                             DEVNAM(sc), sc->sc_ctrl_len, sc->sc_maxpktlen,
     353             :                             md->bmNetworkCapabilities);
     354           0 :                         break;
     355             :                 default:
     356             :                         break;
     357             :                 }
     358             :         }
     359           0 :         if (sc->sc_ver_maj < 0) {
     360           0 :                 printf("%s: missing MBIM descriptor\n", DEVNAM(sc));
     361           0 :                 goto fail;
     362             :         }
     363           0 :         if (usb_lookup(umb_fccauth_devs, uaa->vendor, uaa->product)) {
     364           0 :                 sc->sc_flags |= UMBFLG_FCC_AUTH_REQUIRED;
     365           0 :                 sc->sc_cid = -1;
     366           0 :         }
     367             : 
     368           0 :         for (i = 0; i < uaa->nifaces; i++) {
     369           0 :                 if (usbd_iface_claimed(sc->sc_udev, i))
     370             :                         continue;
     371           0 :                 id = usbd_get_interface_descriptor(uaa->ifaces[i]);
     372           0 :                 if (id != NULL && id->bInterfaceNumber == data_ifaceno) {
     373           0 :                         sc->sc_data_iface = uaa->ifaces[i];
     374           0 :                         usbd_claim_iface(sc->sc_udev, i);
     375           0 :                 }
     376             :         }
     377           0 :         if (sc->sc_data_iface == NULL) {
     378           0 :                 printf("%s: no data interface found\n", DEVNAM(sc));
     379           0 :                 goto fail;
     380             :         }
     381             : 
     382             :         /*
     383             :          * If this is a combined NCM/MBIM function, switch to
     384             :          * alternate setting one to enable MBIM.
     385             :          */
     386           0 :         id = usbd_get_interface_descriptor(uaa->iface);
     387           0 :         if (id->bInterfaceClass == UICLASS_CDC &&
     388           0 :             id->bInterfaceSubClass ==
     389             :             UISUBCLASS_NETWORK_CONTROL_MODEL)
     390           0 :                 usbd_set_interface(uaa->iface, 1);
     391             : 
     392           0 :         id = usbd_get_interface_descriptor(uaa->iface);
     393             :         ctrl_ep = -1;
     394           0 :         for (i = 0; i < id->bNumEndpoints && ctrl_ep == -1; i++) {
     395           0 :                 ed = usbd_interface2endpoint_descriptor(uaa->iface, i);
     396           0 :                 if (ed == NULL)
     397             :                         break;
     398           0 :                 if (UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT &&
     399           0 :                     UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN)
     400           0 :                         ctrl_ep = ed->bEndpointAddress;
     401             :         }
     402           0 :         if (ctrl_ep == -1) {
     403           0 :                 printf("%s: missing interrupt endpoint\n", DEVNAM(sc));
     404           0 :                 goto fail;
     405             :         }
     406             : 
     407             :         /*
     408             :          * For the MBIM Data Interface, select the appropriate
     409             :          * alternate setting by looking for a matching descriptor that
     410             :          * has two endpoints.
     411             :          */
     412           0 :         cd = usbd_get_config_descriptor(sc->sc_udev);
     413           0 :         altnum = usbd_get_no_alts(cd, data_ifaceno);
     414           0 :         for (i = 0; i < altnum; i++) {
     415           0 :                 id = usbd_find_idesc(cd, sc->sc_data_iface->index, i);
     416           0 :                 if (id == NULL)
     417             :                         continue;
     418           0 :                 if (id->bInterfaceClass == UICLASS_CDC_DATA &&
     419           0 :                     id->bInterfaceSubClass == UISUBCLASS_DATA &&
     420           0 :                     id->bInterfaceProtocol == UIPROTO_DATA_MBIM &&
     421           0 :                     id->bNumEndpoints == 2)
     422             :                         break;
     423             :         }
     424           0 :         if (i == altnum || id == NULL) {
     425           0 :                 printf("%s: missing alt setting for interface #%d\n",
     426           0 :                     DEVNAM(sc), data_ifaceno);
     427           0 :                 goto fail;
     428             :         }
     429           0 :         status = usbd_set_interface(sc->sc_data_iface, i);
     430           0 :         if (status) {
     431           0 :                 printf("%s: select alt setting %d for interface #%d "
     432           0 :                     "failed: %s\n", DEVNAM(sc), i, data_ifaceno,
     433           0 :                     usbd_errstr(status));
     434           0 :                 goto fail;
     435             :         }
     436             : 
     437           0 :         id = usbd_get_interface_descriptor(sc->sc_data_iface);
     438           0 :         sc->sc_rx_ep = sc->sc_tx_ep = -1;
     439           0 :         for (i = 0; i < id->bNumEndpoints; i++) {
     440           0 :                 if ((ed = usbd_interface2endpoint_descriptor(sc->sc_data_iface,
     441           0 :                     i)) == NULL)
     442             :                         break;
     443           0 :                 if (UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK &&
     444           0 :                     UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN)
     445           0 :                         sc->sc_rx_ep = ed->bEndpointAddress;
     446           0 :                 else if (UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK &&
     447           0 :                     UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT)
     448           0 :                         sc->sc_tx_ep = ed->bEndpointAddress;
     449             :         }
     450           0 :         if (sc->sc_rx_ep == -1 || sc->sc_tx_ep == -1) {
     451           0 :                 printf("%s: missing bulk endpoints\n", DEVNAM(sc));
     452           0 :                 goto fail;
     453             :         }
     454             : 
     455             :         DPRINTFN(2, "%s: ctrl-ifno#%d: ep-ctrl=%d, data-ifno#%d: ep-rx=%d, "
     456             :             "ep-tx=%d\n", DEVNAM(sc), sc->sc_ctrl_ifaceno,
     457             :             UE_GET_ADDR(ctrl_ep), data_ifaceno,
     458             :             UE_GET_ADDR(sc->sc_rx_ep), UE_GET_ADDR(sc->sc_tx_ep));
     459             : 
     460           0 :         usb_init_task(&sc->sc_umb_task, umb_state_task, sc,
     461             :             USB_TASK_TYPE_GENERIC);
     462           0 :         usb_init_task(&sc->sc_get_response_task, umb_get_response_task, sc,
     463             :             USB_TASK_TYPE_GENERIC);
     464           0 :         timeout_set(&sc->sc_statechg_timer, umb_statechg_timeout, sc);
     465             : 
     466           0 :         if (usbd_open_pipe_intr(uaa->iface, ctrl_ep, USBD_SHORT_XFER_OK,
     467           0 :             &sc->sc_ctrl_pipe, sc, &sc->sc_intr_msg, sizeof (sc->sc_intr_msg),
     468             :             umb_intr, USBD_DEFAULT_INTERVAL)) {
     469           0 :                 printf("%s: failed to open control pipe\n", DEVNAM(sc));
     470           0 :                 goto fail;
     471             :         }
     472           0 :         sc->sc_resp_buf = malloc(sc->sc_ctrl_len, M_USBDEV, M_NOWAIT);
     473           0 :         if (sc->sc_resp_buf == NULL) {
     474           0 :                 printf("%s: allocation of resp buffer failed\n", DEVNAM(sc));
     475           0 :                 goto fail;
     476             :         }
     477           0 :         sc->sc_ctrl_msg = malloc(sc->sc_ctrl_len, M_USBDEV, M_NOWAIT);
     478           0 :         if (sc->sc_ctrl_msg == NULL) {
     479           0 :                 printf("%s: allocation of ctrl msg buffer failed\n",
     480           0 :                     DEVNAM(sc));
     481           0 :                 goto fail;
     482             :         }
     483             : 
     484           0 :         sc->sc_info.regstate = MBIM_REGSTATE_UNKNOWN;
     485           0 :         sc->sc_info.pin_attempts_left = UMB_VALUE_UNKNOWN;
     486           0 :         sc->sc_info.rssi = UMB_VALUE_UNKNOWN;
     487           0 :         sc->sc_info.ber = UMB_VALUE_UNKNOWN;
     488             : 
     489           0 :         umb_ncm_setup(sc);
     490             :         DPRINTFN(2, "%s: rx/tx size %d/%d\n", DEVNAM(sc),
     491             :             sc->sc_rx_bufsz, sc->sc_tx_bufsz);
     492             : 
     493           0 :         s = splnet();
     494           0 :         ifp = GET_IFP(sc);
     495           0 :         ifp->if_flags = IFF_SIMPLEX | IFF_MULTICAST | IFF_POINTOPOINT;
     496           0 :         ifp->if_ioctl = umb_ioctl;
     497           0 :         ifp->if_start = umb_start;
     498           0 :         ifp->if_rtrequest = p2p_rtrequest;
     499             : 
     500           0 :         ifp->if_watchdog = umb_watchdog;
     501           0 :         strlcpy(ifp->if_xname, DEVNAM(sc), IFNAMSIZ);
     502           0 :         ifp->if_link_state = LINK_STATE_DOWN;
     503             : 
     504           0 :         ifp->if_type = IFT_MBIM;
     505           0 :         ifp->if_addrlen = 0;
     506           0 :         ifp->if_hdrlen = sizeof (struct ncm_header16) +
     507             :             sizeof (struct ncm_pointer16);
     508           0 :         ifp->if_mtu = 1500;          /* use a common default */
     509           0 :         ifp->if_hardmtu = sc->sc_maxpktlen;
     510           0 :         ifp->if_output = umb_output;
     511           0 :         if_attach(ifp);
     512           0 :         if_ih_insert(ifp, umb_input, NULL);
     513           0 :         if_alloc_sadl(ifp);
     514           0 :         ifp->if_softc = sc;
     515             : #if NBPFILTER > 0
     516           0 :         bpfattach(&ifp->if_bpf, ifp, DLT_RAW, 0);
     517             : #endif
     518             :         /*
     519             :          * Open the device now so that we are able to query device information.
     520             :          * XXX maybe close when done?
     521             :          */
     522           0 :         umb_open(sc);
     523           0 :         splx(s);
     524             : 
     525             :         DPRINTF("%s: vers %d.%d\n", DEVNAM(sc), sc->sc_ver_maj, sc->sc_ver_min);
     526           0 :         return;
     527             : 
     528             : fail:
     529           0 :         usbd_deactivate(sc->sc_udev);
     530           0 :         return;
     531           0 : }
     532             : 
     533             : int
     534           0 : umb_detach(struct device *self, int flags)
     535             : {
     536           0 :         struct umb_softc *sc = (struct umb_softc *)self;
     537           0 :         struct ifnet *ifp = GET_IFP(sc);
     538             :         int      s;
     539             : 
     540           0 :         s = splnet();
     541           0 :         if (ifp->if_flags & IFF_RUNNING)
     542           0 :                 umb_down(sc, 1);
     543           0 :         umb_close(sc);
     544             : 
     545           0 :         usb_rem_wait_task(sc->sc_udev, &sc->sc_get_response_task);
     546           0 :         if (timeout_initialized(&sc->sc_statechg_timer))
     547           0 :                 timeout_del(&sc->sc_statechg_timer);
     548           0 :         sc->sc_nresp = 0;
     549           0 :         usb_rem_wait_task(sc->sc_udev, &sc->sc_umb_task);
     550           0 :         if (sc->sc_ctrl_pipe) {
     551           0 :                 usbd_close_pipe(sc->sc_ctrl_pipe);
     552           0 :                 sc->sc_ctrl_pipe = NULL;
     553           0 :         }
     554           0 :         if (sc->sc_ctrl_msg) {
     555           0 :                 free(sc->sc_ctrl_msg, M_USBDEV, sc->sc_ctrl_len);
     556           0 :                 sc->sc_ctrl_msg = NULL;
     557           0 :         }
     558           0 :         if (sc->sc_resp_buf) {
     559           0 :                 free(sc->sc_resp_buf, M_USBDEV, sc->sc_ctrl_len);
     560           0 :                 sc->sc_resp_buf = NULL;
     561           0 :         }
     562           0 :         if (ifp->if_softc != NULL) {
     563           0 :                 if_ih_remove(ifp, umb_input, NULL);
     564           0 :                 if_detach(ifp);
     565           0 :         }
     566             : 
     567           0 :         splx(s);
     568           0 :         return 0;
     569             : }
     570             : 
     571             : void
     572           0 : umb_ncm_setup(struct umb_softc *sc)
     573             : {
     574           0 :         usb_device_request_t req;
     575           0 :         struct ncm_ntb_parameters np;
     576             : 
     577             :         /* Query NTB tranfers sizes */
     578           0 :         req.bmRequestType = UT_READ_CLASS_INTERFACE;
     579           0 :         req.bRequest = NCM_GET_NTB_PARAMETERS;
     580           0 :         USETW(req.wValue, 0);
     581           0 :         USETW(req.wIndex, sc->sc_ctrl_ifaceno);
     582           0 :         USETW(req.wLength, sizeof (np));
     583           0 :         if (usbd_do_request(sc->sc_udev, &req, &np) == USBD_NORMAL_COMPLETION &&
     584           0 :             UGETW(np.wLength) == sizeof (np)) {
     585           0 :                 sc->sc_rx_bufsz = UGETDW(np.dwNtbInMaxSize);
     586           0 :                 sc->sc_tx_bufsz = UGETDW(np.dwNtbOutMaxSize);
     587           0 :                 sc->sc_maxdgram = UGETW(np.wNtbOutMaxDatagrams);
     588           0 :                 sc->sc_align = UGETW(np.wNdpOutAlignment);
     589           0 :                 sc->sc_ndp_div = UGETW(np.wNdpOutDivisor);
     590           0 :                 sc->sc_ndp_remainder = UGETW(np.wNdpOutPayloadRemainder);
     591             :                 /* Validate values */
     592           0 :                 if (!powerof2(sc->sc_align) || sc->sc_align == 0 ||
     593           0 :                     sc->sc_align >= sc->sc_tx_bufsz)
     594           0 :                         sc->sc_align = sizeof (uint32_t);
     595           0 :                 if (!powerof2(sc->sc_ndp_div) || sc->sc_ndp_div == 0 ||
     596           0 :                     sc->sc_ndp_div >= sc->sc_tx_bufsz)
     597           0 :                         sc->sc_ndp_div = sizeof (uint32_t);
     598           0 :                 if (sc->sc_ndp_remainder >= sc->sc_ndp_div)
     599           0 :                         sc->sc_ndp_remainder = 0;
     600             :         } else {
     601           0 :                 sc->sc_rx_bufsz = sc->sc_tx_bufsz = 8 * 1024;
     602           0 :                 sc->sc_maxdgram = 0;
     603           0 :                 sc->sc_align = sc->sc_ndp_div = sizeof (uint32_t);
     604           0 :                 sc->sc_ndp_remainder = 0;
     605             :         }
     606           0 : }
     607             : 
     608             : int
     609           0 : umb_alloc_xfers(struct umb_softc *sc)
     610             : {
     611           0 :         if (!sc->sc_rx_xfer) {
     612           0 :                 if ((sc->sc_rx_xfer = usbd_alloc_xfer(sc->sc_udev)) != NULL)
     613           0 :                         sc->sc_rx_buf = usbd_alloc_buffer(sc->sc_rx_xfer,
     614           0 :                             sc->sc_rx_bufsz);
     615             :         }
     616           0 :         if (!sc->sc_tx_xfer) {
     617           0 :                 if ((sc->sc_tx_xfer = usbd_alloc_xfer(sc->sc_udev)) != NULL)
     618           0 :                         sc->sc_tx_buf = usbd_alloc_buffer(sc->sc_tx_xfer,
     619           0 :                             sc->sc_tx_bufsz);
     620             :         }
     621           0 :         return (sc->sc_rx_buf && sc->sc_tx_buf) ? 1 : 0;
     622             : }
     623             : 
     624             : void
     625           0 : umb_free_xfers(struct umb_softc *sc)
     626             : {
     627           0 :         if (sc->sc_rx_xfer) {
     628             :                 /* implicit usbd_free_buffer() */
     629           0 :                 usbd_free_xfer(sc->sc_rx_xfer);
     630           0 :                 sc->sc_rx_xfer = NULL;
     631           0 :                 sc->sc_rx_buf = NULL;
     632           0 :         }
     633           0 :         if (sc->sc_tx_xfer) {
     634           0 :                 usbd_free_xfer(sc->sc_tx_xfer);
     635           0 :                 sc->sc_tx_xfer = NULL;
     636           0 :                 sc->sc_tx_buf = NULL;
     637           0 :         }
     638           0 :         ml_purge(&sc->sc_tx_ml);
     639           0 : }
     640             : 
     641             : int
     642           0 : umb_alloc_bulkpipes(struct umb_softc *sc)
     643             : {
     644           0 :         struct ifnet *ifp = GET_IFP(sc);
     645             : 
     646           0 :         if (!(ifp->if_flags & IFF_RUNNING)) {
     647           0 :                 if (usbd_open_pipe(sc->sc_data_iface, sc->sc_rx_ep,
     648           0 :                     USBD_EXCLUSIVE_USE, &sc->sc_rx_pipe))
     649           0 :                         return 0;
     650           0 :                 if (usbd_open_pipe(sc->sc_data_iface, sc->sc_tx_ep,
     651           0 :                     USBD_EXCLUSIVE_USE, &sc->sc_tx_pipe))
     652           0 :                         return 0;
     653             : 
     654           0 :                 ifp->if_flags |= IFF_RUNNING;
     655           0 :                 ifq_clr_oactive(&ifp->if_snd);
     656           0 :                 umb_rx(sc);
     657           0 :         }
     658           0 :         return 1;
     659           0 : }
     660             : 
     661             : void
     662           0 : umb_close_bulkpipes(struct umb_softc *sc)
     663             : {
     664           0 :         struct ifnet *ifp = GET_IFP(sc);
     665             : 
     666           0 :         ifp->if_flags &= ~IFF_RUNNING;
     667           0 :         ifq_clr_oactive(&ifp->if_snd);
     668           0 :         ifp->if_timer = 0;
     669           0 :         if (sc->sc_rx_pipe) {
     670           0 :                 usbd_close_pipe(sc->sc_rx_pipe);
     671           0 :                 sc->sc_rx_pipe = NULL;
     672           0 :         }
     673           0 :         if (sc->sc_tx_pipe) {
     674           0 :                 usbd_close_pipe(sc->sc_tx_pipe);
     675           0 :                 sc->sc_tx_pipe = NULL;
     676           0 :         }
     677           0 : }
     678             : 
     679             : int
     680           0 : umb_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
     681             : {
     682           0 :         struct proc *p = curproc;
     683           0 :         struct umb_softc *sc = ifp->if_softc;
     684           0 :         struct ifreq *ifr = (struct ifreq *)data;
     685             :         int      s, error = 0;
     686           0 :         struct umb_parameter mp;
     687             : 
     688           0 :         if (usbd_is_dying(sc->sc_udev))
     689           0 :                 return EIO;
     690             : 
     691           0 :         s = splnet();
     692           0 :         switch (cmd) {
     693             :         case SIOCSIFFLAGS:
     694           0 :                 usb_add_task(sc->sc_udev, &sc->sc_umb_task);
     695           0 :                 break;
     696             :         case SIOCGUMBINFO:
     697           0 :                 error = copyout(&sc->sc_info, ifr->ifr_data,
     698             :                     sizeof (sc->sc_info));
     699           0 :                 break;
     700             :         case SIOCSUMBPARAM:
     701           0 :                 if ((error = suser(p)) != 0)
     702             :                         break;
     703           0 :                 if ((error = copyin(ifr->ifr_data, &mp, sizeof (mp))) != 0)
     704             :                         break;
     705             : 
     706           0 :                 if ((error = umb_setpin(sc, mp.op, mp.is_puk, mp.pin, mp.pinlen,
     707           0 :                     mp.newpin, mp.newpinlen)) != 0)
     708             :                         break;
     709             : 
     710           0 :                 if (mp.apnlen < 0 || mp.apnlen > sizeof (sc->sc_info.apn)) {
     711             :                         error = EINVAL;
     712           0 :                         break;
     713             :                 }
     714           0 :                 sc->sc_roaming = mp.roaming ? 1 : 0;
     715           0 :                 memset(sc->sc_info.apn, 0, sizeof (sc->sc_info.apn));
     716           0 :                 memcpy(sc->sc_info.apn, mp.apn, mp.apnlen);
     717           0 :                 sc->sc_info.apnlen = mp.apnlen;
     718           0 :                 sc->sc_info.preferredclasses = mp.preferredclasses;
     719           0 :                 umb_setdataclass(sc);
     720           0 :                 break;
     721             :         case SIOCGUMBPARAM:
     722           0 :                 memset(&mp, 0, sizeof (mp));
     723           0 :                 memcpy(mp.apn, sc->sc_info.apn, sc->sc_info.apnlen);
     724           0 :                 mp.apnlen = sc->sc_info.apnlen;
     725           0 :                 mp.roaming = sc->sc_roaming;
     726           0 :                 mp.preferredclasses = sc->sc_info.preferredclasses;
     727           0 :                 error = copyout(&mp, ifr->ifr_data, sizeof (mp));
     728           0 :                 break;
     729             :         case SIOCSIFMTU:
     730             :                 /* Does this include the NCM headers and tail? */
     731           0 :                 if (ifr->ifr_mtu > ifp->if_hardmtu) {
     732             :                         error = EINVAL;
     733           0 :                         break;
     734             :                 }
     735           0 :                 ifp->if_mtu = ifr->ifr_mtu;
     736           0 :                 break;
     737             :         case SIOCSIFADDR:
     738             :         case SIOCAIFADDR:
     739             :         case SIOCSIFDSTADDR:
     740             :         case SIOCADDMULTI:
     741             :         case SIOCDELMULTI:
     742             :                 break;
     743             :         default:
     744             :                 error = ENOTTY;
     745           0 :                 break;
     746             :         }
     747           0 :         splx(s);
     748           0 :         return error;
     749           0 : }
     750             : 
     751             : int
     752           0 : umb_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
     753             :     struct rtentry *rtp)
     754             : {
     755           0 :         if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
     756           0 :                 m_freem(m);
     757           0 :                 return ENETDOWN;
     758             :         }
     759           0 :         return if_enqueue(ifp, m);
     760           0 : }
     761             : 
     762             : int
     763           0 : umb_input(struct ifnet *ifp, struct mbuf *m, void *cookie)
     764             : {
     765           0 :         uint8_t ipv;
     766             : 
     767           0 :         if ((ifp->if_flags & IFF_UP) == 0) {
     768           0 :                 m_freem(m);
     769           0 :                 return 1;
     770             :         }
     771           0 :         if (m->m_pkthdr.len < sizeof (struct ip)) {
     772           0 :                 ifp->if_ierrors++;
     773             :                 DPRINTFN(4, "%s: dropping short packet (len %d)\n", __func__,
     774             :                     m->m_pkthdr.len);
     775           0 :                 m_freem(m);
     776           0 :                 return 1;
     777             :         }
     778           0 :         m->m_pkthdr.ph_rtableid = ifp->if_rdomain;
     779           0 :         m_copydata(m, 0, sizeof (ipv), &ipv);
     780           0 :         ipv >>= 4;
     781             : 
     782           0 :         ifp->if_ibytes += m->m_pkthdr.len;
     783           0 :         switch (ipv) {
     784             :         case 4:
     785           0 :                 ipv4_input(ifp, m);
     786           0 :                 return 1;
     787             : #ifdef INET6
     788             :         case 6:
     789           0 :                 ipv6_input(ifp, m);
     790           0 :                 return 1;
     791             : #endif /* INET6 */
     792             :         default:
     793           0 :                 ifp->if_ierrors++;
     794             :                 DPRINTFN(4, "%s: dropping packet with bad IP version (%d)\n",
     795             :                     __func__, ipv);
     796           0 :                 m_freem(m);
     797           0 :                 return 1;
     798             :         }
     799             :         return 1;
     800           0 : }
     801             : 
     802             : static inline int
     803           0 : umb_align(size_t bufsz, int offs, int alignment, int remainder)
     804             : {
     805           0 :         size_t   m = alignment - 1;
     806             :         int      align;
     807             : 
     808           0 :         align = (((size_t)offs + m) & ~m) - alignment + remainder;
     809           0 :         if (align < offs)
     810           0 :                 align += alignment;
     811           0 :         if (align > bufsz)
     812           0 :                 align = bufsz;
     813           0 :         return align - offs;
     814             : }
     815             : 
     816             : static inline int
     817           0 : umb_padding(void *buf, size_t bufsz, int offs, int alignment, int remainder)
     818             : {
     819             :         int      nb;
     820             : 
     821           0 :         nb = umb_align(bufsz, offs, alignment, remainder);
     822           0 :         if (nb > 0)
     823           0 :                 memset(buf + offs, 0, nb);
     824           0 :         return nb;
     825             : }
     826             : 
     827             : void
     828           0 : umb_start(struct ifnet *ifp)
     829             : {
     830           0 :         struct umb_softc *sc = ifp->if_softc;
     831             :         struct mbuf *m = NULL;
     832             :         int      ndgram = 0;
     833             :         int      offs, plen, len, mlen;
     834             :         int      maxalign;
     835             : 
     836           0 :         if (usbd_is_dying(sc->sc_udev) ||
     837           0 :             !(ifp->if_flags & IFF_RUNNING) ||
     838           0 :             ifq_is_oactive(&ifp->if_snd))
     839           0 :                 return;
     840             : 
     841           0 :         KASSERT(ml_empty(&sc->sc_tx_ml));
     842             : 
     843             :         offs = sizeof (struct ncm_header16);
     844           0 :         offs += umb_align(sc->sc_tx_bufsz, offs, sc->sc_align, 0);
     845             : 
     846             :         /*
     847             :          * Note that 'struct ncm_pointer16' already includes space for the
     848             :          * terminating zero pointer.
     849             :          */
     850           0 :         offs += sizeof (struct ncm_pointer16);
     851             :         plen = sizeof (struct ncm_pointer16_dgram);
     852           0 :         maxalign = (sc->sc_ndp_div - 1) + sc->sc_ndp_remainder;
     853             :         len = 0;
     854           0 :         while (1) {
     855           0 :                 m = ifq_deq_begin(&ifp->if_snd);
     856           0 :                 if (m == NULL)
     857             :                         break;
     858             : 
     859             :                 /*
     860             :                  * Check if mbuf plus required NCM pointer still fits into
     861             :                  * xfer buffers. Assume maximal padding.
     862             :                  */
     863           0 :                 plen += sizeof (struct ncm_pointer16_dgram);
     864           0 :                 mlen = maxalign +  m->m_pkthdr.len;
     865           0 :                 if ((sc->sc_maxdgram != 0 && ndgram >= sc->sc_maxdgram) ||
     866           0 :                     (offs + plen + len + mlen > sc->sc_tx_bufsz)) {
     867           0 :                         ifq_deq_rollback(&ifp->if_snd, m);
     868           0 :                         break;
     869             :                 }
     870           0 :                 ifq_deq_commit(&ifp->if_snd, m);
     871             : 
     872           0 :                 ndgram++;
     873           0 :                 len += mlen;
     874           0 :                 ml_enqueue(&sc->sc_tx_ml, m);
     875             : 
     876             : #if NBPFILTER > 0
     877           0 :                 if (ifp->if_bpf)
     878           0 :                         bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
     879             : #endif
     880             :         }
     881           0 :         if (ml_empty(&sc->sc_tx_ml))
     882           0 :                 return;
     883           0 :         if (umb_encap(sc)) {
     884           0 :                 ifq_set_oactive(&ifp->if_snd);
     885           0 :                 ifp->if_timer = (2 * umb_xfer_tout) / 1000;
     886           0 :         }
     887           0 : }
     888             : 
     889             : void
     890           0 : umb_watchdog(struct ifnet *ifp)
     891             : {
     892           0 :         struct umb_softc *sc = ifp->if_softc;
     893             : 
     894           0 :         if (usbd_is_dying(sc->sc_udev))
     895           0 :                 return;
     896             : 
     897           0 :         ifp->if_oerrors++;
     898           0 :         printf("%s: watchdog timeout\n", DEVNAM(sc));
     899           0 :         usbd_abort_pipe(sc->sc_tx_pipe);
     900           0 :         return;
     901           0 : }
     902             : 
     903             : void
     904           0 : umb_statechg_timeout(void *arg)
     905             : {
     906           0 :         struct umb_softc *sc = arg;
     907             : 
     908           0 :         if (sc->sc_info.regstate != MBIM_REGSTATE_ROAMING || sc->sc_roaming)
     909           0 :                 printf("%s: state change timeout\n",DEVNAM(sc));
     910           0 :         usb_add_task(sc->sc_udev, &sc->sc_umb_task);
     911           0 : }
     912             : 
     913             : void
     914           0 : umb_newstate(struct umb_softc *sc, enum umb_state newstate, int flags)
     915             : {
     916           0 :         struct ifnet *ifp = GET_IFP(sc);
     917             : 
     918           0 :         if (newstate == sc->sc_state)
     919           0 :                 return;
     920           0 :         if (((flags & UMB_NS_DONT_DROP) && newstate < sc->sc_state) ||
     921           0 :             ((flags & UMB_NS_DONT_RAISE) && newstate > sc->sc_state))
     922           0 :                 return;
     923           0 :         if (ifp->if_flags & IFF_DEBUG)
     924           0 :                 log(LOG_DEBUG, "%s: state going %s from '%s' to '%s'\n",
     925           0 :                     DEVNAM(sc), newstate > sc->sc_state ? "up" : "down",
     926           0 :                     umb_istate(sc->sc_state), umb_istate(newstate));
     927           0 :         sc->sc_state = newstate;
     928           0 :         usb_add_task(sc->sc_udev, &sc->sc_umb_task);
     929           0 : }
     930             : 
     931             : void
     932           0 : umb_state_task(void *arg)
     933             : {
     934           0 :         struct umb_softc *sc = arg;
     935           0 :         struct ifnet *ifp = GET_IFP(sc);
     936           0 :         struct ifreq ifr;
     937           0 :         struct in_aliasreq ifra;
     938             :         int      s;
     939             :         int      state;
     940             : 
     941           0 :         if (sc->sc_info.regstate == MBIM_REGSTATE_ROAMING && !sc->sc_roaming) {
     942             :                 /*
     943             :                  * Query the registration state until we're with the home
     944             :                  * network again.
     945             :                  */
     946           0 :                 umb_cmd(sc, MBIM_CID_REGISTER_STATE, MBIM_CMDOP_QRY, NULL, 0);
     947           0 :                 return;
     948             :         }
     949             : 
     950           0 :         s = splnet();
     951           0 :         if (ifp->if_flags & IFF_UP)
     952           0 :                 umb_up(sc);
     953             :         else
     954           0 :                 umb_down(sc, 0);
     955             : 
     956           0 :         state = sc->sc_state == UMB_S_UP ? LINK_STATE_UP : LINK_STATE_DOWN;
     957           0 :         if (ifp->if_link_state != state) {
     958           0 :                 if (ifp->if_flags & IFF_DEBUG)
     959           0 :                         log(LOG_DEBUG, "%s: link state changed from %s to %s\n",
     960           0 :                             DEVNAM(sc),
     961           0 :                             LINK_STATE_IS_UP(ifp->if_link_state)
     962             :                             ? "up" : "down",
     963           0 :                             LINK_STATE_IS_UP(state) ? "up" : "down");
     964           0 :                 ifp->if_link_state = state;
     965           0 :                 if (!LINK_STATE_IS_UP(state)) {
     966             :                         /*
     967             :                          * Purge any existing addresses
     968             :                          */
     969           0 :                         memset(sc->sc_info.ipv4dns, 0,
     970             :                             sizeof (sc->sc_info.ipv4dns));
     971           0 :                         if (in_ioctl(SIOCGIFADDR, (caddr_t)&ifr, ifp, 1) == 0 &&
     972           0 :                             satosin(&ifr.ifr_addr)->sin_addr.s_addr !=
     973             :                             INADDR_ANY) {
     974           0 :                                 memset(&ifra, 0, sizeof (ifra));
     975           0 :                                 memcpy(&ifra.ifra_addr, &ifr.ifr_addr,
     976             :                                     sizeof (ifra.ifra_addr));
     977           0 :                                 in_ioctl(SIOCDIFADDR, (caddr_t)&ifra, ifp, 1);
     978           0 :                         }
     979             :                 }
     980           0 :                 if_link_state_change(ifp);
     981           0 :         }
     982           0 :         splx(s);
     983           0 : }
     984             : 
     985             : void
     986           0 : umb_up(struct umb_softc *sc)
     987             : {
     988           0 :         splassert(IPL_NET);
     989             : 
     990           0 :         switch (sc->sc_state) {
     991             :         case UMB_S_DOWN:
     992             :                 DPRINTF("%s: init: opening ...\n", DEVNAM(sc));
     993           0 :                 umb_open(sc);
     994           0 :                 break;
     995             :         case UMB_S_OPEN:
     996           0 :                 if (sc->sc_flags & UMBFLG_FCC_AUTH_REQUIRED) {
     997           0 :                         if (sc->sc_cid == -1) {
     998             :                                 DPRINTF("%s: init: allocating CID ...\n",
     999             :                                     DEVNAM(sc));
    1000           0 :                                 umb_allocate_cid(sc);
    1001           0 :                                 break;
    1002             :                         } else
    1003           0 :                                 umb_newstate(sc, UMB_S_CID, UMB_NS_DONT_DROP);
    1004             :                 } else {
    1005             :                         DPRINTF("%s: init: turning radio on ...\n", DEVNAM(sc));
    1006           0 :                         umb_radio(sc, 1);
    1007           0 :                         break;
    1008             :                 }
    1009             :                 /*FALLTHROUGH*/
    1010             :         case UMB_S_CID:
    1011             :                 DPRINTF("%s: init: sending FCC auth ...\n", DEVNAM(sc));
    1012           0 :                 umb_send_fcc_auth(sc);
    1013           0 :                 break;
    1014             :         case UMB_S_RADIO:
    1015             :                 DPRINTF("%s: init: checking SIM state ...\n", DEVNAM(sc));
    1016           0 :                 umb_cmd(sc, MBIM_CID_SUBSCRIBER_READY_STATUS, MBIM_CMDOP_QRY,
    1017             :                     NULL, 0);
    1018           0 :                 break;
    1019             :         case UMB_S_SIMREADY:
    1020             :                 DPRINTF("%s: init: attaching ...\n", DEVNAM(sc));
    1021           0 :                 umb_packet_service(sc, 1);
    1022           0 :                 break;
    1023             :         case UMB_S_ATTACHED:
    1024           0 :                 sc->sc_tx_seq = 0;
    1025           0 :                 if (!umb_alloc_xfers(sc)) {
    1026           0 :                         umb_free_xfers(sc);
    1027           0 :                         printf("%s: allocation of xfers failed\n", DEVNAM(sc));
    1028           0 :                         break;
    1029             :                 }
    1030             :                 DPRINTF("%s: init: connecting ...\n", DEVNAM(sc));
    1031           0 :                 umb_connect(sc);
    1032           0 :                 break;
    1033             :         case UMB_S_CONNECTED:
    1034             :                 DPRINTF("%s: init: getting IP config ...\n", DEVNAM(sc));
    1035           0 :                 umb_qry_ipconfig(sc);
    1036           0 :                 break;
    1037             :         case UMB_S_UP:
    1038             :                 DPRINTF("%s: init: reached state UP\n", DEVNAM(sc));
    1039           0 :                 if (!umb_alloc_bulkpipes(sc)) {
    1040           0 :                         printf("%s: opening bulk pipes failed\n", DEVNAM(sc));
    1041           0 :                         umb_down(sc, 1);
    1042           0 :                 }
    1043             :                 break;
    1044             :         }
    1045           0 :         if (sc->sc_state < UMB_S_UP)
    1046           0 :                 timeout_add_sec(&sc->sc_statechg_timer,
    1047             :                     UMB_STATE_CHANGE_TIMEOUT);
    1048             :         else
    1049           0 :                 timeout_del(&sc->sc_statechg_timer);
    1050           0 :         return;
    1051             : }
    1052             : 
    1053             : void
    1054           0 : umb_down(struct umb_softc *sc, int force)
    1055             : {
    1056           0 :         splassert(IPL_NET);
    1057             : 
    1058           0 :         umb_close_bulkpipes(sc);
    1059           0 :         if (sc->sc_state < UMB_S_CONNECTED)
    1060           0 :                 umb_free_xfers(sc);
    1061             : 
    1062           0 :         switch (sc->sc_state) {
    1063             :         case UMB_S_UP:
    1064             :         case UMB_S_CONNECTED:
    1065             :                 DPRINTF("%s: stop: disconnecting ...\n", DEVNAM(sc));
    1066           0 :                 umb_disconnect(sc);
    1067           0 :                 if (!force)
    1068             :                         break;
    1069             :                 /*FALLTHROUGH*/
    1070             :         case UMB_S_ATTACHED:
    1071             :                 DPRINTF("%s: stop: detaching ...\n", DEVNAM(sc));
    1072           0 :                 umb_packet_service(sc, 0);
    1073           0 :                 if (!force)
    1074             :                         break;
    1075             :                 /*FALLTHROUGH*/
    1076             :         case UMB_S_SIMREADY:
    1077             :         case UMB_S_RADIO:
    1078             :                 DPRINTF("%s: stop: turning radio off ...\n", DEVNAM(sc));
    1079           0 :                 umb_radio(sc, 0);
    1080           0 :                 if (!force)
    1081             :                         break;
    1082             :                 /*FALLTHROUGH*/
    1083             :         case UMB_S_CID:
    1084             :         case UMB_S_OPEN:
    1085             :         case UMB_S_DOWN:
    1086             :                 /* Do not close the device */
    1087             :                 DPRINTF("%s: stop: reached state DOWN\n", DEVNAM(sc));
    1088             :                 break;
    1089             :         }
    1090           0 :         if (force)
    1091           0 :                 sc->sc_state = UMB_S_OPEN;
    1092             : 
    1093           0 :         if (sc->sc_state > UMB_S_OPEN)
    1094           0 :                 timeout_add_sec(&sc->sc_statechg_timer,
    1095             :                     UMB_STATE_CHANGE_TIMEOUT);
    1096             :         else
    1097           0 :                 timeout_del(&sc->sc_statechg_timer);
    1098           0 : }
    1099             : 
    1100             : void
    1101           0 : umb_get_response_task(void *arg)
    1102             : {
    1103           0 :         struct umb_softc *sc = arg;
    1104           0 :         int      len;
    1105             :         int      s;
    1106             : 
    1107             :         /*
    1108             :          * Function is required to send on RESPONSE_AVAILABLE notification for
    1109             :          * each encapsulated response that is to be processed by the host.
    1110             :          * But of course, we can receive multiple notifications before the
    1111             :          * response task is run.
    1112             :          */
    1113           0 :         s = splusb();
    1114           0 :         while (sc->sc_nresp > 0) {
    1115           0 :                 --sc->sc_nresp;
    1116           0 :                 len = sc->sc_ctrl_len;
    1117           0 :                 if (umb_get_encap_response(sc, sc->sc_resp_buf, &len))
    1118           0 :                         umb_decode_response(sc, sc->sc_resp_buf, len);
    1119             :         }
    1120           0 :         splx(s);
    1121           0 : }
    1122             : 
    1123             : void
    1124           0 : umb_decode_response(struct umb_softc *sc, void *response, int len)
    1125             : {
    1126           0 :         struct mbim_msghdr *hdr = response;
    1127             :         struct mbim_fragmented_msg_hdr *fraghdr;
    1128             :         uint32_t type;
    1129             :         uint32_t tid;
    1130             : 
    1131             :         DPRINTFN(3, "%s: got response: len %d\n", DEVNAM(sc), len);
    1132             :         DDUMPN(4, response, len);
    1133             : 
    1134           0 :         if (len < sizeof (*hdr) || letoh32(hdr->len) != len) {
    1135             :                 /*
    1136             :                  * We should probably cancel a transaction, but since the
    1137             :                  * message is too short, we cannot decode the transaction
    1138             :                  * id (tid) and hence don't know, whom to cancel. Must wait
    1139             :                  * for the timeout.
    1140             :                  */
    1141             :                 DPRINTF("%s: received short response (len %d)\n",
    1142             :                     DEVNAM(sc), len);
    1143           0 :                 return;
    1144             :         }
    1145             : 
    1146             :         /*
    1147             :          * XXX FIXME: if message is fragmented, store it until last frag
    1148             :          *      is received and then re-assemble all fragments.
    1149             :          */
    1150           0 :         type = letoh32(hdr->type);
    1151           0 :         tid = letoh32(hdr->tid);
    1152           0 :         switch (type) {
    1153             :         case MBIM_INDICATE_STATUS_MSG:
    1154             :         case MBIM_COMMAND_DONE:
    1155           0 :                 fraghdr = response;
    1156           0 :                 if (letoh32(fraghdr->frag.nfrag) != 1) {
    1157             :                         DPRINTF("%s: discarding fragmented messages\n",
    1158             :                             DEVNAM(sc));
    1159           0 :                         return;
    1160             :                 }
    1161             :                 break;
    1162             :         default:
    1163             :                 break;
    1164             :         }
    1165             : 
    1166             :         DPRINTF("%s: <- rcv %s (tid %u)\n", DEVNAM(sc), umb_request2str(type),
    1167             :             tid);
    1168           0 :         switch (type) {
    1169             :         case MBIM_FUNCTION_ERROR_MSG:
    1170             :         case MBIM_HOST_ERROR_MSG:
    1171             :         {
    1172             :                 struct mbim_f2h_hosterr *e;
    1173             :                 int      err;
    1174             : 
    1175           0 :                 if (len >= sizeof (*e)) {
    1176           0 :                         e = response;
    1177           0 :                         err = letoh32(e->err);
    1178             : 
    1179             :                         DPRINTF("%s: %s message, error %s (tid %u)\n",
    1180             :                             DEVNAM(sc), umb_request2str(type),
    1181             :                             umb_error2str(err), tid);
    1182           0 :                         if (err == MBIM_ERROR_NOT_OPENED)
    1183           0 :                                 umb_newstate(sc, UMB_S_DOWN, 0);
    1184             :                 }
    1185             :                 break;
    1186             :         }
    1187             :         case MBIM_INDICATE_STATUS_MSG:
    1188           0 :                 umb_handle_indicate_status_msg(sc, response, len);
    1189           0 :                 break;
    1190             :         case MBIM_OPEN_DONE:
    1191           0 :                 umb_handle_opendone_msg(sc, response, len);
    1192           0 :                 break;
    1193             :         case MBIM_CLOSE_DONE:
    1194           0 :                 umb_handle_closedone_msg(sc, response, len);
    1195           0 :                 break;
    1196             :         case MBIM_COMMAND_DONE:
    1197           0 :                 umb_command_done(sc, response, len);
    1198           0 :                 break;
    1199             :         default:
    1200             :                 DPRINTF("%s: discard messsage %s\n", DEVNAM(sc),
    1201             :                     umb_request2str(type));
    1202             :                 break;
    1203             :         }
    1204           0 : }
    1205             : 
    1206             : void
    1207           0 : umb_handle_indicate_status_msg(struct umb_softc *sc, void *data, int len)
    1208             : {
    1209           0 :         struct mbim_f2h_indicate_status *m = data;
    1210             :         uint32_t infolen;
    1211             :         uint32_t cid;
    1212             : 
    1213           0 :         if (len < sizeof (*m)) {
    1214             :                 DPRINTF("%s: discard short %s messsage\n", DEVNAM(sc),
    1215             :                     umb_request2str(letoh32(m->hdr.type)));
    1216           0 :                 return;
    1217             :         }
    1218           0 :         if (memcmp(m->devid, umb_uuid_basic_connect, sizeof (m->devid))) {
    1219             :                 DPRINTF("%s: discard %s messsage for other UUID '%s'\n",
    1220             :                     DEVNAM(sc), umb_request2str(letoh32(m->hdr.type)),
    1221             :                     umb_uuid2str(m->devid));
    1222           0 :                 return;
    1223             :         }
    1224           0 :         infolen = letoh32(m->infolen);
    1225           0 :         if (len < sizeof (*m) + infolen) {
    1226             :                 DPRINTF("%s: discard truncated %s messsage (want %d, got %d)\n",
    1227             :                     DEVNAM(sc), umb_request2str(letoh32(m->hdr.type)),
    1228             :                     (int)sizeof (*m) + infolen, len);
    1229           0 :                 return;
    1230             :         }
    1231             : 
    1232           0 :         cid = letoh32(m->cid);
    1233             :         DPRINTF("%s: indicate %s status\n", DEVNAM(sc), umb_cid2str(cid));
    1234           0 :         umb_decode_cid(sc, cid, m->info, infolen);
    1235           0 : }
    1236             : 
    1237             : void
    1238           0 : umb_handle_opendone_msg(struct umb_softc *sc, void *data, int len)
    1239             : {
    1240           0 :         struct mbim_f2h_openclosedone *resp = data;
    1241           0 :         struct ifnet *ifp = GET_IFP(sc);
    1242             :         uint32_t status;
    1243             : 
    1244           0 :         status = letoh32(resp->status);
    1245           0 :         if (status == MBIM_STATUS_SUCCESS) {
    1246           0 :                 if (sc->sc_maxsessions == 0) {
    1247           0 :                         umb_cmd(sc, MBIM_CID_DEVICE_CAPS, MBIM_CMDOP_QRY, NULL,
    1248             :                             0);
    1249           0 :                         umb_cmd(sc, MBIM_CID_PIN, MBIM_CMDOP_QRY, NULL, 0);
    1250           0 :                         umb_cmd(sc, MBIM_CID_REGISTER_STATE, MBIM_CMDOP_QRY,
    1251             :                             NULL, 0);
    1252           0 :                 }
    1253           0 :                 umb_newstate(sc, UMB_S_OPEN, UMB_NS_DONT_DROP);
    1254           0 :         } else if (ifp->if_flags & IFF_DEBUG)
    1255           0 :                 log(LOG_ERR, "%s: open error: %s\n", DEVNAM(sc),
    1256           0 :                     umb_status2str(status));
    1257             :         return;
    1258           0 : }
    1259             : 
    1260             : void
    1261           0 : umb_handle_closedone_msg(struct umb_softc *sc, void *data, int len)
    1262             : {
    1263           0 :         struct mbim_f2h_openclosedone *resp = data;
    1264             :         uint32_t status;
    1265             : 
    1266           0 :         status = letoh32(resp->status);
    1267           0 :         if (status == MBIM_STATUS_SUCCESS)
    1268           0 :                 umb_newstate(sc, UMB_S_DOWN, 0);
    1269             :         else
    1270             :                 DPRINTF("%s: close error: %s\n", DEVNAM(sc),
    1271             :                     umb_status2str(status));
    1272             :         return;
    1273           0 : }
    1274             : 
    1275             : static inline void
    1276           0 : umb_getinfobuf(void *in, int inlen, uint32_t offs, uint32_t sz,
    1277             :     void *out, size_t outlen)
    1278             : {
    1279             :         offs = letoh32(offs);
    1280             :         sz = letoh32(sz);
    1281           0 :         if (inlen >= offs + sz) {
    1282           0 :                 memset(out, 0, outlen);
    1283           0 :                 memcpy(out, in + offs, MIN(sz, outlen));
    1284           0 :         }
    1285           0 : }
    1286             : 
    1287             : static inline int
    1288           0 : umb_addstr(void *buf, size_t bufsz, int *offs, void *str, int slen,
    1289             :     uint32_t *offsmember, uint32_t *sizemember)
    1290             : {
    1291           0 :         if (*offs + slen > bufsz)
    1292           0 :                 return 0;
    1293             : 
    1294           0 :         *sizemember = htole32((uint32_t)slen);
    1295           0 :         if (slen && str) {
    1296           0 :                 *offsmember = htole32((uint32_t)*offs);
    1297           0 :                 memcpy(buf + *offs, str, slen);
    1298           0 :                 *offs += slen;
    1299           0 :                 *offs += umb_padding(buf, bufsz, *offs, sizeof (uint32_t), 0);
    1300           0 :         } else
    1301           0 :                 *offsmember = htole32(0);
    1302           0 :         return 1;
    1303           0 : }
    1304             : 
    1305             : int
    1306           0 : umb_decode_register_state(struct umb_softc *sc, void *data, int len)
    1307             : {
    1308           0 :         struct mbim_cid_registration_state_info *rs = data;
    1309           0 :         struct ifnet *ifp = GET_IFP(sc);
    1310             : 
    1311           0 :         if (len < sizeof (*rs))
    1312           0 :                 return 0;
    1313           0 :         sc->sc_info.nwerror = letoh32(rs->nwerror);
    1314           0 :         sc->sc_info.regstate = letoh32(rs->regstate);
    1315           0 :         sc->sc_info.regmode = letoh32(rs->regmode);
    1316           0 :         sc->sc_info.cellclass = letoh32(rs->curcellclass);
    1317             : 
    1318             :         /* XXX should we remember the provider_id? */
    1319           0 :         umb_getinfobuf(data, len, rs->provname_offs, rs->provname_size,
    1320           0 :             sc->sc_info.provider, sizeof (sc->sc_info.provider));
    1321           0 :         umb_getinfobuf(data, len, rs->roamingtxt_offs, rs->roamingtxt_size,
    1322           0 :             sc->sc_info.roamingtxt, sizeof (sc->sc_info.roamingtxt));
    1323             : 
    1324             :         DPRINTFN(2, "%s: %s, availclass 0x%x, class 0x%x, regmode %d\n",
    1325             :             DEVNAM(sc), umb_regstate(sc->sc_info.regstate),
    1326             :             letoh32(rs->availclasses), sc->sc_info.cellclass,
    1327             :             sc->sc_info.regmode);
    1328             : 
    1329           0 :         if (sc->sc_info.regstate == MBIM_REGSTATE_ROAMING &&
    1330           0 :             !sc->sc_roaming &&
    1331           0 :             sc->sc_info.activation == MBIM_ACTIVATION_STATE_ACTIVATED) {
    1332           0 :                 if (ifp->if_flags & IFF_DEBUG)
    1333           0 :                         log(LOG_INFO,
    1334             :                             "%s: disconnecting from roaming network\n",
    1335           0 :                             DEVNAM(sc));
    1336           0 :                 umb_disconnect(sc);
    1337           0 :         }
    1338           0 :         return 1;
    1339           0 : }
    1340             : 
    1341             : int
    1342           0 : umb_decode_devices_caps(struct umb_softc *sc, void *data, int len)
    1343             : {
    1344           0 :         struct mbim_cid_device_caps *dc = data;
    1345             : 
    1346           0 :         if (len < sizeof (*dc))
    1347           0 :                 return 0;
    1348           0 :         sc->sc_maxsessions = letoh32(dc->max_sessions);
    1349           0 :         sc->sc_info.supportedclasses = letoh32(dc->dataclass);
    1350           0 :         umb_getinfobuf(data, len, dc->devid_offs, dc->devid_size,
    1351           0 :             sc->sc_info.devid, sizeof (sc->sc_info.devid));
    1352           0 :         umb_getinfobuf(data, len, dc->fwinfo_offs, dc->fwinfo_size,
    1353           0 :             sc->sc_info.fwinfo, sizeof (sc->sc_info.fwinfo));
    1354           0 :         umb_getinfobuf(data, len, dc->hwinfo_offs, dc->hwinfo_size,
    1355           0 :             sc->sc_info.hwinfo, sizeof (sc->sc_info.hwinfo));
    1356             :         DPRINTFN(2, "%s: max sessions %d, supported classes 0x%x\n",
    1357             :             DEVNAM(sc), sc->sc_maxsessions, sc->sc_info.supportedclasses);
    1358           0 :         return 1;
    1359           0 : }
    1360             : 
    1361             : int
    1362           0 : umb_decode_subscriber_status(struct umb_softc *sc, void *data, int len)
    1363             : {
    1364           0 :         struct mbim_cid_subscriber_ready_info *si = data;
    1365           0 :         struct ifnet *ifp = GET_IFP(sc);
    1366             :         int     npn;
    1367             : 
    1368           0 :         if (len < sizeof (*si))
    1369           0 :                 return 0;
    1370           0 :         sc->sc_info.sim_state = letoh32(si->ready);
    1371             : 
    1372           0 :         umb_getinfobuf(data, len, si->sid_offs, si->sid_size,
    1373           0 :             sc->sc_info.sid, sizeof (sc->sc_info.sid));
    1374           0 :         umb_getinfobuf(data, len, si->icc_offs, si->icc_size,
    1375           0 :             sc->sc_info.iccid, sizeof (sc->sc_info.iccid));
    1376             : 
    1377           0 :         npn = letoh32(si->no_pn);
    1378           0 :         if (npn > 0)
    1379           0 :                 umb_getinfobuf(data, len, si->pn[0].offs, si->pn[0].size,
    1380           0 :                     sc->sc_info.pn, sizeof (sc->sc_info.pn));
    1381             :         else
    1382           0 :                 memset(sc->sc_info.pn, 0, sizeof (sc->sc_info.pn));
    1383             : 
    1384           0 :         if (sc->sc_info.sim_state == MBIM_SIMSTATE_LOCKED)
    1385           0 :                 sc->sc_info.pin_state = UMB_PUK_REQUIRED;
    1386           0 :         if (ifp->if_flags & IFF_DEBUG)
    1387           0 :                 log(LOG_INFO, "%s: SIM %s\n", DEVNAM(sc),
    1388           0 :                     umb_simstate(sc->sc_info.sim_state));
    1389           0 :         if (sc->sc_info.sim_state == MBIM_SIMSTATE_INITIALIZED)
    1390           0 :                 umb_newstate(sc, UMB_S_SIMREADY, UMB_NS_DONT_DROP);
    1391           0 :         return 1;
    1392           0 : }
    1393             : 
    1394             : int
    1395           0 : umb_decode_radio_state(struct umb_softc *sc, void *data, int len)
    1396             : {
    1397           0 :         struct mbim_cid_radio_state_info *rs = data;
    1398           0 :         struct ifnet *ifp = GET_IFP(sc);
    1399             : 
    1400           0 :         if (len < sizeof (*rs))
    1401           0 :                 return 0;
    1402             : 
    1403           0 :         sc->sc_info.hw_radio_on =
    1404           0 :             (letoh32(rs->hw_state) == MBIM_RADIO_STATE_ON) ? 1 : 0;
    1405           0 :         sc->sc_info.sw_radio_on =
    1406           0 :             (letoh32(rs->sw_state) == MBIM_RADIO_STATE_ON) ? 1 : 0;
    1407           0 :         if (!sc->sc_info.hw_radio_on) {
    1408           0 :                 printf("%s: radio is disabled by hardware switch\n",
    1409           0 :                     DEVNAM(sc));
    1410             :                 /*
    1411             :                  * XXX do we need a time to poll the state of the rfkill switch
    1412             :                  *      or will the device send an unsolicited notification
    1413             :                  *      in case the state changes?
    1414             :                  */
    1415           0 :                 umb_newstate(sc, UMB_S_OPEN, 0);
    1416           0 :         } else if (!sc->sc_info.sw_radio_on) {
    1417           0 :                 if (ifp->if_flags & IFF_DEBUG)
    1418           0 :                         log(LOG_INFO, "%s: radio is off\n", DEVNAM(sc));
    1419           0 :                 umb_newstate(sc, UMB_S_OPEN, 0);
    1420           0 :         } else
    1421           0 :                 umb_newstate(sc, UMB_S_RADIO, UMB_NS_DONT_DROP);
    1422           0 :         return 1;
    1423           0 : }
    1424             : 
    1425             : int
    1426           0 : umb_decode_pin(struct umb_softc *sc, void *data, int len)
    1427             : {
    1428           0 :         struct mbim_cid_pin_info *pi = data;
    1429           0 :         struct ifnet *ifp = GET_IFP(sc);
    1430             :         uint32_t        attempts_left;
    1431             : 
    1432           0 :         if (len < sizeof (*pi))
    1433           0 :                 return 0;
    1434             : 
    1435           0 :         attempts_left = letoh32(pi->remaining_attempts);
    1436           0 :         if (attempts_left != 0xffffffff)
    1437           0 :                 sc->sc_info.pin_attempts_left = attempts_left;
    1438             : 
    1439           0 :         switch (letoh32(pi->state)) {
    1440             :         case MBIM_PIN_STATE_UNLOCKED:
    1441           0 :                 sc->sc_info.pin_state = UMB_PIN_UNLOCKED;
    1442           0 :                 break;
    1443             :         case MBIM_PIN_STATE_LOCKED:
    1444           0 :                 switch (letoh32(pi->type)) {
    1445             :                 case MBIM_PIN_TYPE_PIN1:
    1446           0 :                         sc->sc_info.pin_state = UMB_PIN_REQUIRED;
    1447           0 :                         break;
    1448             :                 case MBIM_PIN_TYPE_PUK1:
    1449           0 :                         sc->sc_info.pin_state = UMB_PUK_REQUIRED;
    1450           0 :                         break;
    1451             :                 case MBIM_PIN_TYPE_PIN2:
    1452             :                 case MBIM_PIN_TYPE_PUK2:
    1453             :                         /* Assume that PIN1 was accepted */
    1454           0 :                         sc->sc_info.pin_state = UMB_PIN_UNLOCKED;
    1455           0 :                         break;
    1456             :                 }
    1457             :                 break;
    1458             :         }
    1459           0 :         if (ifp->if_flags & IFF_DEBUG)
    1460           0 :                 log(LOG_INFO, "%s: %s state %s (%d attempts left)\n",
    1461           0 :                     DEVNAM(sc), umb_pin_type(letoh32(pi->type)),
    1462           0 :                     (letoh32(pi->state) == MBIM_PIN_STATE_UNLOCKED) ?
    1463             :                         "unlocked" : "locked",
    1464           0 :                     letoh32(pi->remaining_attempts));
    1465             : 
    1466             :         /*
    1467             :          * In case the PIN was set after IFF_UP, retrigger the state machine
    1468             :          */
    1469           0 :         usb_add_task(sc->sc_udev, &sc->sc_umb_task);
    1470           0 :         return 1;
    1471           0 : }
    1472             : 
    1473             : int
    1474           0 : umb_decode_packet_service(struct umb_softc *sc, void *data, int len)
    1475             : {
    1476           0 :         struct mbim_cid_packet_service_info *psi = data;
    1477             :         int      state, highestclass;
    1478             :         uint64_t up_speed, down_speed;
    1479           0 :         struct ifnet *ifp = GET_IFP(sc);
    1480             : 
    1481           0 :         if (len < sizeof (*psi))
    1482           0 :                 return 0;
    1483             : 
    1484           0 :         sc->sc_info.nwerror = letoh32(psi->nwerror);
    1485           0 :         state = letoh32(psi->state);
    1486           0 :         highestclass = letoh32(psi->highest_dataclass);
    1487           0 :         up_speed = letoh64(psi->uplink_speed);
    1488           0 :         down_speed = letoh64(psi->downlink_speed);
    1489           0 :         if (sc->sc_info.packetstate  != state ||
    1490           0 :             sc->sc_info.uplink_speed != up_speed ||
    1491           0 :             sc->sc_info.downlink_speed != down_speed) {
    1492           0 :                 if (ifp->if_flags & IFF_DEBUG) {
    1493           0 :                         log(LOG_INFO, "%s: packet service ", DEVNAM(sc));
    1494           0 :                         if (sc->sc_info.packetstate  != state)
    1495           0 :                                 addlog("changed from %s to ",
    1496           0 :                                     umb_packet_state(sc->sc_info.packetstate));
    1497           0 :                         addlog("%s, class %s, speed: %llu up / %llu down\n",
    1498           0 :                             umb_packet_state(state), 
    1499           0 :                             umb_dataclass(highestclass), up_speed, down_speed);
    1500           0 :                 }
    1501             :         }
    1502           0 :         sc->sc_info.packetstate = state;
    1503           0 :         sc->sc_info.highestclass = highestclass;
    1504           0 :         sc->sc_info.uplink_speed = up_speed;
    1505           0 :         sc->sc_info.downlink_speed = down_speed;
    1506             : 
    1507           0 :         if (sc->sc_info.regmode == MBIM_REGMODE_AUTOMATIC) {
    1508             :                 /*
    1509             :                  * For devices using automatic registration mode, just proceed,
    1510             :                  * once registration has completed.
    1511             :                  */
    1512           0 :                 if (ifp->if_flags & IFF_UP) {
    1513           0 :                         switch (sc->sc_info.regstate) {
    1514             :                         case MBIM_REGSTATE_HOME:
    1515             :                         case MBIM_REGSTATE_ROAMING:
    1516             :                         case MBIM_REGSTATE_PARTNER:
    1517           0 :                                 umb_newstate(sc, UMB_S_ATTACHED,
    1518             :                                     UMB_NS_DONT_DROP);
    1519           0 :                                 break;
    1520             :                         default:
    1521             :                                 break;
    1522             :                         }
    1523             :                 } else
    1524           0 :                         umb_newstate(sc, UMB_S_SIMREADY, UMB_NS_DONT_RAISE);
    1525           0 :         } else switch (sc->sc_info.packetstate) {
    1526             :         case MBIM_PKTSERVICE_STATE_ATTACHED:
    1527           0 :                 umb_newstate(sc, UMB_S_ATTACHED, UMB_NS_DONT_DROP);
    1528           0 :                 break;
    1529             :         case MBIM_PKTSERVICE_STATE_DETACHED:
    1530           0 :                 umb_newstate(sc, UMB_S_SIMREADY, UMB_NS_DONT_RAISE);
    1531           0 :                 break;
    1532             :         }
    1533           0 :         return 1;
    1534           0 : }
    1535             : 
    1536             : int
    1537           0 : umb_decode_signal_state(struct umb_softc *sc, void *data, int len)
    1538             : {
    1539           0 :         struct mbim_cid_signal_state *ss = data;
    1540           0 :         struct ifnet *ifp = GET_IFP(sc);
    1541             :         int      rssi;
    1542             : 
    1543           0 :         if (len < sizeof (*ss))
    1544           0 :                 return 0;
    1545             : 
    1546           0 :         if (letoh32(ss->rssi) == 99)
    1547           0 :                 rssi = UMB_VALUE_UNKNOWN;
    1548             :         else {
    1549           0 :                 rssi = -113 + 2 * letoh32(ss->rssi);
    1550           0 :                 if ((ifp->if_flags & IFF_DEBUG) && sc->sc_info.rssi != rssi &&
    1551           0 :                     sc->sc_state >= UMB_S_CONNECTED)
    1552           0 :                         log(LOG_INFO, "%s: rssi %d dBm\n", DEVNAM(sc), rssi);
    1553             :         }
    1554           0 :         sc->sc_info.rssi = rssi;
    1555           0 :         sc->sc_info.ber = letoh32(ss->err_rate);
    1556           0 :         if (sc->sc_info.ber == -99)
    1557           0 :                 sc->sc_info.ber = UMB_VALUE_UNKNOWN;
    1558           0 :         return 1;
    1559           0 : }
    1560             : 
    1561             : int
    1562           0 : umb_decode_connect_info(struct umb_softc *sc, void *data, int len)
    1563             : {
    1564           0 :         struct mbim_cid_connect_info *ci = data;
    1565           0 :         struct ifnet *ifp = GET_IFP(sc);
    1566             :         int      act;
    1567             : 
    1568           0 :         if (len < sizeof (*ci))
    1569           0 :                 return 0;
    1570             : 
    1571           0 :         if (letoh32(ci->sessionid) != umb_session_id) {
    1572             :                 DPRINTF("%s: discard connection info for session %u\n",
    1573             :                     DEVNAM(sc), letoh32(ci->sessionid));
    1574           0 :                 return 1;
    1575             :         }
    1576           0 :         if (memcmp(ci->context, umb_uuid_context_internet,
    1577             :             sizeof (ci->context))) {
    1578             :                 DPRINTF("%s: discard connection info for other context\n",
    1579             :                     DEVNAM(sc));
    1580           0 :                 return 1;
    1581             :         }
    1582           0 :         act = letoh32(ci->activation);
    1583           0 :         if (sc->sc_info.activation != act) {
    1584           0 :                 if (ifp->if_flags & IFF_DEBUG)
    1585           0 :                         log(LOG_INFO, "%s: connection %s\n", DEVNAM(sc),
    1586           0 :                             umb_activation(act));
    1587           0 :                 if ((ifp->if_flags & IFF_DEBUG) &&
    1588           0 :                     letoh32(ci->iptype) != MBIM_CONTEXT_IPTYPE_DEFAULT &&
    1589           0 :                     letoh32(ci->iptype) != MBIM_CONTEXT_IPTYPE_IPV4)
    1590           0 :                         log(LOG_DEBUG, "%s: got iptype %d connection\n",
    1591           0 :                             DEVNAM(sc), letoh32(ci->iptype));
    1592             : 
    1593           0 :                 sc->sc_info.activation = act;
    1594           0 :                 sc->sc_info.nwerror = letoh32(ci->nwerror);
    1595             : 
    1596           0 :                 if (sc->sc_info.activation == MBIM_ACTIVATION_STATE_ACTIVATED)
    1597           0 :                         umb_newstate(sc, UMB_S_CONNECTED, UMB_NS_DONT_DROP);
    1598           0 :                 else if (sc->sc_info.activation ==
    1599             :                     MBIM_ACTIVATION_STATE_DEACTIVATED)
    1600           0 :                         umb_newstate(sc, UMB_S_ATTACHED, 0);
    1601             :                 /* else: other states are purely transitional */
    1602             :         }
    1603           0 :         return 1;
    1604           0 : }
    1605             : 
    1606             : int
    1607           0 : umb_decode_ip_configuration(struct umb_softc *sc, void *data, int len)
    1608             : {
    1609           0 :         struct mbim_cid_ip_configuration_info *ic = data;
    1610           0 :         struct ifnet *ifp = GET_IFP(sc);
    1611             :         int      s;
    1612             :         uint32_t avail;
    1613             :         uint32_t val;
    1614             :         int      n, i;
    1615             :         int      off;
    1616             :         struct mbim_cid_ipv4_element ipv4elem;
    1617           0 :         struct in_aliasreq ifra;
    1618             :         struct sockaddr_in *sin;
    1619             :         int      state = -1;
    1620             :         int      rv;
    1621             : 
    1622           0 :         if (len < sizeof (*ic))
    1623           0 :                 return 0;
    1624           0 :         if (letoh32(ic->sessionid) != umb_session_id) {
    1625             :                 DPRINTF("%s: ignore IP configration for session id %d\n",
    1626             :                     DEVNAM(sc), letoh32(ic->sessionid));
    1627           0 :                 return 0;
    1628             :         }
    1629           0 :         s = splnet();
    1630             : 
    1631             :         /*
    1632             :          * IPv4 configuation
    1633             :          */
    1634           0 :         avail = letoh32(ic->ipv4_available);
    1635           0 :         if (avail & MBIM_IPCONF_HAS_ADDRINFO) {
    1636           0 :                 n = letoh32(ic->ipv4_naddr);
    1637           0 :                 off = letoh32(ic->ipv4_addroffs);
    1638             : 
    1639           0 :                 if (n == 0 || off + sizeof (ipv4elem) > len)
    1640             :                         goto done;
    1641             : 
    1642             :                 /* Only pick the first one */
    1643           0 :                 memcpy(&ipv4elem, data + off, sizeof (ipv4elem));
    1644             :                 ipv4elem.prefixlen = letoh32(ipv4elem.prefixlen);
    1645             : 
    1646           0 :                 memset(&ifra, 0, sizeof (ifra));
    1647           0 :                 sin = (struct sockaddr_in *)&ifra.ifra_addr;
    1648           0 :                 sin->sin_family = AF_INET;
    1649           0 :                 sin->sin_len = sizeof (ifra.ifra_addr);
    1650           0 :                 sin->sin_addr.s_addr = ipv4elem.addr;
    1651             : 
    1652           0 :                 sin = (struct sockaddr_in *)&ifra.ifra_dstaddr;
    1653           0 :                 sin->sin_family = AF_INET;
    1654           0 :                 sin->sin_len = sizeof (ifra.ifra_dstaddr);
    1655           0 :                 if (avail & MBIM_IPCONF_HAS_GWINFO) {
    1656           0 :                         off = letoh32(ic->ipv4_gwoffs);
    1657           0 :                         sin->sin_addr.s_addr = *((uint32_t *)(data + off));
    1658           0 :                 }
    1659             : 
    1660           0 :                 sin = (struct sockaddr_in *)&ifra.ifra_mask;
    1661           0 :                 sin->sin_family = AF_INET;
    1662           0 :                 sin->sin_len = sizeof (ifra.ifra_mask);
    1663           0 :                 in_len2mask(&sin->sin_addr, ipv4elem.prefixlen);
    1664             : 
    1665           0 :                 rv = in_ioctl(SIOCAIFADDR, (caddr_t)&ifra, ifp, 1);
    1666           0 :                 if (rv == 0) {
    1667           0 :                         if (ifp->if_flags & IFF_DEBUG)
    1668           0 :                                 log(LOG_INFO, "%s: IPv4 addr %s, mask %s, "
    1669           0 :                                     "gateway %s\n", DEVNAM(ifp->if_softc),
    1670           0 :                                     umb_ntop(sintosa(&ifra.ifra_addr)),
    1671           0 :                                     umb_ntop(sintosa(&ifra.ifra_mask)),
    1672           0 :                                     umb_ntop(sintosa(&ifra.ifra_dstaddr)));
    1673             :                         state = UMB_S_UP;
    1674           0 :                 } else
    1675           0 :                         printf("%s: unable to set IPv4 address, error %d\n",
    1676           0 :                             DEVNAM(ifp->if_softc), rv);
    1677             :         }
    1678             : 
    1679           0 :         memset(sc->sc_info.ipv4dns, 0, sizeof (sc->sc_info.ipv4dns));
    1680           0 :         if (avail & MBIM_IPCONF_HAS_DNSINFO) {
    1681           0 :                 n = letoh32(ic->ipv4_ndnssrv);
    1682           0 :                 off = letoh32(ic->ipv4_dnssrvoffs);
    1683             :                 i = 0;
    1684           0 :                 while (n-- > 0) {
    1685           0 :                         if (off + sizeof (uint32_t) > len)
    1686             :                                 break;
    1687           0 :                         val = *((uint32_t *)(data + off));
    1688           0 :                         if (i < UMB_MAX_DNSSRV)
    1689           0 :                                 sc->sc_info.ipv4dns[i++] = val;
    1690           0 :                         off += sizeof (uint32_t);
    1691             :                 }
    1692             :         }
    1693             : 
    1694           0 :         if ((avail & MBIM_IPCONF_HAS_MTUINFO)) {
    1695           0 :                 val = letoh32(ic->ipv4_mtu);
    1696           0 :                 if (ifp->if_hardmtu != val && val <= sc->sc_maxpktlen) {
    1697           0 :                         ifp->if_hardmtu = val;
    1698           0 :                         if (ifp->if_mtu > val)
    1699           0 :                                 ifp->if_mtu = val;
    1700           0 :                         if (ifp->if_flags & IFF_DEBUG)
    1701           0 :                                 log(LOG_INFO, "%s: MTU %d\n", DEVNAM(sc), val);
    1702             :                 }
    1703             :         }
    1704             : 
    1705           0 :         avail = letoh32(ic->ipv6_available);
    1706           0 :         if ((ifp->if_flags & IFF_DEBUG) && avail & MBIM_IPCONF_HAS_ADDRINFO) {
    1707             :                 /* XXX FIXME: IPv6 configuation missing */
    1708           0 :                 log(LOG_INFO, "%s: ignoring IPv6 configuration\n", DEVNAM(sc));
    1709           0 :         }
    1710           0 :         if (state != -1)
    1711           0 :                 umb_newstate(sc, state, 0);
    1712             : 
    1713             : done:
    1714           0 :         splx(s);
    1715           0 :         return 1;
    1716           0 : }
    1717             : 
    1718             : void
    1719           0 : umb_rx(struct umb_softc *sc)
    1720             : {
    1721           0 :         usbd_setup_xfer(sc->sc_rx_xfer, sc->sc_rx_pipe, sc, sc->sc_rx_buf,
    1722           0 :             sc->sc_rx_bufsz, USBD_SHORT_XFER_OK | USBD_NO_COPY,
    1723             :             USBD_NO_TIMEOUT, umb_rxeof);
    1724           0 :         usbd_transfer(sc->sc_rx_xfer);
    1725           0 : }
    1726             : 
    1727             : void
    1728           0 : umb_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
    1729             : {
    1730           0 :         struct umb_softc *sc = priv;
    1731           0 :         struct ifnet *ifp = GET_IFP(sc);
    1732             : 
    1733           0 :         if (usbd_is_dying(sc->sc_udev) || !(ifp->if_flags & IFF_RUNNING))
    1734           0 :                 return;
    1735             : 
    1736           0 :         if (status != USBD_NORMAL_COMPLETION) {
    1737           0 :                 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
    1738           0 :                         return;
    1739             :                 DPRINTF("%s: rx error: %s\n", DEVNAM(sc), usbd_errstr(status));
    1740           0 :                 if (status == USBD_STALLED)
    1741           0 :                         usbd_clear_endpoint_stall_async(sc->sc_rx_pipe);
    1742           0 :                 if (++sc->sc_rx_nerr > 100) {
    1743           0 :                         log(LOG_ERR, "%s: too many rx errors, disabling\n",
    1744           0 :                             DEVNAM(sc));
    1745           0 :                         usbd_deactivate(sc->sc_udev);
    1746           0 :                 }
    1747             :         } else {
    1748           0 :                 sc->sc_rx_nerr = 0;
    1749           0 :                 umb_decap(sc, xfer);
    1750             :         }
    1751             : 
    1752           0 :         umb_rx(sc);
    1753           0 :         return;
    1754           0 : }
    1755             : 
    1756             : int
    1757           0 : umb_encap(struct umb_softc *sc)
    1758             : {
    1759             :         struct ncm_header16 *hdr;
    1760             :         struct ncm_pointer16 *ptr;
    1761             :         struct ncm_pointer16_dgram *dgram;
    1762             :         int      offs, poffs;
    1763           0 :         struct mbuf_list tmpml = MBUF_LIST_INITIALIZER();
    1764             :         struct mbuf *m;
    1765             :         usbd_status  err;
    1766             : 
    1767             :         /* All size constraints have been validated by the caller! */
    1768           0 :         hdr = sc->sc_tx_buf;
    1769           0 :         USETDW(hdr->dwSignature, NCM_HDR16_SIG);
    1770           0 :         USETW(hdr->wHeaderLength, sizeof (*hdr));
    1771           0 :         USETW(hdr->wBlockLength, 0);
    1772           0 :         USETW(hdr->wSequence, sc->sc_tx_seq);
    1773           0 :         sc->sc_tx_seq++;
    1774             :         offs = sizeof (*hdr);
    1775           0 :         offs += umb_padding(sc->sc_tx_buf, sc->sc_tx_bufsz, offs,
    1776           0 :             sc->sc_align, 0);
    1777           0 :         USETW(hdr->wNdpIndex, offs);
    1778             : 
    1779             :         poffs = offs;
    1780           0 :         ptr = (struct ncm_pointer16 *)(sc->sc_tx_buf + offs);
    1781           0 :         USETDW(ptr->dwSignature, MBIM_NCM_NTH16_SIG(umb_session_id));
    1782           0 :         USETW(ptr->wNextNdpIndex, 0);
    1783           0 :         dgram = &ptr->dgram[0];
    1784           0 :         offs = (caddr_t)dgram - (caddr_t)sc->sc_tx_buf;
    1785             : 
    1786             :         /* Leave space for dgram pointers */
    1787           0 :         while ((m = ml_dequeue(&sc->sc_tx_ml)) != NULL) {
    1788             :                 offs += sizeof (*dgram);
    1789           0 :                 ml_enqueue(&tmpml, m);
    1790             :         }
    1791             :         offs += sizeof (*dgram);        /* one more to terminate pointer list */
    1792           0 :         USETW(ptr->wLength, offs - poffs);
    1793             : 
    1794             :         /* Encap mbufs */
    1795           0 :         while ((m = ml_dequeue(&tmpml)) != NULL) {
    1796           0 :                 offs += umb_padding(sc->sc_tx_buf, sc->sc_tx_bufsz, offs,
    1797           0 :                     sc->sc_ndp_div, sc->sc_ndp_remainder);
    1798           0 :                 USETW(dgram->wDatagramIndex, offs);
    1799           0 :                 USETW(dgram->wDatagramLen, m->m_pkthdr.len);
    1800           0 :                 dgram++;
    1801           0 :                 m_copydata(m, 0, m->m_pkthdr.len, sc->sc_tx_buf + offs);
    1802           0 :                 offs += m->m_pkthdr.len;
    1803           0 :                 ml_enqueue(&sc->sc_tx_ml, m);
    1804             :         }
    1805             : 
    1806             :         /* Terminating pointer */
    1807           0 :         USETW(dgram->wDatagramIndex, 0);
    1808           0 :         USETW(dgram->wDatagramLen, 0);
    1809           0 :         USETW(hdr->wBlockLength, offs);
    1810             : 
    1811             :         DPRINTFN(3, "%s: encap %d bytes\n", DEVNAM(sc), offs);
    1812             :         DDUMPN(5, sc->sc_tx_buf, offs);
    1813           0 :         KASSERT(offs <= sc->sc_tx_bufsz);
    1814             : 
    1815           0 :         usbd_setup_xfer(sc->sc_tx_xfer, sc->sc_tx_pipe, sc, sc->sc_tx_buf, offs,
    1816           0 :             USBD_FORCE_SHORT_XFER | USBD_NO_COPY, umb_xfer_tout, umb_txeof);
    1817           0 :         err = usbd_transfer(sc->sc_tx_xfer);
    1818           0 :         if (err != USBD_IN_PROGRESS) {
    1819             :                 DPRINTF("%s: start tx error: %s\n", DEVNAM(sc),
    1820             :                     usbd_errstr(err));
    1821           0 :                 ml_purge(&sc->sc_tx_ml);
    1822           0 :                 return 0;
    1823             :         }
    1824           0 :         return 1;
    1825           0 : }
    1826             : 
    1827             : void
    1828           0 : umb_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
    1829             : {
    1830           0 :         struct umb_softc *sc = priv;
    1831           0 :         struct ifnet *ifp = GET_IFP(sc);
    1832             :         int      s;
    1833             : 
    1834           0 :         s = splnet();
    1835           0 :         ml_purge(&sc->sc_tx_ml);
    1836           0 :         ifq_clr_oactive(&ifp->if_snd);
    1837           0 :         ifp->if_timer = 0;
    1838             : 
    1839           0 :         if (status != USBD_NORMAL_COMPLETION) {
    1840           0 :                 if (status != USBD_NOT_STARTED && status != USBD_CANCELLED) {
    1841           0 :                         ifp->if_oerrors++;
    1842             :                         DPRINTF("%s: tx error: %s\n", DEVNAM(sc),
    1843             :                             usbd_errstr(status));
    1844           0 :                         if (status == USBD_STALLED)
    1845           0 :                                 usbd_clear_endpoint_stall_async(sc->sc_tx_pipe);
    1846             :                 }
    1847             :         }
    1848           0 :         if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
    1849           0 :                 umb_start(ifp);
    1850             : 
    1851           0 :         splx(s);
    1852           0 : }
    1853             : 
    1854             : void
    1855           0 : umb_decap(struct umb_softc *sc, struct usbd_xfer *xfer)
    1856             : {
    1857           0 :         struct ifnet *ifp = GET_IFP(sc);
    1858             :         int      s;
    1859           0 :         void    *buf;
    1860           0 :         uint32_t len;
    1861             :         char    *dp;
    1862             :         struct ncm_header16 *hdr16;
    1863             :         struct ncm_header32 *hdr32;
    1864             :         struct ncm_pointer16 *ptr16;
    1865             :         struct ncm_pointer16_dgram *dgram16;
    1866             :         struct ncm_pointer32_dgram *dgram32;
    1867             :         uint32_t hsig, psig;
    1868             :         int      hlen, blen;
    1869             :         int      ptrlen, ptroff, dgentryoff;
    1870             :         uint32_t doff, dlen;
    1871           0 :         struct mbuf_list ml = MBUF_LIST_INITIALIZER();
    1872             :         struct mbuf *m;
    1873             : 
    1874           0 :         usbd_get_xfer_status(xfer, NULL, &buf, &len, NULL);
    1875             :         DPRINTFN(4, "%s: recv %d bytes\n", DEVNAM(sc), len);
    1876             :         DDUMPN(5, buf, len);
    1877           0 :         s = splnet();
    1878           0 :         if (len < sizeof (*hdr16))
    1879             :                 goto toosmall;
    1880             : 
    1881           0 :         hdr16 = (struct ncm_header16 *)buf;
    1882           0 :         hsig = UGETDW(hdr16->dwSignature);
    1883           0 :         hlen = UGETW(hdr16->wHeaderLength);
    1884           0 :         if (len < hlen)
    1885             :                 goto toosmall;
    1886             : 
    1887           0 :         switch (hsig) {
    1888             :         case NCM_HDR16_SIG:
    1889           0 :                 blen = UGETW(hdr16->wBlockLength);
    1890           0 :                 ptroff = UGETW(hdr16->wNdpIndex);
    1891           0 :                 if (hlen != sizeof (*hdr16)) {
    1892             :                         DPRINTF("%s: bad header len %d for NTH16 (exp %zu)\n",
    1893             :                             DEVNAM(sc), hlen, sizeof (*hdr16));
    1894             :                         goto fail;
    1895             :                 }
    1896             :                 break;
    1897             :         case NCM_HDR32_SIG:
    1898           0 :                 hdr32 = (struct ncm_header32 *)hdr16;
    1899           0 :                 blen = UGETDW(hdr32->dwBlockLength);
    1900           0 :                 ptroff = UGETDW(hdr32->dwNdpIndex);
    1901           0 :                 if (hlen != sizeof (*hdr32)) {
    1902             :                         DPRINTF("%s: bad header len %d for NTH32 (exp %zu)\n",
    1903             :                             DEVNAM(sc), hlen, sizeof (*hdr32));
    1904             :                         goto fail;
    1905             :                 }
    1906             :                 break;
    1907             :         default:
    1908             :                 DPRINTF("%s: unsupported NCM header signature (0x%08x)\n",
    1909             :                     DEVNAM(sc), hsig);
    1910             :                 goto fail;
    1911             :         }
    1912           0 :         if (blen != 0 && len < blen) {
    1913             :                 DPRINTF("%s: bad NTB len (%d) for %d bytes of data\n",
    1914             :                     DEVNAM(sc), blen, len);
    1915             :                 goto fail;
    1916             :         }
    1917             : 
    1918           0 :         ptr16 = (struct ncm_pointer16 *)(buf + ptroff);
    1919           0 :         psig = UGETDW(ptr16->dwSignature);
    1920           0 :         ptrlen = UGETW(ptr16->wLength);
    1921           0 :         if (len < ptrlen + ptroff)
    1922             :                 goto toosmall;
    1923           0 :         if (!MBIM_NCM_NTH16_ISISG(psig) && !MBIM_NCM_NTH32_ISISG(psig)) {
    1924             :                 DPRINTF("%s: unsupported NCM pointer signature (0x%08x)\n",
    1925             :                     DEVNAM(sc), psig);
    1926             :                 goto fail;
    1927             :         }
    1928             : 
    1929           0 :         switch (hsig) {
    1930             :         case NCM_HDR16_SIG:
    1931             :                 dgentryoff = offsetof(struct ncm_pointer16, dgram);
    1932           0 :                 break;
    1933             :         case NCM_HDR32_SIG:
    1934             :                 dgentryoff = offsetof(struct ncm_pointer32, dgram);
    1935           0 :                 break;
    1936             :         default:
    1937             :                 goto fail;
    1938             :         }
    1939             : 
    1940           0 :         while (dgentryoff < ptrlen) {
    1941           0 :                 switch (hsig) {
    1942             :                 case NCM_HDR16_SIG:
    1943           0 :                         if (ptroff + dgentryoff < sizeof (*dgram16))
    1944             :                                 goto done;
    1945           0 :                         dgram16 = (struct ncm_pointer16_dgram *)
    1946           0 :                             (buf + ptroff + dgentryoff);
    1947           0 :                         dgentryoff += sizeof (*dgram16);
    1948           0 :                         dlen = UGETW(dgram16->wDatagramLen);
    1949           0 :                         doff = UGETW(dgram16->wDatagramIndex);
    1950           0 :                         break;
    1951             :                 case NCM_HDR32_SIG:
    1952           0 :                         if (ptroff + dgentryoff < sizeof (*dgram32))
    1953             :                                 goto done;
    1954           0 :                         dgram32 = (struct ncm_pointer32_dgram *)
    1955           0 :                             (buf + ptroff + dgentryoff);
    1956           0 :                         dgentryoff += sizeof (*dgram32);
    1957           0 :                         dlen = UGETDW(dgram32->dwDatagramLen);
    1958           0 :                         doff = UGETDW(dgram32->dwDatagramIndex);
    1959           0 :                         break;
    1960             :                 default:
    1961           0 :                         ifp->if_ierrors++;
    1962           0 :                         goto done;
    1963             :                 }
    1964             : 
    1965             :                 /* Terminating zero entry */
    1966           0 :                 if (dlen == 0 || doff == 0)
    1967             :                         break;
    1968           0 :                 if (len < dlen + doff) {
    1969             :                         /* Skip giant datagram but continue processing */
    1970             :                         DPRINTF("%s: datagram too large (%d @ off %d)\n",
    1971             :                             DEVNAM(sc), dlen, doff);
    1972           0 :                         continue;
    1973             :                 }
    1974             : 
    1975           0 :                 dp = buf + doff;
    1976             :                 DPRINTFN(3, "%s: decap %d bytes\n", DEVNAM(sc), dlen);
    1977           0 :                 m = m_devget(dp, dlen, 0);
    1978           0 :                 if (m == NULL) {
    1979           0 :                         ifp->if_iqdrops++;
    1980           0 :                         continue;
    1981             :                 }
    1982             : 
    1983           0 :                 ml_enqueue(&ml, m);
    1984             :         }
    1985             : done:
    1986           0 :         if_input(ifp, &ml);
    1987           0 :         splx(s);
    1988           0 :         return;
    1989             : toosmall:
    1990             :         DPRINTF("%s: packet too small (%d)\n", DEVNAM(sc), len);
    1991             : fail:
    1992           0 :         ifp->if_ierrors++;
    1993           0 :         splx(s);
    1994           0 : }
    1995             : 
    1996             : usbd_status
    1997           0 : umb_send_encap_command(struct umb_softc *sc, void *data, int len)
    1998             : {
    1999             :         struct usbd_xfer *xfer;
    2000           0 :         usb_device_request_t req;
    2001             :         char *buf;
    2002             : 
    2003           0 :         if (len > sc->sc_ctrl_len)
    2004           0 :                 return USBD_INVAL;
    2005             : 
    2006           0 :         if ((xfer = usbd_alloc_xfer(sc->sc_udev)) == NULL)
    2007           0 :                 return USBD_NOMEM;
    2008           0 :         if ((buf = usbd_alloc_buffer(xfer, len)) == NULL) {
    2009           0 :                 usbd_free_xfer(xfer);
    2010           0 :                 return USBD_NOMEM;
    2011             :         }
    2012           0 :         memcpy(buf, data, len);
    2013             : 
    2014             :         /* XXX FIXME: if (total len > sc->sc_ctrl_len) => must fragment */
    2015           0 :         req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
    2016           0 :         req.bRequest = UCDC_SEND_ENCAPSULATED_COMMAND;
    2017           0 :         USETW(req.wValue, 0);
    2018           0 :         USETW(req.wIndex, sc->sc_ctrl_ifaceno);
    2019           0 :         USETW(req.wLength, len);
    2020           0 :         DELAY(umb_delay);
    2021           0 :         return usbd_request_async(xfer, &req, NULL, NULL);
    2022           0 : }
    2023             : 
    2024             : int
    2025           0 : umb_get_encap_response(struct umb_softc *sc, void *buf, int *len)
    2026             : {
    2027           0 :         usb_device_request_t req;
    2028             :         usbd_status err;
    2029             : 
    2030           0 :         req.bmRequestType = UT_READ_CLASS_INTERFACE;
    2031           0 :         req.bRequest = UCDC_GET_ENCAPSULATED_RESPONSE;
    2032           0 :         USETW(req.wValue, 0);
    2033           0 :         USETW(req.wIndex, sc->sc_ctrl_ifaceno);
    2034           0 :         USETW(req.wLength, *len);
    2035             :         /* XXX FIXME: re-assemble fragments */
    2036             : 
    2037           0 :         DELAY(umb_delay);
    2038           0 :         err = usbd_do_request_flags(sc->sc_udev, &req, buf, USBD_SHORT_XFER_OK,
    2039           0 :             len, umb_xfer_tout);
    2040           0 :         if (err == USBD_NORMAL_COMPLETION)
    2041           0 :                 return 1;
    2042             :         DPRINTF("%s: ctrl recv: %s\n", DEVNAM(sc), usbd_errstr(err));
    2043           0 :         return 0;
    2044           0 : }
    2045             : 
    2046             : void
    2047           0 : umb_ctrl_msg(struct umb_softc *sc, uint32_t req, void *data, int len)
    2048             : {
    2049           0 :         struct ifnet *ifp = GET_IFP(sc);
    2050             :         uint32_t tid;
    2051           0 :         struct mbim_msghdr *hdr = data;
    2052             :         usbd_status err;
    2053             :         int      s;
    2054             : 
    2055           0 :         assertwaitok();
    2056           0 :         if (usbd_is_dying(sc->sc_udev))
    2057           0 :                 return;
    2058           0 :         if (len < sizeof (*hdr))
    2059           0 :                 return;
    2060           0 :         tid = ++sc->sc_tid;
    2061             : 
    2062           0 :         hdr->type = htole32(req);
    2063           0 :         hdr->len = htole32(len);
    2064           0 :         hdr->tid = htole32(tid);
    2065             : 
    2066             : #ifdef UMB_DEBUG
    2067             :         if (umb_debug) {
    2068             :                 const char *op, *str;
    2069             :                 if (req == MBIM_COMMAND_MSG) {
    2070             :                         struct mbim_h2f_cmd *c = data;
    2071             :                         if (letoh32(c->op) == MBIM_CMDOP_SET)
    2072             :                                 op = "set";
    2073             :                         else
    2074             :                                 op = "qry";
    2075             :                         str = umb_cid2str(letoh32(c->cid));
    2076             :                 } else {
    2077             :                         op = "snd";
    2078             :                         str = umb_request2str(req);
    2079             :                 }
    2080             :                 DPRINTF("%s: -> %s %s (tid %u)\n", DEVNAM(sc), op, str, tid);
    2081             :         }
    2082             : #endif
    2083           0 :         s = splusb();
    2084           0 :         err = umb_send_encap_command(sc, data, len);
    2085           0 :         splx(s);
    2086           0 :         if (err != USBD_NORMAL_COMPLETION) {
    2087           0 :                 if (ifp->if_flags & IFF_DEBUG)
    2088           0 :                         log(LOG_ERR, "%s: send %s msg (tid %u) failed: %s\n",
    2089           0 :                             DEVNAM(sc), umb_request2str(req), tid,
    2090           0 :                             usbd_errstr(err));
    2091             : 
    2092             :                 /* will affect other transactions, too */
    2093           0 :                 usbd_abort_pipe(sc->sc_udev->default_pipe);
    2094           0 :         } else {
    2095             :                 DPRINTFN(2, "%s: sent %s (tid %u)\n", DEVNAM(sc),
    2096             :                     umb_request2str(req), tid);
    2097             :                 DDUMPN(3, data, len);
    2098             :         }
    2099           0 :         return;
    2100           0 : }
    2101             : 
    2102             : void
    2103           0 : umb_open(struct umb_softc *sc)
    2104             : {
    2105           0 :         struct mbim_h2f_openmsg msg;
    2106             : 
    2107           0 :         memset(&msg, 0, sizeof (msg));
    2108           0 :         msg.maxlen = htole32(sc->sc_ctrl_len);
    2109           0 :         umb_ctrl_msg(sc, MBIM_OPEN_MSG, &msg, sizeof (msg));
    2110             :         return;
    2111           0 : }
    2112             : 
    2113             : void
    2114           0 : umb_close(struct umb_softc *sc)
    2115             : {
    2116           0 :         struct mbim_h2f_closemsg msg;
    2117             : 
    2118           0 :         memset(&msg, 0, sizeof (msg));
    2119           0 :         umb_ctrl_msg(sc, MBIM_CLOSE_MSG, &msg, sizeof (msg));
    2120           0 : }
    2121             : 
    2122             : int
    2123           0 : umb_setpin(struct umb_softc *sc, int op, int is_puk, void *pin, int pinlen,
    2124             :     void *newpin, int newpinlen)
    2125             : {
    2126           0 :         struct mbim_cid_pin cp;
    2127           0 :         int      off;
    2128             : 
    2129           0 :         if (pinlen == 0)
    2130           0 :                 return 0;
    2131           0 :         if (pinlen < 0 || pinlen > MBIM_PIN_MAXLEN ||
    2132           0 :             newpinlen < 0 || newpinlen > MBIM_PIN_MAXLEN ||
    2133           0 :             op < 0 || op > MBIM_PIN_OP_CHANGE ||
    2134           0 :             (is_puk && op != MBIM_PIN_OP_ENTER))
    2135           0 :                 return EINVAL;
    2136             : 
    2137           0 :         memset(&cp, 0, sizeof (cp));
    2138           0 :         cp.type = htole32(is_puk ? MBIM_PIN_TYPE_PUK1 : MBIM_PIN_TYPE_PIN1);
    2139             : 
    2140           0 :         off = offsetof(struct mbim_cid_pin, data);
    2141           0 :         if (!umb_addstr(&cp, sizeof (cp), &off, pin, pinlen,
    2142           0 :             &cp.pin_offs, &cp.pin_size))
    2143           0 :                 return EINVAL;
    2144             : 
    2145           0 :         cp.op  = htole32(op);
    2146           0 :         if (newpinlen) {
    2147           0 :                 if (!umb_addstr(&cp, sizeof (cp), &off, newpin, newpinlen,
    2148           0 :                     &cp.newpin_offs, &cp.newpin_size))
    2149           0 :                         return EINVAL;
    2150             :         } else {
    2151           0 :                 if ((op == MBIM_PIN_OP_CHANGE) || is_puk)
    2152           0 :                         return EINVAL;
    2153           0 :                 if (!umb_addstr(&cp, sizeof (cp), &off, NULL, 0,
    2154           0 :                     &cp.newpin_offs, &cp.newpin_size))
    2155           0 :                         return EINVAL;
    2156             :         }
    2157           0 :         umb_cmd(sc, MBIM_CID_PIN, MBIM_CMDOP_SET, &cp, off);
    2158           0 :         return 0;
    2159           0 : }
    2160             : 
    2161             : void
    2162           0 : umb_setdataclass(struct umb_softc *sc)
    2163             : {
    2164           0 :         struct mbim_cid_registration_state rs;
    2165             :         uint32_t         classes;
    2166             : 
    2167           0 :         if (sc->sc_info.supportedclasses == MBIM_DATACLASS_NONE)
    2168           0 :                 return;
    2169             : 
    2170           0 :         memset(&rs, 0, sizeof (rs));
    2171           0 :         rs.regaction = htole32(MBIM_REGACTION_AUTOMATIC);
    2172           0 :         classes = sc->sc_info.supportedclasses;
    2173           0 :         if (sc->sc_info.preferredclasses != MBIM_DATACLASS_NONE)
    2174           0 :                 classes &= sc->sc_info.preferredclasses;
    2175           0 :         rs.data_class = htole32(classes);
    2176           0 :         umb_cmd(sc, MBIM_CID_REGISTER_STATE, MBIM_CMDOP_SET, &rs, sizeof (rs));
    2177           0 : }
    2178             : 
    2179             : void
    2180           0 : umb_radio(struct umb_softc *sc, int on)
    2181             : {
    2182           0 :         struct mbim_cid_radio_state s;
    2183             : 
    2184             :         DPRINTF("%s: set radio %s\n", DEVNAM(sc), on ? "on" : "off");
    2185           0 :         memset(&s, 0, sizeof (s));
    2186           0 :         s.state = htole32(on ? MBIM_RADIO_STATE_ON : MBIM_RADIO_STATE_OFF);
    2187           0 :         umb_cmd(sc, MBIM_CID_RADIO_STATE, MBIM_CMDOP_SET, &s, sizeof (s));
    2188           0 : }
    2189             : 
    2190             : void
    2191           0 : umb_allocate_cid(struct umb_softc *sc)
    2192             : {
    2193           0 :         umb_cmd1(sc, MBIM_CID_DEVICE_CAPS, MBIM_CMDOP_SET,
    2194             :             umb_qmi_alloc_cid, sizeof (umb_qmi_alloc_cid), umb_uuid_qmi_mbim);
    2195           0 : }
    2196             : 
    2197             : void
    2198           0 : umb_send_fcc_auth(struct umb_softc *sc)
    2199             : {
    2200           0 :         uint8_t  fccauth[sizeof (umb_qmi_fcc_auth)];
    2201             : 
    2202           0 :         if (sc->sc_cid == -1) {
    2203             :                 DPRINTF("%s: missing CID, cannot send FCC auth\n", DEVNAM(sc));
    2204           0 :                 umb_allocate_cid(sc);
    2205           0 :                 return;
    2206             :         }
    2207           0 :         memcpy(fccauth, umb_qmi_fcc_auth, sizeof (fccauth));
    2208           0 :         fccauth[UMB_QMI_CID_OFFS] = sc->sc_cid;
    2209           0 :         umb_cmd1(sc, MBIM_CID_DEVICE_CAPS, MBIM_CMDOP_SET,
    2210             :             fccauth, sizeof (fccauth), umb_uuid_qmi_mbim);
    2211           0 : }
    2212             : 
    2213             : void
    2214           0 : umb_packet_service(struct umb_softc *sc, int attach)
    2215             : {
    2216           0 :         struct mbim_cid_packet_service  s;
    2217             : 
    2218             :         DPRINTF("%s: %s packet service\n", DEVNAM(sc),
    2219             :             attach ? "attach" : "detach");
    2220           0 :         memset(&s, 0, sizeof (s));
    2221           0 :         s.action = htole32(attach ?
    2222             :             MBIM_PKTSERVICE_ACTION_ATTACH : MBIM_PKTSERVICE_ACTION_DETACH);
    2223           0 :         umb_cmd(sc, MBIM_CID_PACKET_SERVICE, MBIM_CMDOP_SET, &s, sizeof (s));
    2224           0 : }
    2225             : 
    2226             : void
    2227           0 : umb_connect(struct umb_softc *sc)
    2228             : {
    2229           0 :         struct ifnet *ifp = GET_IFP(sc);
    2230             : 
    2231           0 :         if (sc->sc_info.regstate == MBIM_REGSTATE_ROAMING && !sc->sc_roaming) {
    2232           0 :                 log(LOG_INFO, "%s: connection disabled in roaming network\n",
    2233           0 :                     DEVNAM(sc));
    2234           0 :                 return;
    2235             :         }
    2236           0 :         if (ifp->if_flags & IFF_DEBUG)
    2237           0 :                 log(LOG_DEBUG, "%s: connecting ...\n", DEVNAM(sc));
    2238           0 :         umb_send_connect(sc, MBIM_CONNECT_ACTIVATE);
    2239           0 : }
    2240             : 
    2241             : void
    2242           0 : umb_disconnect(struct umb_softc *sc)
    2243             : {
    2244           0 :         struct ifnet *ifp = GET_IFP(sc);
    2245             : 
    2246           0 :         if (ifp->if_flags & IFF_DEBUG)
    2247           0 :                 log(LOG_DEBUG, "%s: disconnecting ...\n", DEVNAM(sc));
    2248           0 :         umb_send_connect(sc, MBIM_CONNECT_DEACTIVATE);
    2249           0 : }
    2250             : 
    2251             : void
    2252           0 : umb_send_connect(struct umb_softc *sc, int command)
    2253             : {
    2254             :         struct mbim_cid_connect *c;
    2255           0 :         int      off;
    2256             : 
    2257             :         /* Too large or the stack */
    2258           0 :         c = malloc(sizeof (*c), M_USBDEV, M_WAIT|M_ZERO);
    2259           0 :         c->sessionid = htole32(umb_session_id);
    2260           0 :         c->command = htole32(command);
    2261           0 :         off = offsetof(struct mbim_cid_connect, data);
    2262           0 :         if (!umb_addstr(c, sizeof (*c), &off, sc->sc_info.apn,
    2263           0 :             sc->sc_info.apnlen, &c->access_offs, &c->access_size))
    2264             :                 goto done;
    2265             :         /* XXX FIXME: support user name and passphrase */
    2266           0 :         c->user_offs = htole32(0);
    2267           0 :         c->user_size = htole32(0);
    2268           0 :         c->passwd_offs = htole32(0);
    2269           0 :         c->passwd_size = htole32(0);
    2270           0 :         c->authprot = htole32(MBIM_AUTHPROT_NONE);
    2271           0 :         c->compression = htole32(MBIM_COMPRESSION_NONE);
    2272           0 :         c->iptype = htole32(MBIM_CONTEXT_IPTYPE_IPV4);
    2273           0 :         memcpy(c->context, umb_uuid_context_internet, sizeof (c->context));
    2274           0 :         umb_cmd(sc, MBIM_CID_CONNECT, MBIM_CMDOP_SET, c, off);
    2275             : done:
    2276           0 :         free(c, M_USBDEV, sizeof (*c));
    2277             :         return;
    2278           0 : }
    2279             : 
    2280             : void
    2281           0 : umb_qry_ipconfig(struct umb_softc *sc)
    2282             : {
    2283           0 :         struct mbim_cid_ip_configuration_info ipc;
    2284             : 
    2285           0 :         memset(&ipc, 0, sizeof (ipc));
    2286           0 :         ipc.sessionid = htole32(umb_session_id);
    2287           0 :         umb_cmd(sc, MBIM_CID_IP_CONFIGURATION, MBIM_CMDOP_QRY,
    2288             :             &ipc, sizeof (ipc));
    2289           0 : }
    2290             : 
    2291             : void
    2292           0 : umb_cmd(struct umb_softc *sc, int cid, int op, void *data, int len)
    2293             : {
    2294           0 :         umb_cmd1(sc, cid, op, data, len, umb_uuid_basic_connect);
    2295           0 : }
    2296             : 
    2297             : void
    2298           0 : umb_cmd1(struct umb_softc *sc, int cid, int op, void *data, int len,
    2299             :     uint8_t *uuid)
    2300             : {
    2301             :         struct mbim_h2f_cmd *cmd;
    2302             :         int     totlen;
    2303             : 
    2304             :         /* XXX FIXME support sending fragments */
    2305           0 :         if (sizeof (*cmd) + len > sc->sc_ctrl_len) {
    2306             :                 DPRINTF("%s: set %s msg too long: cannot send\n",
    2307             :                     DEVNAM(sc), umb_cid2str(cid));
    2308           0 :                 return;
    2309             :         }
    2310           0 :         cmd = sc->sc_ctrl_msg;
    2311           0 :         memset(cmd, 0, sizeof (*cmd));
    2312           0 :         cmd->frag.nfrag = htole32(1);
    2313           0 :         memcpy(cmd->devid, uuid, sizeof (cmd->devid));
    2314           0 :         cmd->cid = htole32(cid);
    2315           0 :         cmd->op = htole32(op);
    2316           0 :         cmd->infolen = htole32(len);
    2317             :         totlen = sizeof (*cmd);
    2318           0 :         if (len > 0) {
    2319           0 :                 memcpy(cmd + 1, data, len);
    2320           0 :                 totlen += len;
    2321           0 :         }
    2322           0 :         umb_ctrl_msg(sc, MBIM_COMMAND_MSG, cmd, totlen);
    2323           0 : }
    2324             : 
    2325             : void
    2326           0 : umb_command_done(struct umb_softc *sc, void *data, int len)
    2327             : {
    2328           0 :         struct mbim_f2h_cmddone *cmd = data;
    2329           0 :         struct ifnet *ifp = GET_IFP(sc);
    2330             :         uint32_t status;
    2331             :         uint32_t cid;
    2332             :         uint32_t infolen;
    2333             :         int      qmimsg = 0;
    2334             : 
    2335           0 :         if (len < sizeof (*cmd)) {
    2336             :                 DPRINTF("%s: discard short %s messsage\n", DEVNAM(sc),
    2337             :                     umb_request2str(letoh32(cmd->hdr.type)));
    2338           0 :                 return;
    2339             :         }
    2340           0 :         cid = letoh32(cmd->cid);
    2341           0 :         if (memcmp(cmd->devid, umb_uuid_basic_connect, sizeof (cmd->devid))) {
    2342           0 :                 if (memcmp(cmd->devid, umb_uuid_qmi_mbim,
    2343             :                     sizeof (cmd->devid))) {
    2344             :                         DPRINTF("%s: discard %s messsage for other UUID '%s'\n",
    2345             :                             DEVNAM(sc), umb_request2str(letoh32(cmd->hdr.type)),
    2346             :                             umb_uuid2str(cmd->devid));
    2347           0 :                         return;
    2348             :                 } else
    2349             :                         qmimsg = 1;
    2350           0 :         }
    2351             : 
    2352           0 :         status = letoh32(cmd->status);
    2353           0 :         switch (status) {
    2354             :         case MBIM_STATUS_SUCCESS:
    2355             :                 break;
    2356             :         case MBIM_STATUS_NOT_INITIALIZED:
    2357           0 :                 if (ifp->if_flags & IFF_DEBUG)
    2358           0 :                         log(LOG_ERR, "%s: SIM not initialized (PIN missing)\n",
    2359           0 :                             DEVNAM(sc));
    2360           0 :                 return;
    2361             :         case MBIM_STATUS_PIN_REQUIRED:
    2362           0 :                 sc->sc_info.pin_state = UMB_PIN_REQUIRED;
    2363             :                 /*FALLTHROUGH*/
    2364             :         default:
    2365           0 :                 if (ifp->if_flags & IFF_DEBUG)
    2366           0 :                         log(LOG_ERR, "%s: set/qry %s failed: %s\n", DEVNAM(sc),
    2367           0 :                             umb_cid2str(cid), umb_status2str(status));
    2368           0 :                 return;
    2369             :         }
    2370             : 
    2371           0 :         infolen = letoh32(cmd->infolen);
    2372           0 :         if (len < sizeof (*cmd) + infolen) {
    2373             :                 DPRINTF("%s: discard truncated %s messsage (want %d, got %d)\n",
    2374             :                     DEVNAM(sc), umb_cid2str(cid),
    2375             :                     (int)sizeof (*cmd) + infolen, len);
    2376           0 :                 return;
    2377             :         }
    2378           0 :         if (qmimsg) {
    2379           0 :                 if (sc->sc_flags & UMBFLG_FCC_AUTH_REQUIRED)
    2380           0 :                         umb_decode_qmi(sc, cmd->info, infolen);
    2381             :         } else {
    2382             :                 DPRINTFN(2, "%s: set/qry %s done\n", DEVNAM(sc),
    2383             :                     umb_cid2str(cid));
    2384           0 :                 umb_decode_cid(sc, cid, cmd->info, infolen);
    2385             :         }
    2386           0 : }
    2387             : 
    2388             : void
    2389           0 : umb_decode_cid(struct umb_softc *sc, uint32_t cid, void *data, int len)
    2390             : {
    2391             :         int      ok = 1;
    2392             : 
    2393           0 :         switch (cid) {
    2394             :         case MBIM_CID_DEVICE_CAPS:
    2395           0 :                 ok = umb_decode_devices_caps(sc, data, len);
    2396           0 :                 break;
    2397             :         case MBIM_CID_SUBSCRIBER_READY_STATUS:
    2398           0 :                 ok = umb_decode_subscriber_status(sc, data, len);
    2399           0 :                 break;
    2400             :         case MBIM_CID_RADIO_STATE:
    2401           0 :                 ok = umb_decode_radio_state(sc, data, len);
    2402           0 :                 break;
    2403             :         case MBIM_CID_PIN:
    2404           0 :                 ok = umb_decode_pin(sc, data, len);
    2405           0 :                 break;
    2406             :         case MBIM_CID_REGISTER_STATE:
    2407           0 :                 ok = umb_decode_register_state(sc, data, len);
    2408           0 :                 break;
    2409             :         case MBIM_CID_PACKET_SERVICE:
    2410           0 :                 ok = umb_decode_packet_service(sc, data, len);
    2411           0 :                 break;
    2412             :         case MBIM_CID_SIGNAL_STATE:
    2413           0 :                 ok = umb_decode_signal_state(sc, data, len);
    2414           0 :                 break;
    2415             :         case MBIM_CID_CONNECT:
    2416           0 :                 ok = umb_decode_connect_info(sc, data, len);
    2417           0 :                 break;
    2418             :         case MBIM_CID_IP_CONFIGURATION:
    2419           0 :                 ok = umb_decode_ip_configuration(sc, data, len);
    2420           0 :                 break;
    2421             :         default:
    2422             :                 /*
    2423             :                  * Note: the above list is incomplete and only contains
    2424             :                  *      mandatory CIDs from the BASIC_CONNECT set.
    2425             :                  *      So alternate values are not unusual.
    2426             :                  */
    2427             :                 DPRINTFN(4, "%s: ignore %s\n", DEVNAM(sc), umb_cid2str(cid));
    2428             :                 break;
    2429             :         }
    2430             :         if (!ok)
    2431             :                 DPRINTF("%s: discard %s with bad info length %d\n",
    2432             :                     DEVNAM(sc), umb_cid2str(cid), len);
    2433             :         return;
    2434           0 : }
    2435             : 
    2436             : void
    2437           0 : umb_decode_qmi(struct umb_softc *sc, uint8_t *data, int len)
    2438             : {
    2439             :         uint8_t srv;
    2440             :         uint16_t msg, tlvlen;
    2441             :         uint32_t val;
    2442             : 
    2443             : #define UMB_QMI_QMUXLEN         6
    2444           0 :         if (len < UMB_QMI_QMUXLEN)
    2445             :                 goto tooshort;
    2446             : 
    2447           0 :         srv = data[4];
    2448           0 :         data += UMB_QMI_QMUXLEN;
    2449           0 :         len -= UMB_QMI_QMUXLEN;
    2450             : 
    2451             : #define UMB_GET16(p)    ((uint16_t)*p | (uint16_t)*(p + 1) << 8)
    2452             : #define UMB_GET32(p)    ((uint32_t)*p | (uint32_t)*(p + 1) << 8 | \
    2453             :                             (uint32_t)*(p + 2) << 16 |(uint32_t)*(p + 3) << 24)
    2454           0 :         switch (srv) {
    2455             :         case 0: /* ctl */
    2456             : #define UMB_QMI_CTLLEN          6
    2457           0 :                 if (len < UMB_QMI_CTLLEN)
    2458             :                         goto tooshort;
    2459           0 :                 msg = UMB_GET16(&data[2]);
    2460           0 :                 tlvlen = UMB_GET16(&data[4]);
    2461           0 :                 data += UMB_QMI_CTLLEN;
    2462           0 :                 len -= UMB_QMI_CTLLEN;
    2463           0 :                 break;
    2464             :         case 2: /* dms  */
    2465             : #define UMB_QMI_DMSLEN          7
    2466           0 :                 if (len < UMB_QMI_DMSLEN)
    2467             :                         goto tooshort;
    2468           0 :                 msg = UMB_GET16(&data[3]);
    2469           0 :                 tlvlen = UMB_GET16(&data[5]);
    2470           0 :                 data += UMB_QMI_DMSLEN;
    2471           0 :                 len -= UMB_QMI_DMSLEN;
    2472           0 :                 break;
    2473             :         default:
    2474             :                 DPRINTF("%s: discard QMI message for unknown service type %d\n",
    2475             :                     DEVNAM(sc), srv);
    2476           0 :                 return;
    2477             :         }
    2478             : 
    2479           0 :         if (len < tlvlen)
    2480             :                 goto tooshort;
    2481             : 
    2482             : #define UMB_QMI_TLVLEN          3
    2483           0 :         while (len > 0) {
    2484           0 :                 if (len < UMB_QMI_TLVLEN)
    2485             :                         goto tooshort;
    2486           0 :                 tlvlen = UMB_GET16(&data[1]);
    2487           0 :                 if (len < UMB_QMI_TLVLEN + tlvlen)
    2488             :                         goto tooshort;
    2489           0 :                 switch (data[0]) {
    2490             :                 case 1: /* allocation info */
    2491           0 :                         if (msg == 0x0022) {    /* Allocate CID */
    2492           0 :                                 if (tlvlen != 2 || data[3] != 2) /* dms */
    2493             :                                         break;
    2494           0 :                                 sc->sc_cid = data[4];
    2495             :                                 DPRINTF("%s: QMI CID %d allocated\n",
    2496             :                                     DEVNAM(sc), sc->sc_cid);
    2497           0 :                                 umb_newstate(sc, UMB_S_CID, UMB_NS_DONT_DROP);
    2498           0 :                         }
    2499             :                         break;
    2500             :                 case 2: /* response */
    2501           0 :                         if (tlvlen != sizeof (val))
    2502             :                                 break;
    2503           0 :                         val = UMB_GET32(&data[3]);
    2504           0 :                         switch (msg) {
    2505             :                         case 0x0022:    /* Allocate CID */
    2506           0 :                                 if (val != 0) {
    2507           0 :                                         log(LOG_ERR, "%s: allocation of QMI CID"
    2508           0 :                                             " failed, error 0x%x\n", DEVNAM(sc),
    2509             :                                             val);
    2510             :                                         /* XXX how to proceed? */
    2511           0 :                                         return;
    2512             :                                 }
    2513             :                                 break;
    2514             :                         case 0x555f:    /* Send FCC Authentication */
    2515           0 :                                 if (val == 0)
    2516           0 :                                         log(LOG_INFO, "%s: send FCC "
    2517             :                                             "Authentication succeeded\n",
    2518           0 :                                             DEVNAM(sc));
    2519           0 :                                 else if (val == 0x001a0001)
    2520           0 :                                         log(LOG_INFO, "%s: FCC Authentication "
    2521             :                                             "not required\n", DEVNAM(sc));
    2522             :                                 else
    2523           0 :                                         log(LOG_INFO, "%s: send FCC "
    2524             :                                             "Authentication failed, "
    2525             :                                             "error 0x%x\n", DEVNAM(sc), val);
    2526             : 
    2527             :                                 /* FCC Auth is needed only once after power-on*/
    2528           0 :                                 sc->sc_flags &= ~UMBFLG_FCC_AUTH_REQUIRED;
    2529             : 
    2530             :                                 /* Try to proceed anyway */
    2531             :                                 DPRINTF("%s: init: turning radio on ...\n",
    2532             :                                     DEVNAM(sc));
    2533           0 :                                 umb_radio(sc, 1);
    2534           0 :                                 break;
    2535             :                         default:
    2536             :                                 break;
    2537             :                         }
    2538             :                         break;
    2539             :                 default:
    2540             :                         break;
    2541             :                 }
    2542           0 :                 data += UMB_QMI_TLVLEN + tlvlen;
    2543           0 :                 len -= UMB_QMI_TLVLEN + tlvlen;
    2544             :         }
    2545           0 :         return;
    2546             : 
    2547             : tooshort:
    2548             :         DPRINTF("%s: discard short QMI message\n", DEVNAM(sc));
    2549           0 :         return;
    2550           0 : }
    2551             : 
    2552             : void
    2553           0 : umb_intr(struct usbd_xfer *xfer, void *priv, usbd_status status)
    2554             : {
    2555           0 :         struct umb_softc *sc = priv;
    2556           0 :         struct ifnet *ifp = GET_IFP(sc);
    2557           0 :         int      total_len;
    2558             : 
    2559           0 :         if (status != USBD_NORMAL_COMPLETION) {
    2560             :                 DPRINTF("%s: notification error: %s\n", DEVNAM(sc),
    2561             :                     usbd_errstr(status));
    2562           0 :                 if (status == USBD_STALLED)
    2563           0 :                         usbd_clear_endpoint_stall_async(sc->sc_ctrl_pipe);
    2564           0 :                 return;
    2565             :         }
    2566           0 :         usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
    2567           0 :         if (total_len < UCDC_NOTIFICATION_LENGTH) {
    2568             :                 DPRINTF("%s: short notification (%d<%d)\n", DEVNAM(sc),
    2569             :                     total_len, UCDC_NOTIFICATION_LENGTH);
    2570           0 :                     return;
    2571             :         }
    2572           0 :         if (sc->sc_intr_msg.bmRequestType != UCDC_NOTIFICATION) {
    2573             :                 DPRINTF("%s: unexpected notification (type=0x%02x)\n",
    2574             :                     DEVNAM(sc), sc->sc_intr_msg.bmRequestType);
    2575           0 :                 return;
    2576             :         }
    2577             : 
    2578           0 :         switch (sc->sc_intr_msg.bNotification) {
    2579             :         case UCDC_N_NETWORK_CONNECTION:
    2580           0 :                 if (ifp->if_flags & IFF_DEBUG)
    2581           0 :                         log(LOG_DEBUG, "%s: network %sconnected\n", DEVNAM(sc),
    2582           0 :                             UGETW(sc->sc_intr_msg.wValue) ? "" : "dis");
    2583             :                 break;
    2584             :         case UCDC_N_RESPONSE_AVAILABLE:
    2585             :                 DPRINTFN(2, "%s: umb_intr: response available\n", DEVNAM(sc));
    2586           0 :                 ++sc->sc_nresp;
    2587           0 :                 usb_add_task(sc->sc_udev, &sc->sc_get_response_task);
    2588           0 :                 break;
    2589             :         case UCDC_N_CONNECTION_SPEED_CHANGE:
    2590             :                 DPRINTFN(2, "%s: umb_intr: connection speed changed\n",
    2591             :                     DEVNAM(sc));
    2592             :                 break;
    2593             :         default:
    2594             :                 DPRINTF("%s: unexpected notifiation (0x%02x)\n",
    2595             :                     DEVNAM(sc), sc->sc_intr_msg.bNotification);
    2596             :                 break;
    2597             :         }
    2598           0 : }
    2599             : 
    2600             : /*
    2601             :  * Diagnostic routines
    2602             :  */
    2603             : char *
    2604           0 : umb_ntop(struct sockaddr *sa)
    2605             : {
    2606             : #define NUMBUFS         4
    2607             :         static char astr[NUMBUFS][INET_ADDRSTRLEN];
    2608             :         static unsigned nbuf = 0;
    2609             :         char    *s;
    2610             : 
    2611           0 :         s = astr[nbuf++];
    2612           0 :         if (nbuf >= NUMBUFS)
    2613           0 :                 nbuf = 0;
    2614             : 
    2615           0 :         switch (sa->sa_family) {
    2616             :         case AF_INET:
    2617             :         default:
    2618           0 :                 inet_ntop(AF_INET, &satosin(sa)->sin_addr, s, sizeof (astr[0]));
    2619           0 :                 break;
    2620             :         case AF_INET6:
    2621           0 :                 inet_ntop(AF_INET6, &satosin6(sa)->sin6_addr, s,
    2622             :                     sizeof (astr[0]));
    2623           0 :                 break;
    2624             :         }
    2625           0 :         return s;
    2626             : }
    2627             : 
    2628             : #ifdef UMB_DEBUG
    2629             : char *
    2630             : umb_uuid2str(uint8_t uuid[MBIM_UUID_LEN])
    2631             : {
    2632             :         static char uuidstr[2 * MBIM_UUID_LEN + 5];
    2633             : 
    2634             : #define UUID_BFMT       "%02X"
    2635             : #define UUID_SEP        "-"
    2636             :         snprintf(uuidstr, sizeof (uuidstr),
    2637             :             UUID_BFMT UUID_BFMT UUID_BFMT UUID_BFMT UUID_SEP
    2638             :             UUID_BFMT UUID_BFMT UUID_SEP
    2639             :             UUID_BFMT UUID_BFMT UUID_SEP
    2640             :             UUID_BFMT UUID_BFMT UUID_SEP
    2641             :             UUID_BFMT UUID_BFMT UUID_BFMT UUID_BFMT UUID_BFMT UUID_BFMT,
    2642             :             uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5],
    2643             :             uuid[6], uuid[7], uuid[8], uuid[9], uuid[10], uuid[11],
    2644             :             uuid[12], uuid[13], uuid[14], uuid[15]);
    2645             :         return uuidstr;
    2646             : }
    2647             : 
    2648             : void
    2649             : umb_dump(void *buf, int len)
    2650             : {
    2651             :         int      i = 0;
    2652             :         uint8_t *c = buf;
    2653             : 
    2654             :         if (len == 0)
    2655             :                 return;
    2656             :         while (i < len) {
    2657             :                 if ((i % 16) == 0) {
    2658             :                         if (i > 0)
    2659             :                                 addlog("\n");
    2660             :                         log(LOG_DEBUG, "%4d:  ", i);
    2661             :                 }
    2662             :                 addlog(" %02x", *c);
    2663             :                 c++;
    2664             :                 i++;
    2665             :         }
    2666             :         addlog("\n");
    2667             : }
    2668             : #endif /* UMB_DEBUG */

Generated by: LCOV version 1.13