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