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 */
|