Bug Summary

File:dev/usb/if_umb.c
Warning:line 2344, column 3
Dereference of null pointer

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name if_umb.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -relaxed-aliasing -ffp-contract=on -fno-rounding-math -mconstructor-aliases -ffreestanding -mcmodel=kernel -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -target-feature -sse2 -target-feature -sse -target-feature -3dnow -target-feature -mmx -target-feature +save-args -target-feature +retpoline-external-thunk -disable-red-zone -no-implicit-float -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -nostdsysteminc -nobuiltininc -resource-dir /usr/local/llvm16/lib/clang/16 -I /usr/src/sys -I /usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -I /usr/src/sys/arch -I /usr/src/sys/dev/pci/drm/include -I /usr/src/sys/dev/pci/drm/include/uapi -I /usr/src/sys/dev/pci/drm/amd/include/asic_reg -I /usr/src/sys/dev/pci/drm/amd/include -I /usr/src/sys/dev/pci/drm/amd/amdgpu -I /usr/src/sys/dev/pci/drm/amd/display -I /usr/src/sys/dev/pci/drm/amd/display/include -I /usr/src/sys/dev/pci/drm/amd/display/dc -I /usr/src/sys/dev/pci/drm/amd/display/amdgpu_dm -I /usr/src/sys/dev/pci/drm/amd/pm/inc -I /usr/src/sys/dev/pci/drm/amd/pm/legacy-dpm -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/inc -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu11 -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu12 -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu13 -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/inc -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/hwmgr -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/smumgr -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/inc -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/inc/pmfw_if -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc/hw -I /usr/src/sys/dev/pci/drm/amd/display/dc/clk_mgr -I /usr/src/sys/dev/pci/drm/amd/display/modules/inc -I /usr/src/sys/dev/pci/drm/amd/display/modules/hdcp -I /usr/src/sys/dev/pci/drm/amd/display/dmub/inc -I /usr/src/sys/dev/pci/drm/i915 -D DDB -D DIAGNOSTIC -D KTRACE -D ACCOUNTING -D KMEMSTATS -D PTRACE -D POOL_DEBUG -D CRYPTO -D SYSVMSG -D SYSVSEM -D SYSVSHM -D UVM_SWAP_ENCRYPT -D FFS -D FFS2 -D FFS_SOFTUPDATES -D UFS_DIRHASH -D QUOTA -D EXT2FS -D MFS -D NFSCLIENT -D NFSSERVER -D CD9660 -D UDF -D MSDOSFS -D FIFO -D FUSE -D SOCKET_SPLICE -D TCP_ECN -D TCP_SIGNATURE -D INET6 -D IPSEC -D PPP_BSDCOMP -D PPP_DEFLATE -D PIPEX -D MROUTING -D MPLS -D BOOT_CONFIG -D USER_PCICONF -D APERTURE -D MTRR -D NTFS -D SUSPEND -D HIBERNATE -D PCIVERBOSE -D USBVERBOSE -D WSDISPLAY_COMPAT_USL -D WSDISPLAY_COMPAT_RAWKBD -D WSDISPLAY_DEFAULTSCREENS=6 -D X86EMU -D ONEWIREVERBOSE -D MULTIPROCESSOR -D MAXUSERS=80 -D _KERNEL -O2 -Wno-pointer-sign -Wno-address-of-packed-member -Wno-constant-conversion -Wno-unused-but-set-variable -Wno-gnu-folding-constant -fdebug-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fcf-protection=branch -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -o /home/ben/Projects/scan/2024-01-11-110808-61670-1 -x c /usr/src/sys/dev/usb/if_umb.c
1/* $OpenBSD: if_umb.c,v 1.56 2023/10/24 09:13:22 jmatthew 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 * https://www.usb.org/sites/default/files/MBIM10Errata1_073013.zip
23 * Compliance testing guide
24 * https://www.usb.org/sites/default/files/MBIM-Compliance-1.0.pdf
25 */
26
27#include "bpfilter.h"
28#include "kstat.h"
29
30#include <sys/param.h>
31#include <sys/mbuf.h>
32#include <sys/socket.h>
33#include <sys/systm.h>
34#include <sys/syslog.h>
35#include <sys/kstat.h>
36
37#if NBPFILTER1 > 0
38#include <net/bpf.h>
39#endif
40#include <net/if.h>
41#include <net/if_var.h>
42#include <net/if_types.h>
43#include <net/route.h>
44
45#include <netinet/in.h>
46#include <netinet/in_var.h>
47#include <netinet/ip.h>
48
49#ifdef INET61
50#include <netinet/ip6.h>
51#include <netinet6/in6_var.h>
52#include <netinet6/ip6_var.h>
53#include <netinet6/in6_ifattach.h>
54#include <netinet6/nd6.h>
55#endif
56
57#include <machine/bus.h>
58
59#include <dev/usb/usb.h>
60#include <dev/usb/usbdi.h>
61#include <dev/usb/usbdivar.h>
62#include <dev/usb/usbdi_util.h>
63#include <dev/usb/usbdevs.h>
64#include <dev/usb/usbcdc.h>
65
66#include <dev/usb/mbim.h>
67#include <dev/usb/if_umb.h>
68
69#ifdef UMB_DEBUG
70#define DPRINTF(x...)do { } while (0) \
71 do { if (umb_debug) log(LOG_DEBUG7, x); } while (0)
72
73#define DPRINTFN(n, x...)do { } while (0) \
74 do { if (umb_debug >= (n)) log(LOG_DEBUG7, x); } while (0)
75
76#define DDUMPN(n, b, l)do { } while (0) \
77 do { \
78 if (umb_debug >= (n)) \
79 umb_dump((b), (l)); \
80 } while (0)
81
82int umb_debug = 0;
83char *umb_uuid2str(uint8_t [MBIM_UUID_LEN16]);
84void umb_dump(void *, int);
85
86#else
87#define DPRINTF(x...)do { } while (0) do { } while (0)
88#define DPRINTFN(n, x...)do { } while (0) do { } while (0)
89#define DDUMPN(n, b, l)do { } while (0) do { } while (0)
90#endif
91
92#define DEVNAM(sc)(((struct umb_softc *)(sc))->sc_dev.dv_xname) (((struct umb_softc *)(sc))->sc_dev.dv_xname)
93
94/*
95 * State change timeout
96 */
97#define UMB_STATE_CHANGE_TIMEOUT30 30
98
99/*
100 * State change flags
101 */
102#define UMB_NS_DONT_DROP0x0001 0x0001 /* do not drop below current state */
103#define UMB_NS_DONT_RAISE0x0002 0x0002 /* do not raise below current state */
104
105/*
106 * Diagnostic macros
107 */
108const struct umb_valdescr umb_regstates[] = MBIM_REGSTATE_DESCRIPTIONS{ { 0, "unknown" }, { 1, "not registered" }, { 2, "searching"
}, { 3, "home network" }, { 4, "roaming network" }, { 5, "partner network"
}, { 6, "access denied" }, { 0, ((void *)0) } }
;
109const struct umb_valdescr umb_dataclasses[] = MBIM_DATACLASS_DESCRIPTIONS{ { 0x00000000, "none" }, { 0x00000001, "GPRS" }, { 0x00000002
, "EDGE" }, { 0x00000004, "UMTS" }, { 0x00000008, "HSDPA" }, {
0x00000010, "HSUPA" }, { 0x00000008|0x00000010, "HSPA" }, { 0x00000020
, "LTE" }, { 0x00010000, "CDMA2000" }, { 0x00020000, "CDMA2000"
}, { 0x00040000, "CDMA2000" }, { 0x00080000, "CDMA2000" }, {
0x00100000, "CDMA2000" }, { 0x00200000, "CDMA2000" }, { 0x00400000
, "CDMA2000" }, { 0x80000000, "custom" }, { 0, ((void *)0) } }
;
110const struct umb_valdescr umb_simstate[] = MBIM_SIMSTATE_DESCRIPTIONS{ { 0, "not initialized" }, { 1, "initialized" }, { 2, "not inserted"
}, { 3, "bad type" }, { 4, "failed" }, { 5, "not activated" }
, { 6, "locked" }, { 0, ((void *)0) } }
;
111const struct umb_valdescr umb_messages[] = MBIM_MESSAGES_DESCRIPTIONS{ { (1U), "MBIM_OPEN_MSG" }, { (2U), "MBIM_CLOSE_MSG" }, { (3U
), "MBIM_COMMAND_MSG" }, { (4U), "MBIM_HOST_ERROR_MSG" }, { (
0x80000001U), "MBIM_OPEN_DONE" }, { (0x80000002U), "MBIM_CLOSE_DONE"
}, { (0x80000003U), "MBIM_COMMAND_DONE" }, { (0x80000004U), "MBIM_FUNCTION_ERROR_MSG"
}, { (0x80000007U), "MBIM_INDICATE_STATUS_MSG" }, { 0, ((void
*)0) } }
;
112const struct umb_valdescr umb_status[] = MBIM_STATUS_DESCRIPTIONS{ { 0, "SUCCESS" }, { 1, "BUSY" }, { 2, "FAILURE" }, { 3, "SIM_NOT_INSERTED"
}, { 4, "BAD_SIM" }, { 5, "PIN_REQUIRED" }, { 6, "PIN_DISABLED"
}, { 7, "NOT_REGISTERED" }, { 8, "PROVIDERS_NOT_FOUND" }, { 9
, "NO_DEVICE_SUPPORT" }, { 10, "PROVIDER_NOT_VISIBLE" }, { 11
, "DATA_CLASS_NOT_AVAILABLE" }, { 12, "PACKET_SERVICE_DETACHED"
}, { 13, "MAX_ACTIVATED_CONTEXTS" }, { 14, "NOT_INITIALIZED"
}, { 15, "VOICE_CALL_IN_PROGRESS" }, { 16, "CONTEXT_NOT_ACTIVATED"
}, { 17, "SERVICE_NOT_ACTIVATED" }, { 18, "INVALID_ACCESS_STRING"
}, { 19, "INVALID_USER_NAME_PWD" }, { 20, "RADIO_POWER_OFF" }
, { 21, "INVALID_PARAMETERS" }, { 22, "READ_FAILURE" }, { 23,
"WRITE_FAILURE" }, { 25, "NO_PHONEBOOK" }, { 26, "PARAMETER_TOO_LONG"
}, { 27, "STK_BUSY" }, { 28, "OPERATION_NOT_ALLOWED" }, { 29
, "MEMORY_FAILURE" }, { 30, "INVALID_MEMORY_INDEX" }, { 31, "MEMORY_FULL"
}, { 32, "FILTER_NOT_SUPPORTED" }, { 33, "DSS_INSTANCE_LIMIT"
}, { 34, "INVALID_DEVICE_SERVICE_OPERATION" }, { 35, "AUTH_INCORRECT_AUTN"
}, { 36, "AUTH_SYNC_FAILURE" }, { 37, "AUTH_AMF_NOT_SET" }, {
38, "CONTEXT_NOT_SUPPORTED" }, { 100, "SMS_UNKNOWN_SMSC_ADDRESS"
}, { 101, "SMS_NETWORK_TIMEOUT" }, { 102, "SMS_LANG_NOT_SUPPORTED"
}, { 103, "SMS_ENCODING_NOT_SUPPORTED" }, { 104, "SMS_FORMAT_NOT_SUPPORTED"
}, { 0, ((void *)0) } }
;
113const struct umb_valdescr umb_cids[] = MBIM_CID_DESCRIPTIONS{ { (1), "MBIM_CID_DEVICE_CAPS" }, { (2), "MBIM_CID_SUBSCRIBER_READY_STATUS"
}, { (3), "MBIM_CID_RADIO_STATE" }, { (4), "MBIM_CID_PIN" },
{ (5), "MBIM_CID_PIN_LIST" }, { (6), "MBIM_CID_HOME_PROVIDER"
}, { (7), "MBIM_CID_PREFERRED_PROVIDERS" }, { (8), "MBIM_CID_VISIBLE_PROVIDERS"
}, { (9), "MBIM_CID_REGISTER_STATE" }, { (10), "MBIM_CID_PACKET_SERVICE"
}, { (11), "MBIM_CID_SIGNAL_STATE" }, { (12), "MBIM_CID_CONNECT"
}, { (13), "MBIM_CID_PROVISIONED_CONTEXTS" }, { (14), "MBIM_CID_SERVICE_ACTIVATION"
}, { (15), "MBIM_CID_IP_CONFIGURATION" }, { (16), "MBIM_CID_DEVICE_SERVICES"
}, { (19), "MBIM_CID_DEVICE_SERVICE_SUBSCRIBE_LIST" }, { (20
), "MBIM_CID_PACKET_STATISTICS" }, { (21), "MBIM_CID_NETWORK_IDLE_HINT"
}, { (22), "MBIM_CID_EMERGENCY_MODE" }, { (23), "MBIM_CID_IP_PACKET_FILTERS"
}, { (24), "MBIM_CID_MULTICARRIER_PROVIDERS" }, { 0, ((void *
)0) } }
;
114const struct umb_valdescr umb_pktstate[] = MBIM_PKTSRV_STATE_DESCRIPTIONS{ { 0, "unknown" }, { 1, "attaching" }, { 2, "attached" }, { 3
, "detaching" }, { 4, "detached" }, { 0, ((void *)0) } }
;
115const struct umb_valdescr umb_actstate[] = MBIM_ACTIVATION_STATE_DESCRIPTIONS{ { 0, "unknown" }, { 1, "activated" }, { 2, "activating" }, {
3, "deactivated" }, { 4, "deactivating" }, { 0, ((void *)0) }
}
;
116const struct umb_valdescr umb_error[] = MBIM_ERROR_DESCRIPTIONS{ { 1, "TIMEOUT_FRAGMENT" }, { 2, "FRAGMENT_OUT_OF_SEQUENCE" }
, { 3, "LENGTH_MISMATCH" }, { 4, "DUPLICATED_TID" }, { 5, "NOT_OPENED"
}, { 6, "UNKNOWN" }, { 7, "CANCEL" }, { 8, "MAX_TRANSFER" },
{ 0, ((void *)0) } }
;
117const struct umb_valdescr umb_pintype[] = MBIM_PINTYPE_DESCRIPTIONS{ { 0, "none" }, { 1, "custom" }, { 2, "PIN1" }, { 3, "PIN2" }
, { 4, "device PIN" }, { 5, "device 1st PIN" }, { 6, "network PIN"
}, { 7, "network subset PIN" }, { 8, "provider PIN" }, { 9, "corporate PIN"
}, { 10, "subsidy lock" }, { 11, "PUK" }, { 12, "PUK2" }, { 13
, "device 1st PUK" }, { 14, "network PUK" }, { 15, "network subset PUK"
}, { 16, "provider PUK" }, { 17, "corporate PUK" }, { 0, ((void
*)0) } }
;
118const struct umb_valdescr umb_istate[] = UMB_INTERNAL_STATE_DESCRIPTIONS{ { UMB_S_DOWN, "down" }, { UMB_S_OPEN, "open" }, { UMB_S_CID
, "CID allocated" }, { UMB_S_RADIO, "radio on" }, { UMB_S_SIMREADY
, "SIM is ready" }, { UMB_S_ATTACHED, "attached" }, { UMB_S_CONNECTED
, "connected" }, { UMB_S_UP, "up" }, { 0, ((void *)0) } }
;
119
120#define umb_regstate(c)umb_val2descr(umb_regstates, (c)) umb_val2descr(umb_regstates, (c))
121#define umb_dataclass(c)umb_val2descr(umb_dataclasses, (c)) umb_val2descr(umb_dataclasses, (c))
122#define umb_simstate(s)umb_val2descr(umb_simstate, (s)) umb_val2descr(umb_simstate, (s))
123#define umb_request2str(m)umb_val2descr(umb_messages, (m)) umb_val2descr(umb_messages, (m))
124#define umb_status2str(s)umb_val2descr(umb_status, (s)) umb_val2descr(umb_status, (s))
125#define umb_cid2str(c)umb_val2descr(umb_cids, (c)) umb_val2descr(umb_cids, (c))
126#define umb_packet_state(s)umb_val2descr(umb_pktstate, (s)) umb_val2descr(umb_pktstate, (s))
127#define umb_activation(s)umb_val2descr(umb_actstate, (s)) umb_val2descr(umb_actstate, (s))
128#define umb_error2str(e)umb_val2descr(umb_error, (e)) umb_val2descr(umb_error, (e))
129#define umb_pin_type(t)umb_val2descr(umb_pintype, (t)) umb_val2descr(umb_pintype, (t))
130#define umb_istate(s)umb_val2descr(umb_istate, (s)) umb_val2descr(umb_istate, (s))
131
132int umb_match(struct device *, void *, void *);
133void umb_attach(struct device *, struct device *, void *);
134int umb_detach(struct device *, int);
135void umb_ncm_setup(struct umb_softc *);
136void umb_ncm_setup_format(struct umb_softc *);
137int umb_alloc_xfers(struct umb_softc *);
138void umb_free_xfers(struct umb_softc *);
139int umb_alloc_bulkpipes(struct umb_softc *);
140void umb_close_bulkpipes(struct umb_softc *);
141int umb_ioctl(struct ifnet *, u_long, caddr_t);
142int umb_output(struct ifnet *, struct mbuf *, struct sockaddr *,
143 struct rtentry *);
144void umb_start(struct ifnet *);
145void umb_rtrequest(struct ifnet *, int, struct rtentry *);
146void umb_watchdog(struct ifnet *);
147void umb_statechg_timeout(void *);
148
149void umb_newstate(struct umb_softc *, enum umb_state, int);
150void umb_state_task(void *);
151void umb_up(struct umb_softc *);
152void umb_down(struct umb_softc *, int);
153
154void umb_get_response_task(void *);
155
156void umb_decode_response(struct umb_softc *, void *, int);
157void umb_handle_indicate_status_msg(struct umb_softc *, void *,
158 int);
159void umb_handle_opendone_msg(struct umb_softc *, void *, int);
160void umb_handle_closedone_msg(struct umb_softc *, void *, int);
161int umb_decode_register_state(struct umb_softc *, void *, int);
162int umb_decode_devices_caps(struct umb_softc *, void *, int);
163int umb_decode_subscriber_status(struct umb_softc *, void *, int);
164int umb_decode_radio_state(struct umb_softc *, void *, int);
165int umb_decode_pin(struct umb_softc *, void *, int);
166int umb_decode_packet_service(struct umb_softc *, void *, int);
167int umb_decode_signal_state(struct umb_softc *, void *, int);
168int umb_decode_connect_info(struct umb_softc *, void *, int);
169void umb_clear_addr(struct umb_softc *);
170int umb_add_inet_config(struct umb_softc *, struct in_addr, u_int,
171 struct in_addr);
172int umb_add_inet6_config(struct umb_softc *, struct in6_addr *,
173 u_int, struct in6_addr *);
174void umb_send_inet_proposal(struct umb_softc *, int);
175int umb_decode_ip_configuration(struct umb_softc *, void *, int);
176void umb_rx(struct umb_softc *);
177void umb_rxeof(struct usbd_xfer *, void *, usbd_status);
178int umb_encap(struct umb_softc *, int);
179void umb_txeof(struct usbd_xfer *, void *, usbd_status);
180void umb_decap(struct umb_softc *, struct usbd_xfer *);
181
182usbd_status umb_send_encap_command(struct umb_softc *, void *, int);
183int umb_get_encap_response(struct umb_softc *, void *, int *);
184void umb_ctrl_msg(struct umb_softc *, uint32_t, void *, int);
185
186void umb_open(struct umb_softc *);
187void umb_close(struct umb_softc *);
188
189int umb_setpin(struct umb_softc *, int, int, void *, int, void *,
190 int);
191void umb_setdataclass(struct umb_softc *);
192void umb_radio(struct umb_softc *, int);
193void umb_allocate_cid(struct umb_softc *);
194void umb_send_fcc_auth(struct umb_softc *);
195void umb_packet_service(struct umb_softc *, int);
196void umb_connect(struct umb_softc *);
197void umb_disconnect(struct umb_softc *);
198void umb_send_connect(struct umb_softc *, int);
199
200void umb_qry_ipconfig(struct umb_softc *);
201void umb_cmd(struct umb_softc *, int, int, void *, int);
202void umb_cmd1(struct umb_softc *, int, int, void *, int, uint8_t *);
203void umb_command_done(struct umb_softc *, void *, int);
204void umb_decode_cid(struct umb_softc *, uint32_t, void *, int);
205void umb_decode_qmi(struct umb_softc *, uint8_t *, int);
206
207void umb_intr(struct usbd_xfer *, void *, usbd_status);
208
209#if NKSTAT1 > 0
210void umb_kstat_attach(struct umb_softc *);
211void umb_kstat_detach(struct umb_softc *);
212
213struct umb_kstat_signal {
214 struct kstat_kv rssi;
215 struct kstat_kv error_rate;
216 struct kstat_kv reports;
217};
218#endif
219
220int umb_xfer_tout = USBD_DEFAULT_TIMEOUT5000;
221
222uint8_t umb_uuid_basic_connect[] = MBIM_UUID_BASIC_CONNECT{ 0xa2, 0x89, 0xcc, 0x33, 0xbc, 0xbb, 0x8b, 0x4f, 0xb6, 0xb0,
0x13, 0x3e, 0xc2, 0xaa, 0xe6, 0xdf }
;
223uint8_t umb_uuid_context_internet[] = MBIM_UUID_CONTEXT_INTERNET{ 0x7e, 0x5e, 0x2a, 0x7e, 0x4e, 0x6f, 0x72, 0x72, 0x73, 0x6b,
0x65, 0x6e, 0x7e, 0x5e, 0x2a, 0x7e }
;
224uint8_t umb_uuid_qmi_mbim[] = MBIM_UUID_QMI_MBIM{ 0xd1, 0xa3, 0x0b, 0xc2, 0xf9, 0x7a, 0x6e, 0x43, 0xbf, 0x65,
0xc7, 0xe2, 0x4f, 0xb0, 0xf0, 0xd3 }
;
225uint32_t umb_session_id = 0;
226
227struct cfdriver umb_cd = {
228 NULL((void *)0), "umb", DV_IFNET
229};
230
231const struct cfattach umb_ca = {
232 sizeof (struct umb_softc),
233 umb_match,
234 umb_attach,
235 umb_detach,
236 NULL((void *)0),
237};
238
239int umb_delay = 4000;
240
241struct umb_quirk {
242 struct usb_devno dev;
243 u_int32_t umb_flags;
244 int umb_confno;
245 int umb_match;
246};
247const struct umb_quirk umb_quirks[] = {
248 { { USB_VENDOR_DELL0x413c, USB_PRODUCT_DELL_DW5821E0x81d7 },
249 0,
250 2,
251 UMATCH_VENDOR_PRODUCT13
252 },
253
254 { { USB_VENDOR_HUAWEI0x12d1, USB_PRODUCT_HUAWEI_ME906S0x15c1 },
255 UMBFLG_NDP_AT_END0x0004,
256 3,
257 UMATCH_VENDOR_PRODUCT13
258 },
259
260 { { USB_VENDOR_SIERRA0x1199, USB_PRODUCT_SIERRA_EM74550x9079 },
261 UMBFLG_FCC_AUTH_REQUIRED0x0001,
262 0,
263 0
264 },
265
266 { { USB_VENDOR_SIMCOM0x1e0e, USB_PRODUCT_SIMCOM_SIM76000x9003 },
267 0,
268 1,
269 UMATCH_VENDOR_PRODUCT13
270 },
271};
272
273#define umb_lookup(vid, pid)((const struct umb_quirk *)usbd_match_device((const struct usb_devno
*)(umb_quirks), sizeof (umb_quirks) / sizeof ((umb_quirks)[0
]), sizeof ((umb_quirks)[0]), (vid), (pid)))
\
274 ((const struct umb_quirk *)usb_lookup(umb_quirks, vid, pid)usbd_match_device((const struct usb_devno *)(umb_quirks), sizeof
(umb_quirks) / sizeof ((umb_quirks)[0]), sizeof ((umb_quirks
)[0]), (vid), (pid))
)
275
276uint8_t umb_qmi_alloc_cid[] = {
277 0x01,
278 0x0f, 0x00, /* len */
279 0x00, /* QMUX flags */
280 0x00, /* service "ctl" */
281 0x00, /* CID */
282 0x00, /* QMI flags */
283 0x01, /* transaction */
284 0x22, 0x00, /* msg "Allocate CID" */
285 0x04, 0x00, /* TLV len */
286 0x01, 0x01, 0x00, 0x02 /* TLV */
287};
288
289uint8_t umb_qmi_fcc_auth[] = {
290 0x01,
291 0x0c, 0x00, /* len */
292 0x00, /* QMUX flags */
293 0x02, /* service "dms" */
294#define UMB_QMI_CID_OFFS5 5
295 0x00, /* CID (filled in later) */
296 0x00, /* QMI flags */
297 0x01, 0x00, /* transaction */
298 0x5f, 0x55, /* msg "Send FCC Authentication" */
299 0x00, 0x00 /* TLV len */
300};
301
302int
303umb_match(struct device *parent, void *match, void *aux)
304{
305 struct usb_attach_arg *uaa = aux;
306 const struct umb_quirk *quirk;
307 usb_interface_descriptor_t *id;
308
309 quirk = umb_lookup(uaa->vendor, uaa->product)((const struct umb_quirk *)usbd_match_device((const struct usb_devno
*)(umb_quirks), sizeof (umb_quirks) / sizeof ((umb_quirks)[0
]), sizeof ((umb_quirks)[0]), (uaa->vendor), (uaa->product
)))
;
310 if (quirk != NULL((void *)0) && quirk->umb_match)
311 return (quirk->umb_match);
312 if (!uaa->iface)
313 return UMATCH_NONE0;
314 if ((id = usbd_get_interface_descriptor(uaa->iface)) == NULL((void *)0))
315 return UMATCH_NONE0;
316
317 /*
318 * If this function implements NCM, check if alternate setting
319 * 1 implements MBIM.
320 */
321 if (id->bInterfaceClass == UICLASS_CDC0x02 &&
322 id->bInterfaceSubClass ==
323 UISUBCLASS_NETWORK_CONTROL_MODEL13)
324 id = usbd_find_idesc(uaa->device->cdesc, uaa->iface->index, 1);
325 if (id == NULL((void *)0))
326 return UMATCH_NONE0;
327
328 if (id->bInterfaceClass == UICLASS_CDC0x02 &&
329 id->bInterfaceSubClass ==
330 UISUBCLASS_MOBILE_BROADBAND_INTERFACE_MODEL14 &&
331 id->bInterfaceProtocol == 0)
332 return UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO5;
333
334 return UMATCH_NONE0;
335}
336
337void
338umb_attach(struct device *parent, struct device *self, void *aux)
339{
340 struct umb_softc *sc = (struct umb_softc *)self;
341 struct usb_attach_arg *uaa = aux;
342 const struct umb_quirk *quirk;
343 usbd_status status;
344 struct usbd_desc_iter iter;
345 const usb_descriptor_t *desc;
346 int v;
347 struct usb_cdc_union_descriptor *ud;
348 struct mbim_descriptor *md;
349 int i;
350 int ctrl_ep;
351 usb_interface_descriptor_t *id;
352 usb_config_descriptor_t *cd;
353 usb_endpoint_descriptor_t *ed;
354 usb_interface_assoc_descriptor_t *ad;
355 int current_ifaceno = -1;
356 int data_ifaceno = -1;
357 int altnum;
358 int s;
359 struct ifnet *ifp;
360
361 sc->sc_udev = uaa->device;
362 sc->sc_ctrl_ifaceno = uaa->ifaceno;
363 ml_init(&sc->sc_tx_ml);
364
365 quirk = umb_lookup(uaa->vendor, uaa->product)((const struct umb_quirk *)usbd_match_device((const struct usb_devno
*)(umb_quirks), sizeof (umb_quirks) / sizeof ((umb_quirks)[0
]), sizeof ((umb_quirks)[0]), (uaa->vendor), (uaa->product
)))
;
366 if (quirk != NULL((void *)0) && quirk->umb_flags) {
367 DPRINTF("%s: setting flags 0x%x from quirk\n", DEVNAM(sc),do { } while (0)
368 quirk->umb_flags)do { } while (0);
369 sc->sc_flags |= quirk->umb_flags;
370 }
371
372 /*
373 * Normally, MBIM devices are detected by their interface class and
374 * subclass. But for some models that have multiple configurations, it
375 * is better to match by vendor and product id so that we can select
376 * the desired configuration ourselves, e.g. to override a class-based
377 * match to another driver.
378 */
379 if (uaa->configno < 0) {
380 if (quirk == NULL((void *)0)) {
381 printf("%s: unknown configuration for vid/pid match\n",
382 DEVNAM(sc)(((struct umb_softc *)(sc))->sc_dev.dv_xname));
383 goto fail;
384 }
385 uaa->configno = quirk->umb_confno;
386 DPRINTF("%s: switching to config #%d\n", DEVNAM(sc),do { } while (0)
387 uaa->configno)do { } while (0);
388 status = usbd_set_config_no(sc->sc_udev, uaa->configno, 1);
389 if (status) {
390 printf("%s: failed to switch to config #%d: %s\n",
391 DEVNAM(sc)(((struct umb_softc *)(sc))->sc_dev.dv_xname), uaa->configno, usbd_errstr(status));
392 goto fail;
393 }
394 usbd_delay_ms(sc->sc_udev, 200);
395
396 /*
397 * Need to do some manual setup that usbd_probe_and_attach()
398 * would do for us otherwise.
399 */
400 uaa->nifaces = uaa->device->cdesc->bNumInterfaces;
401 for (i = 0; i < uaa->nifaces; i++) {
402 if (usbd_iface_claimed(sc->sc_udev, i))
403 continue;
404 id = usbd_get_interface_descriptor(&uaa->device->ifaces[i]);
405 if (id != NULL((void *)0) && id->bInterfaceClass == UICLASS_CDC0x02 &&
406 id->bInterfaceSubClass ==
407 UISUBCLASS_MOBILE_BROADBAND_INTERFACE_MODEL14) {
408 uaa->iface = &uaa->device->ifaces[i];
409 uaa->ifaceno = uaa->iface->idesc->bInterfaceNumber;
410 sc->sc_ctrl_ifaceno = uaa->ifaceno;
411 break;
412 }
413 }
414 }
415
416 /*
417 * Some MBIM hardware does not provide the mandatory CDC Union
418 * Descriptor, so we also look at matching Interface
419 * Association Descriptors to find out the MBIM Data Interface
420 * number.
421 */
422 sc->sc_ver_maj = sc->sc_ver_min = -1;
423 sc->sc_maxpktlen = MBIM_MAXSEGSZ_MINVAL(2 * 1024);
424 usbd_desc_iter_init(sc->sc_udev, &iter);
425 while ((desc = usbd_desc_iter_next(&iter))) {
426 if (desc->bDescriptorType == UDESC_IFACE_ASSOC0x0B) {
427 ad = (usb_interface_assoc_descriptor_t *)desc;
428 if (ad->bFirstInterface == uaa->ifaceno &&
429 ad->bInterfaceCount > 1)
430 data_ifaceno = uaa->ifaceno + 1;
431 continue;
432 }
433 if (desc->bDescriptorType == UDESC_INTERFACE0x04) {
434 id = (usb_interface_descriptor_t *)desc;
435 current_ifaceno = id->bInterfaceNumber;
436 continue;
437 }
438 if (current_ifaceno != uaa->ifaceno)
439 continue;
440 if (desc->bDescriptorType != UDESC_CS_INTERFACE0x24)
441 continue;
442 switch (desc->bDescriptorSubtype) {
443 case UDESCSUB_CDC_UNION6:
444 ud = (struct usb_cdc_union_descriptor *)desc;
445 data_ifaceno = ud->bSlaveInterface[0];
446 break;
447 case UDESCSUB_MBIM27:
448 md = (struct mbim_descriptor *)desc;
449 v = UGETW(md->bcdMBIMVersion)(*(u_int16_t *)(md->bcdMBIMVersion));
450 sc->sc_ver_maj = MBIM_VER_MAJOR(v)(((v) >> 8) & 0x0f);
451 sc->sc_ver_min = MBIM_VER_MINOR(v)((v) & 0x0f);
452 sc->sc_ctrl_len = UGETW(md->wMaxControlMessage)(*(u_int16_t *)(md->wMaxControlMessage));
453 /* Never trust a USB device! Could try to exploit us */
454 if (sc->sc_ctrl_len < MBIM_CTRLMSG_MINLEN64 ||
455 sc->sc_ctrl_len > MBIM_CTRLMSG_MAXLEN(4 * 1204)) {
456 DPRINTF("%s: control message len %d out of "do { } while (0)
457 "bounds [%d .. %d]\n", DEVNAM(sc),do { } while (0)
458 sc->sc_ctrl_len, MBIM_CTRLMSG_MINLEN,do { } while (0)
459 MBIM_CTRLMSG_MAXLEN)do { } while (0);
460 /* cont. anyway */
461 }
462 sc->sc_maxpktlen = UGETW(md->wMaxSegmentSize)(*(u_int16_t *)(md->wMaxSegmentSize));
463 DPRINTFN(2, "%s: ctrl_len=%d, maxpktlen=%d, cap=0x%x\n",do { } while (0)
464 DEVNAM(sc), sc->sc_ctrl_len, sc->sc_maxpktlen,do { } while (0)
465 md->bmNetworkCapabilities)do { } while (0);
466 break;
467 default:
468 break;
469 }
470 }
471 if (sc->sc_ver_maj < 0) {
472 printf("%s: missing MBIM descriptor\n", DEVNAM(sc)(((struct umb_softc *)(sc))->sc_dev.dv_xname));
473 goto fail;
474 }
475 if (sc->sc_flags & UMBFLG_FCC_AUTH_REQUIRED0x0001)
476 sc->sc_cid = -1;
477
478 for (i = 0; i < uaa->nifaces; i++) {
479 if (usbd_iface_claimed(sc->sc_udev, i))
480 continue;
481 id = usbd_get_interface_descriptor(&sc->sc_udev->ifaces[i]);
482 if (id != NULL((void *)0) && id->bInterfaceNumber == data_ifaceno) {
483 sc->sc_data_iface = &sc->sc_udev->ifaces[i];
484 usbd_claim_iface(sc->sc_udev, i);
485 }
486 }
487 if (sc->sc_data_iface == NULL((void *)0)) {
488 printf("%s: no data interface found\n", DEVNAM(sc)(((struct umb_softc *)(sc))->sc_dev.dv_xname));
489 goto fail;
490 }
491
492 /*
493 * If this is a combined NCM/MBIM function, switch to
494 * alternate setting one to enable MBIM.
495 */
496 id = usbd_get_interface_descriptor(uaa->iface);
497 if (id->bInterfaceClass == UICLASS_CDC0x02 &&
498 id->bInterfaceSubClass ==
499 UISUBCLASS_NETWORK_CONTROL_MODEL13)
500 usbd_set_interface(uaa->iface, 1);
501
502 id = usbd_get_interface_descriptor(uaa->iface);
503 ctrl_ep = -1;
504 for (i = 0; i < id->bNumEndpoints && ctrl_ep == -1; i++) {
505 ed = usbd_interface2endpoint_descriptor(uaa->iface, i);
506 if (ed == NULL((void *)0))
507 break;
508 if (UE_GET_XFERTYPE(ed->bmAttributes)((ed->bmAttributes) & 0x03) == UE_INTERRUPT0x03 &&
509 UE_GET_DIR(ed->bEndpointAddress)((ed->bEndpointAddress) & 0x80) == UE_DIR_IN0x80)
510 ctrl_ep = ed->bEndpointAddress;
511 }
512 if (ctrl_ep == -1) {
513 printf("%s: missing interrupt endpoint\n", DEVNAM(sc)(((struct umb_softc *)(sc))->sc_dev.dv_xname));
514 goto fail;
515 }
516
517 /*
518 * For the MBIM Data Interface, select the appropriate
519 * alternate setting by looking for a matching descriptor that
520 * has two endpoints.
521 */
522 cd = usbd_get_config_descriptor(sc->sc_udev);
523 altnum = usbd_get_no_alts(cd, data_ifaceno);
524 for (i = 0; i < altnum; i++) {
525 id = usbd_find_idesc(cd, sc->sc_data_iface->index, i);
526 if (id == NULL((void *)0))
527 continue;
528 if (id->bInterfaceClass == UICLASS_CDC_DATA0x0a &&
529 id->bInterfaceSubClass == UISUBCLASS_DATA0 &&
530 id->bInterfaceProtocol == UIPROTO_DATA_MBIM0x02 &&
531 id->bNumEndpoints == 2)
532 break;
533 }
534 if (i == altnum || id == NULL((void *)0)) {
535 printf("%s: missing alt setting for interface #%d\n",
536 DEVNAM(sc)(((struct umb_softc *)(sc))->sc_dev.dv_xname), data_ifaceno);
537 goto fail;
538 }
539 status = usbd_set_interface(sc->sc_data_iface, i);
540 if (status) {
541 printf("%s: select alt setting %d for interface #%d "
542 "failed: %s\n", DEVNAM(sc)(((struct umb_softc *)(sc))->sc_dev.dv_xname), i, data_ifaceno,
543 usbd_errstr(status));
544 goto fail;
545 }
546
547 id = usbd_get_interface_descriptor(sc->sc_data_iface);
548 sc->sc_rx_ep = sc->sc_tx_ep = -1;
549 for (i = 0; i < id->bNumEndpoints; i++) {
550 if ((ed = usbd_interface2endpoint_descriptor(sc->sc_data_iface,
551 i)) == NULL((void *)0))
552 break;
553 if (UE_GET_XFERTYPE(ed->bmAttributes)((ed->bmAttributes) & 0x03) == UE_BULK0x02 &&
554 UE_GET_DIR(ed->bEndpointAddress)((ed->bEndpointAddress) & 0x80) == UE_DIR_IN0x80)
555 sc->sc_rx_ep = ed->bEndpointAddress;
556 else if (UE_GET_XFERTYPE(ed->bmAttributes)((ed->bmAttributes) & 0x03) == UE_BULK0x02 &&
557 UE_GET_DIR(ed->bEndpointAddress)((ed->bEndpointAddress) & 0x80) == UE_DIR_OUT0x00)
558 sc->sc_tx_ep = ed->bEndpointAddress;
559 }
560 if (sc->sc_rx_ep == -1 || sc->sc_tx_ep == -1) {
561 printf("%s: missing bulk endpoints\n", DEVNAM(sc)(((struct umb_softc *)(sc))->sc_dev.dv_xname));
562 goto fail;
563 }
564
565 DPRINTFN(2, "%s: ctrl-ifno#%d: ep-ctrl=%d, data-ifno#%d: ep-rx=%d, "do { } while (0)
566 "ep-tx=%d\n", DEVNAM(sc), sc->sc_ctrl_ifaceno,do { } while (0)
567 UE_GET_ADDR(ctrl_ep), data_ifaceno,do { } while (0)
568 UE_GET_ADDR(sc->sc_rx_ep), UE_GET_ADDR(sc->sc_tx_ep))do { } while (0);
569
570 usb_init_task(&sc->sc_umb_task, umb_state_task, sc,((&sc->sc_umb_task)->fun = (umb_state_task), (&
sc->sc_umb_task)->arg = (sc), (&sc->sc_umb_task)
->type = (0), (&sc->sc_umb_task)->state = 0x0)
571 USB_TASK_TYPE_GENERIC)((&sc->sc_umb_task)->fun = (umb_state_task), (&
sc->sc_umb_task)->arg = (sc), (&sc->sc_umb_task)
->type = (0), (&sc->sc_umb_task)->state = 0x0)
;
572 usb_init_task(&sc->sc_get_response_task, umb_get_response_task, sc,((&sc->sc_get_response_task)->fun = (umb_get_response_task
), (&sc->sc_get_response_task)->arg = (sc), (&sc
->sc_get_response_task)->type = (0), (&sc->sc_get_response_task
)->state = 0x0)
573 USB_TASK_TYPE_GENERIC)((&sc->sc_get_response_task)->fun = (umb_get_response_task
), (&sc->sc_get_response_task)->arg = (sc), (&sc
->sc_get_response_task)->type = (0), (&sc->sc_get_response_task
)->state = 0x0)
;
574 timeout_set(&sc->sc_statechg_timer, umb_statechg_timeout, sc);
575
576 if (usbd_open_pipe_intr(uaa->iface, ctrl_ep, USBD_SHORT_XFER_OK0x04,
577 &sc->sc_ctrl_pipe, sc, &sc->sc_intr_msg, sizeof (sc->sc_intr_msg),
578 umb_intr, USBD_DEFAULT_INTERVAL(-1))) {
579 printf("%s: failed to open control pipe\n", DEVNAM(sc)(((struct umb_softc *)(sc))->sc_dev.dv_xname));
580 goto fail;
581 }
582 sc->sc_resp_buf = malloc(sc->sc_ctrl_len, M_USBDEV102, M_NOWAIT0x0002);
583 if (sc->sc_resp_buf == NULL((void *)0)) {
584 printf("%s: allocation of resp buffer failed\n", DEVNAM(sc)(((struct umb_softc *)(sc))->sc_dev.dv_xname));
585 goto fail;
586 }
587 sc->sc_ctrl_msg = malloc(sc->sc_ctrl_len, M_USBDEV102, M_NOWAIT0x0002);
588 if (sc->sc_ctrl_msg == NULL((void *)0)) {
589 printf("%s: allocation of ctrl msg buffer failed\n",
590 DEVNAM(sc)(((struct umb_softc *)(sc))->sc_dev.dv_xname));
591 goto fail;
592 }
593
594 sc->sc_info.regstate = MBIM_REGSTATE_UNKNOWN0;
595 sc->sc_info.pin_attempts_left = UMB_VALUE_UNKNOWN-999;
596 sc->sc_info.rssi = UMB_VALUE_UNKNOWN-999;
597 sc->sc_info.ber = UMB_VALUE_UNKNOWN-999;
598
599 /* Default to 16 bit NTB format. */
600 sc->sc_ncm_format = NCM_FORMAT_NTB160x00;
601 umb_ncm_setup(sc);
602 umb_ncm_setup_format(sc);
603 if (sc->sc_ncm_supported_formats == 0)
604 goto fail;
605 DPRINTFN(2, "%s: rx/tx size %d/%d\n", DEVNAM(sc),do { } while (0)
606 sc->sc_rx_bufsz, sc->sc_tx_bufsz)do { } while (0);
607
608 s = splnet()splraise(0x4);
609 ifp = GET_IFP(sc)(&(sc)->sc_if);
610 ifp->if_flags = IFF_SIMPLEX0x800 | IFF_MULTICAST0x8000 | IFF_POINTOPOINT0x10;
611 ifp->if_ioctl = umb_ioctl;
612 ifp->if_start = umb_start;
613 ifp->if_rtrequest = umb_rtrequest;
614
615 ifp->if_watchdog = umb_watchdog;
616 strlcpy(ifp->if_xname, DEVNAM(sc)(((struct umb_softc *)(sc))->sc_dev.dv_xname), IFNAMSIZ16);
617 ifp->if_link_stateif_data.ifi_link_state = LINK_STATE_DOWN2;
618
619 ifp->if_typeif_data.ifi_type = IFT_MBIM0xfa;
620 ifp->if_priority = IF_WWAN_DEFAULT_PRIORITY6;
621 ifp->if_addrlenif_data.ifi_addrlen = 0;
622 ifp->if_hdrlenif_data.ifi_hdrlen = sizeof (struct ncm_header16) +
623 sizeof (struct ncm_pointer16);
624 ifp->if_mtuif_data.ifi_mtu = 1500; /* use a common default */
625 ifp->if_hardmtu = sc->sc_maxpktlen;
626 ifp->if_bpf_mtap = p2p_bpf_mtap;
627 ifp->if_input = p2p_input;
628 ifp->if_output = umb_output;
629 if_attach(ifp);
630 if_alloc_sadl(ifp);
631 ifp->if_softc = sc;
632#if NBPFILTER1 > 0
633 bpfattach(&ifp->if_bpf, ifp, DLT_LOOP12, sizeof(uint32_t));
634#endif
635
636#if NKSTAT1 > 0
637 umb_kstat_attach(sc);
638#endif
639
640 /*
641 * Open the device now so that we are able to query device information.
642 * XXX maybe close when done?
643 */
644 umb_open(sc);
645 splx(s)spllower(s);
646
647 DPRINTF("%s: vers %d.%d\n", DEVNAM(sc), sc->sc_ver_maj, sc->sc_ver_min)do { } while (0);
648 return;
649
650fail:
651 usbd_deactivate(sc->sc_udev);
652 return;
653}
654
655int
656umb_detach(struct device *self, int flags)
657{
658 struct umb_softc *sc = (struct umb_softc *)self;
659 struct ifnet *ifp = GET_IFP(sc)(&(sc)->sc_if);
660 int s;
661
662 s = splnet()splraise(0x4);
663 if (ifp->if_flags & IFF_RUNNING0x40)
664 umb_down(sc, 1);
665 umb_close(sc);
666
667#if NKSTAT1 > 0
668 umb_kstat_detach(sc);
669#endif
670
671 usb_rem_wait_task(sc->sc_udev, &sc->sc_get_response_task);
672 if (timeout_initialized(&sc->sc_statechg_timer)((&sc->sc_statechg_timer)->to_flags & 0x04))
673 timeout_del(&sc->sc_statechg_timer);
674 sc->sc_nresp = 0;
675 usb_rem_wait_task(sc->sc_udev, &sc->sc_umb_task);
676 if (sc->sc_ctrl_pipe) {
677 usbd_close_pipe(sc->sc_ctrl_pipe);
678 sc->sc_ctrl_pipe = NULL((void *)0);
679 }
680 if (sc->sc_ctrl_msg) {
681 free(sc->sc_ctrl_msg, M_USBDEV102, sc->sc_ctrl_len);
682 sc->sc_ctrl_msg = NULL((void *)0);
683 }
684 if (sc->sc_resp_buf) {
685 free(sc->sc_resp_buf, M_USBDEV102, sc->sc_ctrl_len);
686 sc->sc_resp_buf = NULL((void *)0);
687 }
688 if (ifp->if_softc != NULL((void *)0)) {
689 if_detach(ifp);
690 }
691
692 splx(s)spllower(s);
693 return 0;
694}
695
696void
697umb_ncm_setup(struct umb_softc *sc)
698{
699 usb_device_request_t req;
700 struct ncm_ntb_parameters np;
701
702 /* Query NTB transfer sizes */
703 req.bmRequestType = UT_READ_CLASS_INTERFACE(0x80 | 0x20 | 0x01);
704 req.bRequest = NCM_GET_NTB_PARAMETERS0x80;
705 USETW(req.wValue, 0)(*(u_int16_t *)(req.wValue) = (0));
706 USETW(req.wIndex, sc->sc_ctrl_ifaceno)(*(u_int16_t *)(req.wIndex) = (sc->sc_ctrl_ifaceno));
707 USETW(req.wLength, sizeof (np))(*(u_int16_t *)(req.wLength) = (sizeof (np)));
708 if (usbd_do_request(sc->sc_udev, &req, &np) == USBD_NORMAL_COMPLETION &&
709 UGETW(np.wLength)(*(u_int16_t *)(np.wLength)) == sizeof (np)) {
710 sc->sc_rx_bufsz = UGETDW(np.dwNtbInMaxSize)(*(u_int32_t *)(np.dwNtbInMaxSize));
711 sc->sc_tx_bufsz = UGETDW(np.dwNtbOutMaxSize)(*(u_int32_t *)(np.dwNtbOutMaxSize));
712 sc->sc_maxdgram = UGETW(np.wNtbOutMaxDatagrams)(*(u_int16_t *)(np.wNtbOutMaxDatagrams));
713 sc->sc_align = UGETW(np.wNdpOutAlignment)(*(u_int16_t *)(np.wNdpOutAlignment));
714 sc->sc_ndp_div = UGETW(np.wNdpOutDivisor)(*(u_int16_t *)(np.wNdpOutDivisor));
715 sc->sc_ndp_remainder = UGETW(np.wNdpOutPayloadRemainder)(*(u_int16_t *)(np.wNdpOutPayloadRemainder));
716 /* Validate values */
717 if (!powerof2(sc->sc_align)((((sc->sc_align)-1)&(sc->sc_align))==0) || sc->sc_align == 0 ||
718 sc->sc_align >= sc->sc_tx_bufsz)
719 sc->sc_align = sizeof (uint32_t);
720 if (!powerof2(sc->sc_ndp_div)((((sc->sc_ndp_div)-1)&(sc->sc_ndp_div))==0) || sc->sc_ndp_div == 0 ||
721 sc->sc_ndp_div >= sc->sc_tx_bufsz)
722 sc->sc_ndp_div = sizeof (uint32_t);
723 if (sc->sc_ndp_remainder >= sc->sc_ndp_div)
724 sc->sc_ndp_remainder = 0;
725 DPRINTF("%s: NCM align=%d div=%d rem=%d\n", DEVNAM(sc),do { } while (0)
726 sc->sc_align, sc->sc_ndp_div, sc->sc_ndp_remainder)do { } while (0);
727 sc->sc_ncm_supported_formats = UGETW(np.bmNtbFormatsSupported)(*(u_int16_t *)(np.bmNtbFormatsSupported));
728 } else {
729 sc->sc_rx_bufsz = sc->sc_tx_bufsz = 8 * 1024;
730 sc->sc_maxdgram = 0;
731 sc->sc_align = sc->sc_ndp_div = sizeof (uint32_t);
732 sc->sc_ndp_remainder = 0;
733 DPRINTF("%s: align=default div=default rem=default\n",do { } while (0)
734 DEVNAM(sc))do { } while (0);
735 sc->sc_ncm_supported_formats = NCM_FORMAT_NTB16_MASK(1U << 0x00);
736 }
737}
738
739void
740umb_ncm_setup_format(struct umb_softc *sc)
741{
742 usb_device_request_t req;
743 uWord wFmt;
744 uint16_t fmt;
745
746 assertwaitok();
747 if (sc->sc_ncm_supported_formats == 0)
748 goto fail;
749
750 /* NCM_GET_NTB_FORMAT is not allowed for 16-bit only devices. */
751 if (sc->sc_ncm_supported_formats == NCM_FORMAT_NTB16_MASK(1U << 0x00)) {
752 DPRINTF("%s: Only NTB16 format supported.\n", DEVNAM(sc))do { } while (0);
753 sc->sc_ncm_format = NCM_FORMAT_NTB160x00;
754 return;
755 }
756
757 /* Query NTB FORMAT (16 vs. 32 bit) */
758 req.bmRequestType = UT_READ_CLASS_INTERFACE(0x80 | 0x20 | 0x01);
759 req.bRequest = NCM_GET_NTB_FORMAT0x83;
760 USETW(req.wValue, 0)(*(u_int16_t *)(req.wValue) = (0));
761 USETW(req.wIndex, sc->sc_ctrl_ifaceno)(*(u_int16_t *)(req.wIndex) = (sc->sc_ctrl_ifaceno));
762 USETW(req.wLength, sizeof (wFmt))(*(u_int16_t *)(req.wLength) = (sizeof (wFmt)));
763 if (usbd_do_request(sc->sc_udev, &req, wFmt) != USBD_NORMAL_COMPLETION)
764 goto fail;
765 fmt = UGETW(wFmt)(*(u_int16_t *)(wFmt));
766 if ((sc->sc_ncm_supported_formats & (1UL << fmt)) == 0)
767 goto fail;
768 if (fmt != NCM_FORMAT_NTB160x00 && fmt != NCM_FORMAT_NTB320x01)
769 goto fail;
770 sc->sc_ncm_format = fmt;
771
772 DPRINTF("%s: Using NCM format %d, supported=0x%x\n",do { } while (0)
773 DEVNAM(sc), sc->sc_ncm_format, sc->sc_ncm_supported_formats)do { } while (0);
774 return;
775
776fail:
777 DPRINTF("%s: Cannot setup NCM format\n", DEVNAM(sc))do { } while (0);
778 sc->sc_ncm_supported_formats = 0;
779}
780
781int
782umb_alloc_xfers(struct umb_softc *sc)
783{
784 if (!sc->sc_rx_xfer) {
785 if ((sc->sc_rx_xfer = usbd_alloc_xfer(sc->sc_udev)) != NULL((void *)0))
786 sc->sc_rx_buf = usbd_alloc_buffer(sc->sc_rx_xfer,
787 sc->sc_rx_bufsz);
788 }
789 if (!sc->sc_tx_xfer) {
790 if ((sc->sc_tx_xfer = usbd_alloc_xfer(sc->sc_udev)) != NULL((void *)0))
791 sc->sc_tx_buf = usbd_alloc_buffer(sc->sc_tx_xfer,
792 sc->sc_tx_bufsz);
793 }
794 return (sc->sc_rx_buf && sc->sc_tx_buf) ? 1 : 0;
795}
796
797void
798umb_free_xfers(struct umb_softc *sc)
799{
800 if (sc->sc_rx_xfer) {
801 /* implicit usbd_free_buffer() */
802 usbd_free_xfer(sc->sc_rx_xfer);
803 sc->sc_rx_xfer = NULL((void *)0);
804 sc->sc_rx_buf = NULL((void *)0);
805 }
806 if (sc->sc_tx_xfer) {
807 usbd_free_xfer(sc->sc_tx_xfer);
808 sc->sc_tx_xfer = NULL((void *)0);
809 sc->sc_tx_buf = NULL((void *)0);
810 }
811 ml_purge(&sc->sc_tx_ml);
812}
813
814int
815umb_alloc_bulkpipes(struct umb_softc *sc)
816{
817 struct ifnet *ifp = GET_IFP(sc)(&(sc)->sc_if);
818
819 if (!(ifp->if_flags & IFF_RUNNING0x40)) {
820 if (usbd_open_pipe(sc->sc_data_iface, sc->sc_rx_ep,
821 USBD_EXCLUSIVE_USE0x01, &sc->sc_rx_pipe))
822 return 0;
823 if (usbd_open_pipe(sc->sc_data_iface, sc->sc_tx_ep,
824 USBD_EXCLUSIVE_USE0x01, &sc->sc_tx_pipe))
825 return 0;
826
827 ifp->if_flags |= IFF_RUNNING0x40;
828 ifq_clr_oactive(&ifp->if_snd);
829 umb_rx(sc);
830 }
831 return 1;
832}
833
834void
835umb_close_bulkpipes(struct umb_softc *sc)
836{
837 struct ifnet *ifp = GET_IFP(sc)(&(sc)->sc_if);
838
839 ifp->if_flags &= ~IFF_RUNNING0x40;
840 ifq_clr_oactive(&ifp->if_snd);
841 ifp->if_timer = 0;
842 if (sc->sc_rx_pipe) {
843 usbd_close_pipe(sc->sc_rx_pipe);
844 sc->sc_rx_pipe = NULL((void *)0);
845 }
846 if (sc->sc_tx_pipe) {
847 usbd_close_pipe(sc->sc_tx_pipe);
848 sc->sc_tx_pipe = NULL((void *)0);
849 }
850}
851
852int
853umb_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
854{
855 struct proc *p = curproc({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r"
(__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self)));
__ci;})->ci_curproc
;
856 struct umb_softc *sc = ifp->if_softc;
857 struct ifreq *ifr = (struct ifreq *)data;
858 int s, error = 0;
859 struct umb_parameter mp;
860
861 if (usbd_is_dying(sc->sc_udev))
862 return ENXIO6;
863
864 s = splnet()splraise(0x4);
865 switch (cmd) {
866 case SIOCSIFFLAGS((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff
) << 16) | ((('i')) << 8) | ((16)))
:
867 usb_add_task(sc->sc_udev, &sc->sc_umb_task);
868 break;
869 case SIOCGUMBINFO(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct ifreq) & 0x1fff) << 16) | ((('i')) <<
8) | ((190)))
:
870 error = copyout(&sc->sc_info, ifr->ifr_dataifr_ifru.ifru_data,
871 sizeof (sc->sc_info));
872 break;
873 case SIOCSUMBPARAM((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff
) << 16) | ((('i')) << 8) | ((191)))
:
874 if ((error = suser(p)) != 0)
875 break;
876 if ((error = copyin(ifr->ifr_dataifr_ifru.ifru_data, &mp, sizeof (mp))) != 0)
877 break;
878
879 if ((error = umb_setpin(sc, mp.op, mp.is_puk, mp.pin, mp.pinlen,
880 mp.newpin, mp.newpinlen)) != 0)
881 break;
882
883 if (mp.apnlen < 0 || mp.apnlen > sizeof (sc->sc_info.apn)) {
884 error = EINVAL22;
885 break;
886 }
887 sc->sc_roamingsc_info.enable_roaming = mp.roaming ? 1 : 0;
888 memset(sc->sc_info.apn, 0, sizeof (sc->sc_info.apn))__builtin_memset((sc->sc_info.apn), (0), (sizeof (sc->sc_info
.apn)))
;
889 memcpy(sc->sc_info.apn, mp.apn, mp.apnlen)__builtin_memcpy((sc->sc_info.apn), (mp.apn), (mp.apnlen));
890 sc->sc_info.apnlen = mp.apnlen;
891 sc->sc_info.preferredclasses = mp.preferredclasses;
892 umb_setdataclass(sc);
893 break;
894 case SIOCGUMBPARAM(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct ifreq) & 0x1fff) << 16) | ((('i')) <<
8) | ((192)))
:
895 memset(&mp, 0, sizeof (mp))__builtin_memset((&mp), (0), (sizeof (mp)));
896 memcpy(mp.apn, sc->sc_info.apn, sc->sc_info.apnlen)__builtin_memcpy((mp.apn), (sc->sc_info.apn), (sc->sc_info
.apnlen))
;
897 mp.apnlen = sc->sc_info.apnlen;
898 mp.roaming = sc->sc_roamingsc_info.enable_roaming;
899 mp.preferredclasses = sc->sc_info.preferredclasses;
900 error = copyout(&mp, ifr->ifr_dataifr_ifru.ifru_data, sizeof (mp));
901 break;
902 case SIOCSIFMTU((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff
) << 16) | ((('i')) << 8) | ((127)))
:
903 /* Does this include the NCM headers and tail? */
904 if (ifr->ifr_mtuifr_ifru.ifru_metric > ifp->if_hardmtu) {
905 error = EINVAL22;
906 break;
907 }
908 ifp->if_mtuif_data.ifi_mtu = ifr->ifr_mtuifr_ifru.ifru_metric;
909 break;
910 case SIOCSIFADDR((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff
) << 16) | ((('i')) << 8) | ((12)))
:
911 case SIOCAIFADDR((unsigned long)0x80000000 | ((sizeof(struct ifaliasreq) &
0x1fff) << 16) | ((('i')) << 8) | ((26)))
:
912 case SIOCSIFDSTADDR((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff
) << 16) | ((('i')) << 8) | ((14)))
:
913 case SIOCADDMULTI((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff
) << 16) | ((('i')) << 8) | ((49)))
:
914 case SIOCDELMULTI((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff
) << 16) | ((('i')) << 8) | ((50)))
:
915 break;
916 default:
917 error = ENOTTY25;
918 break;
919 }
920 splx(s)spllower(s);
921 return error;
922}
923
924int
925umb_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
926 struct rtentry *rtp)
927{
928 if ((ifp->if_flags & (IFF_UP0x1|IFF_RUNNING0x40)) != (IFF_UP0x1|IFF_RUNNING0x40)) {
929 m_freem(m);
930 return ENETDOWN50;
931 }
932 m->m_pkthdrM_dat.MH.MH_pkthdr.ph_family = dst->sa_family;
933 return if_enqueue(ifp, m);
934}
935
936static inline int
937umb_align(size_t bufsz, int offs, int alignment, int remainder)
938{
939 size_t m = alignment - 1;
940 int align;
941
942 align = (((size_t)offs + m) & ~m) - alignment + remainder;
943 if (align < offs)
944 align += alignment;
945 if (align > bufsz)
946 align = bufsz;
947 return align - offs;
948}
949
950static inline int
951umb_padding(void *buf, size_t bufsz, int offs, int alignment, int remainder)
952{
953 int nb;
954
955 nb = umb_align(bufsz, offs, alignment, remainder);
956 if (nb > 0)
957 memset(buf + offs, 0, nb)__builtin_memset((buf + offs), (0), (nb));
958 return nb;
959}
960
961void
962umb_start(struct ifnet *ifp)
963{
964 struct umb_softc *sc = ifp->if_softc;
965 struct mbuf *m = NULL((void *)0);
966 int ndgram = 0;
967 int offs, len, mlen;
968 int maxoverhead;
969
970 if (usbd_is_dying(sc->sc_udev) ||
6
Assuming the condition is false
971 !(ifp->if_flags & IFF_RUNNING0x40) ||
7
Assuming the condition is false
972 ifq_is_oactive(&ifp->if_snd))
973 return;
974
975 KASSERT(ml_empty(&sc->sc_tx_ml))((((&sc->sc_tx_ml)->ml_len == 0)) ? (void)0 : __assert
("diagnostic ", "/usr/src/sys/dev/usb/if_umb.c", 975, "ml_empty(&sc->sc_tx_ml)"
))
;
8
Taking false branch
9
Assuming field 'ml_len' is equal to 0
10
'?' condition is true
976
977 switch (sc->sc_ncm_format) {
11
Control jumps to 'case 1:' at line 984
978 case NCM_FORMAT_NTB160x00:
979 offs = sizeof (struct ncm_header16);
980 offs += umb_align(sc->sc_tx_bufsz, offs, sc->sc_align, 0);
981 offs += sizeof (struct ncm_pointer16);
982 maxoverhead = sizeof (struct ncm_pointer16_dgram);
983 break;
984 case NCM_FORMAT_NTB320x01:
985 offs = sizeof (struct ncm_header32);
986 offs += umb_align(sc->sc_tx_bufsz, offs, sc->sc_align, 0);
987 offs += sizeof (struct ncm_pointer32);
988 maxoverhead = sizeof (struct ncm_pointer32_dgram);
989 break;
12
Execution continues on line 997
990 }
991
992 /*
993 * Overhead for per packet alignment plus packet pointer. Note
994 * that 'struct ncm_pointer{16,32}' already includes space for
995 * the terminating zero pointer.
996 */
997 maxoverhead += sc->sc_ndp_div - 1;
998
999 len = 0;
1000 while (1) {
13
Loop condition is true. Entering loop body
21
Loop condition is true. Entering loop body
1001 m = ifq_deq_begin(&ifp->if_snd);
1002 if (m == NULL((void *)0))
14
Assuming 'm' is not equal to NULL
15
Taking false branch
22
Assuming 'm' is equal to NULL
23
Taking true branch
1003 break;
24
Execution continues on line 1027
1004
1005 /*
1006 * Check if mbuf plus required NCM pointer still fits into
1007 * xfer buffers. Assume maximal padding.
1008 */
1009 mlen = maxoverhead + m->m_pkthdrM_dat.MH.MH_pkthdr.len;
1010 if ((sc->sc_maxdgram != 0 && ndgram >= sc->sc_maxdgram) ||
16
Assuming field 'sc_maxdgram' is equal to 0
18
Taking false branch
1011 (offs + len + mlen > sc->sc_tx_bufsz)) {
17
Assuming the condition is false
1012 ifq_deq_rollback(&ifp->if_snd, m);
1013 break;
1014 }
1015 ifq_deq_commit(&ifp->if_snd, m);
1016
1017 ndgram++;
1018 len += mlen;
1019 ml_enqueue(&sc->sc_tx_ml, m);
1020
1021#if NBPFILTER1 > 0
1022 if (ifp->if_bpf)
19
Assuming field 'if_bpf' is null
20
Taking false branch
1023 bpf_mtap_af(ifp->if_bpf, m->m_pkthdrM_dat.MH.MH_pkthdr.ph_family, m,
1024 BPF_DIRECTION_OUT(1 << 1));
1025#endif
1026 }
1027 if (ml_empty(&sc->sc_tx_ml)((&sc->sc_tx_ml)->ml_len == 0))
25
Assuming field 'ml_len' is not equal to 0
26
Taking false branch
1028 return;
1029 if (umb_encap(sc, ndgram)) {
27
Calling 'umb_encap'
1030 ifq_set_oactive(&ifp->if_snd);
1031 ifp->if_timer = (2 * umb_xfer_tout) / 1000;
1032 }
1033}
1034
1035void
1036umb_rtrequest(struct ifnet *ifp, int req, struct rtentry *rt)
1037{
1038 struct umb_softc *sc = ifp->if_softc;
1039
1040 if (req == RTM_PROPOSAL0x13) {
1041 KERNEL_LOCK()_kernel_lock();
1042 umb_send_inet_proposal(sc, AF_INET2);
1043#ifdef INET61
1044 umb_send_inet_proposal(sc, AF_INET624);
1045#endif
1046 KERNEL_UNLOCK()_kernel_unlock();
1047 return;
1048 }
1049
1050 p2p_rtrequest(ifp, req, rt);
1051}
1052
1053
1054void
1055umb_watchdog(struct ifnet *ifp)
1056{
1057 struct umb_softc *sc = ifp->if_softc;
1058
1059 if (usbd_is_dying(sc->sc_udev))
1060 return;
1061
1062 ifp->if_oerrorsif_data.ifi_oerrors++;
1063 printf("%s: watchdog timeout\n", DEVNAM(sc)(((struct umb_softc *)(sc))->sc_dev.dv_xname));
1064 usbd_abort_pipe(sc->sc_tx_pipe);
1065 return;
1066}
1067
1068void
1069umb_statechg_timeout(void *arg)
1070{
1071 struct umb_softc *sc = arg;
1072 struct ifnet *ifp = GET_IFP(sc)(&(sc)->sc_if);
1073
1074 if (sc->sc_info.regstate != MBIM_REGSTATE_ROAMING4 || sc->sc_roamingsc_info.enable_roaming)
1075 if (ifp->if_flags & IFF_DEBUG0x4)
1076 log(LOG_DEBUG7, "%s: state change timeout\n",
1077 DEVNAM(sc)(((struct umb_softc *)(sc))->sc_dev.dv_xname));
1078 usb_add_task(sc->sc_udev, &sc->sc_umb_task);
1079}
1080
1081void
1082umb_newstate(struct umb_softc *sc, enum umb_state newstate, int flags)
1083{
1084 struct ifnet *ifp = GET_IFP(sc)(&(sc)->sc_if);
1085
1086 if (newstate == sc->sc_statesc_info.state)
1087 return;
1088 if (((flags & UMB_NS_DONT_DROP0x0001) && newstate < sc->sc_statesc_info.state) ||
1089 ((flags & UMB_NS_DONT_RAISE0x0002) && newstate > sc->sc_statesc_info.state))
1090 return;
1091 if (ifp->if_flags & IFF_DEBUG0x4)
1092 log(LOG_DEBUG7, "%s: state going %s from '%s' to '%s'\n",
1093 DEVNAM(sc)(((struct umb_softc *)(sc))->sc_dev.dv_xname), newstate > sc->sc_statesc_info.state ? "up" : "down",
1094 umb_istate(sc->sc_state)umb_val2descr(umb_istate, (sc->sc_info.state)), umb_istate(newstate)umb_val2descr(umb_istate, (newstate)));
1095 sc->sc_statesc_info.state = newstate;
1096 usb_add_task(sc->sc_udev, &sc->sc_umb_task);
1097}
1098
1099void
1100umb_state_task(void *arg)
1101{
1102 struct umb_softc *sc = arg;
1103 struct ifnet *ifp = GET_IFP(sc)(&(sc)->sc_if);
1104 int s;
1105 int state;
1106
1107 if (sc->sc_info.regstate == MBIM_REGSTATE_ROAMING4 && !sc->sc_roamingsc_info.enable_roaming) {
1108 /*
1109 * Query the registration state until we're with the home
1110 * network again.
1111 */
1112 umb_cmd(sc, MBIM_CID_REGISTER_STATE9, MBIM_CMDOP_QRY0, NULL((void *)0), 0);
1113 return;
1114 }
1115
1116 s = splnet()splraise(0x4);
1117 if (ifp->if_flags & IFF_UP0x1)
1118 umb_up(sc);
1119 else
1120 umb_down(sc, 0);
1121
1122 state = sc->sc_statesc_info.state == UMB_S_UP ? LINK_STATE_UP4 : LINK_STATE_DOWN2;
1123 if (ifp->if_link_stateif_data.ifi_link_state != state) {
1124 if (ifp->if_flags & IFF_DEBUG0x4)
1125 log(LOG_DEBUG7, "%s: link state changed from %s to %s\n",
1126 DEVNAM(sc)(((struct umb_softc *)(sc))->sc_dev.dv_xname),
1127 LINK_STATE_IS_UP(ifp->if_link_state)((ifp->if_data.ifi_link_state) >= 4 || (ifp->if_data
.ifi_link_state) == 0)
1128 ? "up" : "down",
1129 LINK_STATE_IS_UP(state)((state) >= 4 || (state) == 0) ? "up" : "down");
1130 ifp->if_link_stateif_data.ifi_link_state = state;
1131 if_link_state_change(ifp);
1132 }
1133 splx(s)spllower(s);
1134}
1135
1136void
1137umb_up(struct umb_softc *sc)
1138{
1139 splassert(IPL_NET)do { if (splassert_ctl > 0) { splassert_check(0x4, __func__
); } } while (0)
;
1140
1141 switch (sc->sc_statesc_info.state) {
1142 case UMB_S_DOWN:
1143 DPRINTF("%s: init: opening ...\n", DEVNAM(sc))do { } while (0);
1144 umb_open(sc);
1145 break;
1146 case UMB_S_OPEN:
1147 if (sc->sc_flags & UMBFLG_FCC_AUTH_REQUIRED0x0001) {
1148 if (sc->sc_cid == -1) {
1149 DPRINTF("%s: init: allocating CID ...\n",do { } while (0)
1150 DEVNAM(sc))do { } while (0);
1151 umb_allocate_cid(sc);
1152 break;
1153 } else
1154 umb_newstate(sc, UMB_S_CID, UMB_NS_DONT_DROP0x0001);
1155 } else {
1156 DPRINTF("%s: init: turning radio on ...\n", DEVNAM(sc))do { } while (0);
1157 umb_radio(sc, 1);
1158 break;
1159 }
1160 /*FALLTHROUGH*/
1161 case UMB_S_CID:
1162 DPRINTF("%s: init: sending FCC auth ...\n", DEVNAM(sc))do { } while (0);
1163 umb_send_fcc_auth(sc);
1164 break;
1165 case UMB_S_RADIO:
1166 DPRINTF("%s: init: checking SIM state ...\n", DEVNAM(sc))do { } while (0);
1167 umb_cmd(sc, MBIM_CID_SUBSCRIBER_READY_STATUS2, MBIM_CMDOP_QRY0,
1168 NULL((void *)0), 0);
1169 break;
1170 case UMB_S_SIMREADY:
1171 DPRINTF("%s: init: attaching ...\n", DEVNAM(sc))do { } while (0);
1172 umb_packet_service(sc, 1);
1173 break;
1174 case UMB_S_ATTACHED:
1175 sc->sc_tx_seq = 0;
1176 if (!umb_alloc_xfers(sc)) {
1177 umb_free_xfers(sc);
1178 printf("%s: allocation of xfers failed\n", DEVNAM(sc)(((struct umb_softc *)(sc))->sc_dev.dv_xname));
1179 break;
1180 }
1181 DPRINTF("%s: init: connecting ...\n", DEVNAM(sc))do { } while (0);
1182 umb_connect(sc);
1183 break;
1184 case UMB_S_CONNECTED:
1185 DPRINTF("%s: init: getting IP config ...\n", DEVNAM(sc))do { } while (0);
1186 umb_qry_ipconfig(sc);
1187 break;
1188 case UMB_S_UP:
1189 DPRINTF("%s: init: reached state UP\n", DEVNAM(sc))do { } while (0);
1190 if (!umb_alloc_bulkpipes(sc)) {
1191 printf("%s: opening bulk pipes failed\n", DEVNAM(sc)(((struct umb_softc *)(sc))->sc_dev.dv_xname));
1192 umb_down(sc, 1);
1193 }
1194 break;
1195 }
1196 if (sc->sc_statesc_info.state < UMB_S_UP)
1197 timeout_add_sec(&sc->sc_statechg_timer,
1198 UMB_STATE_CHANGE_TIMEOUT30);
1199 else
1200 timeout_del(&sc->sc_statechg_timer);
1201 return;
1202}
1203
1204void
1205umb_down(struct umb_softc *sc, int force)
1206{
1207 splassert(IPL_NET)do { if (splassert_ctl > 0) { splassert_check(0x4, __func__
); } } while (0)
;
1208
1209 umb_close_bulkpipes(sc);
1210 if (sc->sc_statesc_info.state < UMB_S_CONNECTED)
1211 umb_free_xfers(sc);
1212
1213 switch (sc->sc_statesc_info.state) {
1214 case UMB_S_UP:
1215 umb_clear_addr(sc);
1216 /*FALLTHROUGH*/
1217 case UMB_S_CONNECTED:
1218 DPRINTF("%s: stop: disconnecting ...\n", DEVNAM(sc))do { } while (0);
1219 umb_disconnect(sc);
1220 if (!force)
1221 break;
1222 /*FALLTHROUGH*/
1223 case UMB_S_ATTACHED:
1224 DPRINTF("%s: stop: detaching ...\n", DEVNAM(sc))do { } while (0);
1225 umb_packet_service(sc, 0);
1226 if (!force)
1227 break;
1228 /*FALLTHROUGH*/
1229 case UMB_S_SIMREADY:
1230 case UMB_S_RADIO:
1231 DPRINTF("%s: stop: turning radio off ...\n", DEVNAM(sc))do { } while (0);
1232 umb_radio(sc, 0);
1233 if (!force)
1234 break;
1235 /*FALLTHROUGH*/
1236 case UMB_S_CID:
1237 case UMB_S_OPEN:
1238 case UMB_S_DOWN:
1239 /* Do not close the device */
1240 DPRINTF("%s: stop: reached state DOWN\n", DEVNAM(sc))do { } while (0);
1241 break;
1242 }
1243 if (force)
1244 sc->sc_statesc_info.state = UMB_S_OPEN;
1245
1246 if (sc->sc_statesc_info.state > UMB_S_OPEN)
1247 timeout_add_sec(&sc->sc_statechg_timer,
1248 UMB_STATE_CHANGE_TIMEOUT30);
1249 else
1250 timeout_del(&sc->sc_statechg_timer);
1251}
1252
1253void
1254umb_get_response_task(void *arg)
1255{
1256 struct umb_softc *sc = arg;
1257 int len;
1258 int s;
1259
1260 /*
1261 * Function is required to send on RESPONSE_AVAILABLE notification for
1262 * each encapsulated response that is to be processed by the host.
1263 * But of course, we can receive multiple notifications before the
1264 * response task is run.
1265 */
1266 s = splusb()splraise(0x2);
1267 while (sc->sc_nresp > 0) {
1268 --sc->sc_nresp;
1269 len = sc->sc_ctrl_len;
1270 if (umb_get_encap_response(sc, sc->sc_resp_buf, &len))
1271 umb_decode_response(sc, sc->sc_resp_buf, len);
1272 }
1273 splx(s)spllower(s);
1274}
1275
1276void
1277umb_decode_response(struct umb_softc *sc, void *response, int len)
1278{
1279 struct mbim_msghdr *hdr = response;
1280 struct mbim_fragmented_msg_hdr *fraghdr;
1281 uint32_t type;
1282 uint32_t tid;
1283
1284 DPRINTFN(3, "%s: got response: len %d\n", DEVNAM(sc), len)do { } while (0);
1285 DDUMPN(4, response, len)do { } while (0);
1286
1287 if (len < sizeof (*hdr) || letoh32(hdr->len)((__uint32_t)(hdr->len)) != len) {
1288 /*
1289 * We should probably cancel a transaction, but since the
1290 * message is too short, we cannot decode the transaction
1291 * id (tid) and hence don't know, whom to cancel. Must wait
1292 * for the timeout.
1293 */
1294 DPRINTF("%s: received short response (len %d)\n",do { } while (0)
1295 DEVNAM(sc), len)do { } while (0);
1296 return;
1297 }
1298
1299 /*
1300 * XXX FIXME: if message is fragmented, store it until last frag
1301 * is received and then re-assemble all fragments.
1302 */
1303 type = letoh32(hdr->type)((__uint32_t)(hdr->type));
1304 tid = letoh32(hdr->tid)((__uint32_t)(hdr->tid));
1305 switch (type) {
1306 case MBIM_INDICATE_STATUS_MSG0x80000007U:
1307 case MBIM_COMMAND_DONE0x80000003U:
1308 fraghdr = response;
1309 if (letoh32(fraghdr->frag.nfrag)((__uint32_t)(fraghdr->frag.nfrag)) != 1) {
1310 DPRINTF("%s: discarding fragmented messages\n",do { } while (0)
1311 DEVNAM(sc))do { } while (0);
1312 return;
1313 }
1314 break;
1315 default:
1316 break;
1317 }
1318
1319 DPRINTF("%s: <- rcv %s (tid %u)\n", DEVNAM(sc), umb_request2str(type),do { } while (0)
1320 tid)do { } while (0);
1321 switch (type) {
1322 case MBIM_FUNCTION_ERROR_MSG0x80000004U:
1323 case MBIM_HOST_ERROR_MSG4U:
1324 {
1325 struct mbim_f2h_hosterr *e;
1326 int err;
1327
1328 if (len >= sizeof (*e)) {
1329 e = response;
1330 err = letoh32(e->err)((__uint32_t)(e->err));
1331
1332 DPRINTF("%s: %s message, error %s (tid %u)\n",do { } while (0)
1333 DEVNAM(sc), umb_request2str(type),do { } while (0)
1334 umb_error2str(err), tid)do { } while (0);
1335 if (err == MBIM_ERROR_NOT_OPENED5)
1336 umb_newstate(sc, UMB_S_DOWN, 0);
1337 }
1338 break;
1339 }
1340 case MBIM_INDICATE_STATUS_MSG0x80000007U:
1341 umb_handle_indicate_status_msg(sc, response, len);
1342 break;
1343 case MBIM_OPEN_DONE0x80000001U:
1344 umb_handle_opendone_msg(sc, response, len);
1345 break;
1346 case MBIM_CLOSE_DONE0x80000002U:
1347 umb_handle_closedone_msg(sc, response, len);
1348 break;
1349 case MBIM_COMMAND_DONE0x80000003U:
1350 umb_command_done(sc, response, len);
1351 break;
1352 default:
1353 DPRINTF("%s: discard message %s\n", DEVNAM(sc),do { } while (0)
1354 umb_request2str(type))do { } while (0);
1355 break;
1356 }
1357}
1358
1359void
1360umb_handle_indicate_status_msg(struct umb_softc *sc, void *data, int len)
1361{
1362 struct mbim_f2h_indicate_status *m = data;
1363 uint32_t infolen;
1364 uint32_t cid;
1365
1366 if (len < sizeof (*m)) {
1367 DPRINTF("%s: discard short %s message\n", DEVNAM(sc),do { } while (0)
1368 umb_request2str(letoh32(m->hdr.type)))do { } while (0);
1369 return;
1370 }
1371 if (memcmp(m->devid, umb_uuid_basic_connect, sizeof (m->devid))__builtin_memcmp((m->devid), (umb_uuid_basic_connect), (sizeof
(m->devid)))
) {
1372 DPRINTF("%s: discard %s message for other UUID '%s'\n",do { } while (0)
1373 DEVNAM(sc), umb_request2str(letoh32(m->hdr.type)),do { } while (0)
1374 umb_uuid2str(m->devid))do { } while (0);
1375 return;
1376 }
1377 infolen = letoh32(m->infolen)((__uint32_t)(m->infolen));
1378 if (len < sizeof (*m) + infolen) {
1379 DPRINTF("%s: discard truncated %s message (want %d, got %d)\n",do { } while (0)
1380 DEVNAM(sc), umb_request2str(letoh32(m->hdr.type)),do { } while (0)
1381 (int)sizeof (*m) + infolen, len)do { } while (0);
1382 return;
1383 }
1384
1385 cid = letoh32(m->cid)((__uint32_t)(m->cid));
1386 DPRINTF("%s: indicate %s status\n", DEVNAM(sc), umb_cid2str(cid))do { } while (0);
1387 umb_decode_cid(sc, cid, m->info, infolen);
1388}
1389
1390void
1391umb_handle_opendone_msg(struct umb_softc *sc, void *data, int len)
1392{
1393 struct mbim_f2h_openclosedone *resp = data;
1394 struct ifnet *ifp = GET_IFP(sc)(&(sc)->sc_if);
1395 uint32_t status;
1396
1397 status = letoh32(resp->status)((__uint32_t)(resp->status));
1398 if (status == MBIM_STATUS_SUCCESS0) {
1399 if (sc->sc_maxsessions == 0) {
1400 umb_cmd(sc, MBIM_CID_DEVICE_CAPS1, MBIM_CMDOP_QRY0, NULL((void *)0),
1401 0);
1402 umb_cmd(sc, MBIM_CID_PIN4, MBIM_CMDOP_QRY0, NULL((void *)0), 0);
1403 umb_cmd(sc, MBIM_CID_REGISTER_STATE9, MBIM_CMDOP_QRY0,
1404 NULL((void *)0), 0);
1405 }
1406 umb_newstate(sc, UMB_S_OPEN, UMB_NS_DONT_DROP0x0001);
1407 } else if (ifp->if_flags & IFF_DEBUG0x4)
1408 log(LOG_ERR3, "%s: open error: %s\n", DEVNAM(sc)(((struct umb_softc *)(sc))->sc_dev.dv_xname),
1409 umb_status2str(status)umb_val2descr(umb_status, (status)));
1410 return;
1411}
1412
1413void
1414umb_handle_closedone_msg(struct umb_softc *sc, void *data, int len)
1415{
1416 struct mbim_f2h_openclosedone *resp = data;
1417 uint32_t status;
1418
1419 status = letoh32(resp->status)((__uint32_t)(resp->status));
1420 if (status == MBIM_STATUS_SUCCESS0)
1421 umb_newstate(sc, UMB_S_DOWN, 0);
1422 else
1423 DPRINTF("%s: close error: %s\n", DEVNAM(sc),do { } while (0)
1424 umb_status2str(status))do { } while (0);
1425 return;
1426}
1427
1428static inline void
1429umb_getinfobuf(void *in, int inlen, uint32_t offs, uint32_t sz,
1430 void *out, size_t outlen)
1431{
1432 offs = letoh32(offs)((__uint32_t)(offs));
1433 sz = letoh32(sz)((__uint32_t)(sz));
1434 if (inlen >= offs + sz) {
1435 memset(out, 0, outlen)__builtin_memset((out), (0), (outlen));
1436 memcpy(out, in + offs, MIN(sz, outlen))__builtin_memcpy((out), (in + offs), ((((sz)<(outlen))?(sz
):(outlen))))
;
1437 }
1438}
1439
1440static inline int
1441umb_addstr(void *buf, size_t bufsz, int *offs, void *str, int slen,
1442 uint32_t *offsmember, uint32_t *sizemember)
1443{
1444 if (*offs + slen > bufsz)
1445 return 0;
1446
1447 *sizemember = htole32((uint32_t)slen)((__uint32_t)((uint32_t)slen));
1448 if (slen && str) {
1449 *offsmember = htole32((uint32_t)*offs)((__uint32_t)((uint32_t)*offs));
1450 memcpy(buf + *offs, str, slen)__builtin_memcpy((buf + *offs), (str), (slen));
1451 *offs += slen;
1452 *offs += umb_padding(buf, bufsz, *offs, sizeof (uint32_t), 0);
1453 } else
1454 *offsmember = htole32(0)((__uint32_t)(0));
1455 return 1;
1456}
1457
1458int
1459umb_decode_register_state(struct umb_softc *sc, void *data, int len)
1460{
1461 struct mbim_cid_registration_state_info *rs = data;
1462 struct ifnet *ifp = GET_IFP(sc)(&(sc)->sc_if);
1463
1464 if (len < sizeof (*rs))
1465 return 0;
1466 sc->sc_info.nwerror = letoh32(rs->nwerror)((__uint32_t)(rs->nwerror));
1467 sc->sc_info.regstate = letoh32(rs->regstate)((__uint32_t)(rs->regstate));
1468 sc->sc_info.regmode = letoh32(rs->regmode)((__uint32_t)(rs->regmode));
1469 sc->sc_info.cellclass = letoh32(rs->curcellclass)((__uint32_t)(rs->curcellclass));
1470
1471 umb_getinfobuf(data, len, rs->provname_offs, rs->provname_size,
1472 sc->sc_info.provider, sizeof (sc->sc_info.provider));
1473 umb_getinfobuf(data, len, rs->provid_offs, rs->provid_size,
1474 sc->sc_info.providerid, sizeof (sc->sc_info.providerid));
1475 umb_getinfobuf(data, len, rs->roamingtxt_offs, rs->roamingtxt_size,
1476 sc->sc_info.roamingtxt, sizeof (sc->sc_info.roamingtxt));
1477
1478 DPRINTFN(2, "%s: %s, availclass 0x%x, class 0x%x, regmode %d\n",do { } while (0)
1479 DEVNAM(sc), umb_regstate(sc->sc_info.regstate),do { } while (0)
1480 letoh32(rs->availclasses), sc->sc_info.cellclass,do { } while (0)
1481 sc->sc_info.regmode)do { } while (0);
1482
1483 if (sc->sc_info.regstate == MBIM_REGSTATE_ROAMING4 &&
1484 !sc->sc_roamingsc_info.enable_roaming &&
1485 sc->sc_info.activation == MBIM_ACTIVATION_STATE_ACTIVATED1) {
1486 if (ifp->if_flags & IFF_DEBUG0x4)
1487 log(LOG_INFO6,
1488 "%s: disconnecting from roaming network\n",
1489 DEVNAM(sc)(((struct umb_softc *)(sc))->sc_dev.dv_xname));
1490 umb_disconnect(sc);
1491 }
1492 return 1;
1493}
1494
1495int
1496umb_decode_devices_caps(struct umb_softc *sc, void *data, int len)
1497{
1498 struct mbim_cid_device_caps *dc = data;
1499
1500 if (len < sizeof (*dc))
1501 return 0;
1502 sc->sc_maxsessions = letoh32(dc->max_sessions)((__uint32_t)(dc->max_sessions));
1503 sc->sc_info.supportedclasses = letoh32(dc->dataclass)((__uint32_t)(dc->dataclass));
1504 umb_getinfobuf(data, len, dc->devid_offs, dc->devid_size,
1505 sc->sc_info.devid, sizeof (sc->sc_info.devid));
1506 umb_getinfobuf(data, len, dc->fwinfo_offs, dc->fwinfo_size,
1507 sc->sc_info.fwinfo, sizeof (sc->sc_info.fwinfo));
1508 umb_getinfobuf(data, len, dc->hwinfo_offs, dc->hwinfo_size,
1509 sc->sc_info.hwinfo, sizeof (sc->sc_info.hwinfo));
1510 DPRINTFN(2, "%s: max sessions %d, supported classes 0x%x\n",do { } while (0)
1511 DEVNAM(sc), sc->sc_maxsessions, sc->sc_info.supportedclasses)do { } while (0);
1512 return 1;
1513}
1514
1515int
1516umb_decode_subscriber_status(struct umb_softc *sc, void *data, int len)
1517{
1518 struct mbim_cid_subscriber_ready_info *si = data;
1519 struct ifnet *ifp = GET_IFP(sc)(&(sc)->sc_if);
1520 int npn;
1521
1522 if (len < sizeof (*si))
1523 return 0;
1524 sc->sc_info.sim_state = letoh32(si->ready)((__uint32_t)(si->ready));
1525
1526 umb_getinfobuf(data, len, si->sid_offs, si->sid_size,
1527 sc->sc_info.sid, sizeof (sc->sc_info.sid));
1528 umb_getinfobuf(data, len, si->icc_offs, si->icc_size,
1529 sc->sc_info.iccid, sizeof (sc->sc_info.iccid));
1530
1531 npn = letoh32(si->no_pn)((__uint32_t)(si->no_pn));
1532 if (npn > 0)
1533 umb_getinfobuf(data, len, si->pn[0].offs, si->pn[0].size,
1534 sc->sc_info.pn, sizeof (sc->sc_info.pn));
1535 else
1536 memset(sc->sc_info.pn, 0, sizeof (sc->sc_info.pn))__builtin_memset((sc->sc_info.pn), (0), (sizeof (sc->sc_info
.pn)))
;
1537
1538 if (sc->sc_info.sim_state == MBIM_SIMSTATE_LOCKED6)
1539 sc->sc_info.pin_state = UMB_PUK_REQUIRED2;
1540 if (ifp->if_flags & IFF_DEBUG0x4)
1541 log(LOG_INFO6, "%s: SIM %s\n", DEVNAM(sc)(((struct umb_softc *)(sc))->sc_dev.dv_xname),
1542 umb_simstate(sc->sc_info.sim_state)umb_val2descr(umb_simstate, (sc->sc_info.sim_state)));
1543 if (sc->sc_info.sim_state == MBIM_SIMSTATE_INITIALIZED1)
1544 umb_newstate(sc, UMB_S_SIMREADY, UMB_NS_DONT_DROP0x0001);
1545 return 1;
1546}
1547
1548int
1549umb_decode_radio_state(struct umb_softc *sc, void *data, int len)
1550{
1551 struct mbim_cid_radio_state_info *rs = data;
1552 struct ifnet *ifp = GET_IFP(sc)(&(sc)->sc_if);
1553
1554 if (len < sizeof (*rs))
1555 return 0;
1556
1557 sc->sc_info.hw_radio_on =
1558 (letoh32(rs->hw_state)((__uint32_t)(rs->hw_state)) == MBIM_RADIO_STATE_ON1) ? 1 : 0;
1559 sc->sc_info.sw_radio_on =
1560 (letoh32(rs->sw_state)((__uint32_t)(rs->sw_state)) == MBIM_RADIO_STATE_ON1) ? 1 : 0;
1561 if (!sc->sc_info.hw_radio_on) {
1562 printf("%s: radio is disabled by hardware switch\n",
1563 DEVNAM(sc)(((struct umb_softc *)(sc))->sc_dev.dv_xname));
1564 /*
1565 * XXX do we need a time to poll the state of the rfkill switch
1566 * or will the device send an unsolicited notification
1567 * in case the state changes?
1568 */
1569 umb_newstate(sc, UMB_S_OPEN, 0);
1570 } else if (!sc->sc_info.sw_radio_on) {
1571 if (ifp->if_flags & IFF_DEBUG0x4)
1572 log(LOG_INFO6, "%s: radio is off\n", DEVNAM(sc)(((struct umb_softc *)(sc))->sc_dev.dv_xname));
1573 umb_newstate(sc, UMB_S_OPEN, 0);
1574 } else
1575 umb_newstate(sc, UMB_S_RADIO, UMB_NS_DONT_DROP0x0001);
1576 return 1;
1577}
1578
1579int
1580umb_decode_pin(struct umb_softc *sc, void *data, int len)
1581{
1582 struct mbim_cid_pin_info *pi = data;
1583 struct ifnet *ifp = GET_IFP(sc)(&(sc)->sc_if);
1584 uint32_t attempts_left;
1585
1586 if (len < sizeof (*pi))
1587 return 0;
1588
1589 attempts_left = letoh32(pi->remaining_attempts)((__uint32_t)(pi->remaining_attempts));
1590 if (attempts_left != 0xffffffff)
1591 sc->sc_info.pin_attempts_left = attempts_left;
1592
1593 switch (letoh32(pi->state)((__uint32_t)(pi->state))) {
1594 case MBIM_PIN_STATE_UNLOCKED0:
1595 sc->sc_info.pin_state = UMB_PIN_UNLOCKED1;
1596 break;
1597 case MBIM_PIN_STATE_LOCKED1:
1598 switch (letoh32(pi->type)((__uint32_t)(pi->type))) {
1599 case MBIM_PIN_TYPE_PIN12:
1600 sc->sc_info.pin_state = UMB_PIN_REQUIRED0;
1601 break;
1602 case MBIM_PIN_TYPE_PUK111:
1603 sc->sc_info.pin_state = UMB_PUK_REQUIRED2;
1604 break;
1605 case MBIM_PIN_TYPE_PIN23:
1606 case MBIM_PIN_TYPE_PUK212:
1607 /* Assume that PIN1 was accepted */
1608 sc->sc_info.pin_state = UMB_PIN_UNLOCKED1;
1609 break;
1610 }
1611 break;
1612 }
1613 if (ifp->if_flags & IFF_DEBUG0x4)
1614 log(LOG_INFO6, "%s: %s state %s (%d attempts left)\n",
1615 DEVNAM(sc)(((struct umb_softc *)(sc))->sc_dev.dv_xname), umb_pin_type(letoh32(pi->type))umb_val2descr(umb_pintype, (((__uint32_t)(pi->type)))),
1616 (letoh32(pi->state)((__uint32_t)(pi->state)) == MBIM_PIN_STATE_UNLOCKED0) ?
1617 "unlocked" : "locked",
1618 letoh32(pi->remaining_attempts)((__uint32_t)(pi->remaining_attempts)));
1619
1620 /*
1621 * In case the PIN was set after IFF_UP, retrigger the state machine
1622 */
1623 usb_add_task(sc->sc_udev, &sc->sc_umb_task);
1624 return 1;
1625}
1626
1627int
1628umb_decode_packet_service(struct umb_softc *sc, void *data, int len)
1629{
1630 struct mbim_cid_packet_service_info *psi = data;
1631 int state, highestclass;
1632 uint64_t up_speed, down_speed;
1633 struct ifnet *ifp = GET_IFP(sc)(&(sc)->sc_if);
1634
1635 if (len < sizeof (*psi))
1636 return 0;
1637
1638 sc->sc_info.nwerror = letoh32(psi->nwerror)((__uint32_t)(psi->nwerror));
1639 state = letoh32(psi->state)((__uint32_t)(psi->state));
1640 highestclass = letoh32(psi->highest_dataclass)((__uint32_t)(psi->highest_dataclass));
1641 up_speed = letoh64(psi->uplink_speed)((__uint64_t)(psi->uplink_speed));
1642 down_speed = letoh64(psi->downlink_speed)((__uint64_t)(psi->downlink_speed));
1643 if (sc->sc_info.packetstate != state ||
1644 sc->sc_info.uplink_speed != up_speed ||
1645 sc->sc_info.downlink_speed != down_speed) {
1646 if (ifp->if_flags & IFF_DEBUG0x4) {
1647 log(LOG_INFO6, "%s: packet service ", DEVNAM(sc)(((struct umb_softc *)(sc))->sc_dev.dv_xname));
1648 if (sc->sc_info.packetstate != state)
1649 addlog("changed from %s to ",
1650 umb_packet_state(sc->sc_info.packetstate)umb_val2descr(umb_pktstate, (sc->sc_info.packetstate)));
1651 addlog("%s, class %s, speed: %llu up / %llu down\n",
1652 umb_packet_state(state)umb_val2descr(umb_pktstate, (state)),
1653 umb_dataclass(highestclass)umb_val2descr(umb_dataclasses, (highestclass)), up_speed, down_speed);
1654 }
1655 }
1656 sc->sc_info.packetstate = state;
1657 sc->sc_info.highestclass = highestclass;
1658 sc->sc_info.uplink_speed = up_speed;
1659 sc->sc_info.downlink_speed = down_speed;
1660
1661 if (sc->sc_info.regmode == MBIM_REGMODE_AUTOMATIC1) {
1662 /*
1663 * For devices using automatic registration mode, just proceed,
1664 * once registration has completed.
1665 */
1666 if (ifp->if_flags & IFF_UP0x1) {
1667 switch (sc->sc_info.regstate) {
1668 case MBIM_REGSTATE_HOME3:
1669 case MBIM_REGSTATE_ROAMING4:
1670 case MBIM_REGSTATE_PARTNER5:
1671 umb_newstate(sc, UMB_S_ATTACHED,
1672 UMB_NS_DONT_DROP0x0001);
1673 break;
1674 default:
1675 break;
1676 }
1677 } else
1678 umb_newstate(sc, UMB_S_SIMREADY, UMB_NS_DONT_RAISE0x0002);
1679 } else switch (sc->sc_info.packetstate) {
1680 case MBIM_PKTSERVICE_STATE_ATTACHED2:
1681 umb_newstate(sc, UMB_S_ATTACHED, UMB_NS_DONT_DROP0x0001);
1682 break;
1683 case MBIM_PKTSERVICE_STATE_DETACHED4:
1684 umb_newstate(sc, UMB_S_SIMREADY, UMB_NS_DONT_RAISE0x0002);
1685 break;
1686 }
1687 return 1;
1688}
1689
1690int
1691umb_decode_signal_state(struct umb_softc *sc, void *data, int len)
1692{
1693 struct mbim_cid_signal_state *ss = data;
1694 struct ifnet *ifp = GET_IFP(sc)(&(sc)->sc_if);
1695 int rssi;
1696#if NKSTAT1 > 0
1697 struct kstat *ks;
1698#endif
1699
1700 if (len < sizeof (*ss))
1701 return 0;
1702
1703 if (letoh32(ss->rssi)((__uint32_t)(ss->rssi)) == 99)
1704 rssi = UMB_VALUE_UNKNOWN-999;
1705 else {
1706 rssi = -113 + 2 * letoh32(ss->rssi)((__uint32_t)(ss->rssi));
1707 if ((ifp->if_flags & IFF_DEBUG0x4) && sc->sc_info.rssi != rssi &&
1708 sc->sc_statesc_info.state >= UMB_S_CONNECTED)
1709 log(LOG_INFO6, "%s: rssi %d dBm\n", DEVNAM(sc)(((struct umb_softc *)(sc))->sc_dev.dv_xname), rssi);
1710 }
1711 sc->sc_info.rssi = rssi;
1712 sc->sc_info.ber = letoh32(ss->err_rate)((__uint32_t)(ss->err_rate));
1713 if (sc->sc_info.ber == 99)
1714 sc->sc_info.ber = UMB_VALUE_UNKNOWN-999;
1715
1716#if NKSTAT1 > 0
1717 ks = sc->sc_kstat_signal;
1718 if (ks != NULL((void *)0)) {
1719 struct umb_kstat_signal *uks = ks->ks_data;
1720
1721 rw_enter_write(&sc->sc_kstat_lock);
1722 kstat_kv_u64(&uks->reports)(&uks->reports)->kv_v.v_u64++;
1723
1724 if (sc->sc_info.rssi == UMB_VALUE_UNKNOWN-999)
1725 uks->rssi.kv_type = KSTAT_KV_T_NULL;
1726 else {
1727 uks->rssi.kv_type = KSTAT_KV_T_INT32;
1728 kstat_kv_s32(&uks->rssi)(&uks->rssi)->kv_v.v_s32 = sc->sc_info.rssi;
1729 }
1730
1731 if (sc->sc_info.ber == UMB_VALUE_UNKNOWN-999)
1732 uks->error_rate.kv_type = KSTAT_KV_T_NULL;
1733 else {
1734 uks->error_rate.kv_type = KSTAT_KV_T_INT32;
1735 kstat_kv_s32(&uks->error_rate)(&uks->error_rate)->kv_v.v_s32 = sc->sc_info.ber;
1736 }
1737
1738 ks->ks_interval.tv_sec = letoh32(ss->ss_intvl)((__uint32_t)(ss->ss_intvl));
1739 getnanouptime(&ks->ks_updated);
1740 rw_exit_write(&sc->sc_kstat_lock);
1741 }
1742#endif
1743
1744 return 1;
1745}
1746
1747int
1748umb_decode_connect_info(struct umb_softc *sc, void *data, int len)
1749{
1750 struct mbim_cid_connect_info *ci = data;
1751 struct ifnet *ifp = GET_IFP(sc)(&(sc)->sc_if);
1752 int act;
1753
1754 if (len < sizeof (*ci))
1755 return 0;
1756
1757 if (letoh32(ci->sessionid)((__uint32_t)(ci->sessionid)) != umb_session_id) {
1758 DPRINTF("%s: discard connection info for session %u\n",do { } while (0)
1759 DEVNAM(sc), letoh32(ci->sessionid))do { } while (0);
1760 return 1;
1761 }
1762 if (memcmp(ci->context, umb_uuid_context_internet,__builtin_memcmp((ci->context), (umb_uuid_context_internet
), (sizeof (ci->context)))
1763 sizeof (ci->context))__builtin_memcmp((ci->context), (umb_uuid_context_internet
), (sizeof (ci->context)))
) {
1764 DPRINTF("%s: discard connection info for other context\n",do { } while (0)
1765 DEVNAM(sc))do { } while (0);
1766 return 1;
1767 }
1768 act = letoh32(ci->activation)((__uint32_t)(ci->activation));
1769 if (sc->sc_info.activation != act) {
1770 if (ifp->if_flags & IFF_DEBUG0x4)
1771 log(LOG_INFO6, "%s: connection %s\n", DEVNAM(sc)(((struct umb_softc *)(sc))->sc_dev.dv_xname),
1772 umb_activation(act)umb_val2descr(umb_actstate, (act)));
1773
1774 sc->sc_info.activation = act;
1775 sc->sc_info.nwerror = letoh32(ci->nwerror)((__uint32_t)(ci->nwerror));
1776
1777 if (sc->sc_info.activation == MBIM_ACTIVATION_STATE_ACTIVATED1)
1778 umb_newstate(sc, UMB_S_CONNECTED, UMB_NS_DONT_DROP0x0001);
1779 else if (sc->sc_info.activation ==
1780 MBIM_ACTIVATION_STATE_DEACTIVATED3)
1781 umb_newstate(sc, UMB_S_ATTACHED, 0);
1782 /* else: other states are purely transitional */
1783 }
1784 return 1;
1785}
1786
1787void
1788umb_clear_addr(struct umb_softc *sc)
1789{
1790 struct ifnet *ifp = GET_IFP(sc)(&(sc)->sc_if);
1791
1792 memset(sc->sc_info.ipv4dns, 0, sizeof (sc->sc_info.ipv4dns))__builtin_memset((sc->sc_info.ipv4dns), (0), (sizeof (sc->
sc_info.ipv4dns)))
;
1793 memset(sc->sc_info.ipv6dns, 0, sizeof (sc->sc_info.ipv6dns))__builtin_memset((sc->sc_info.ipv6dns), (0), (sizeof (sc->
sc_info.ipv6dns)))
;
1794 umb_send_inet_proposal(sc, AF_INET2);
1795#ifdef INET61
1796 umb_send_inet_proposal(sc, AF_INET624);
1797#endif
1798 NET_LOCK()do { rw_enter_write(&netlock); } while (0);
1799 in_ifdetach(ifp);
1800#ifdef INET61
1801 in6_ifdetach(ifp);
1802#endif
1803 NET_UNLOCK()do { rw_exit_write(&netlock); } while (0);
1804}
1805
1806int
1807umb_add_inet_config(struct umb_softc *sc, struct in_addr ip, u_int prefixlen,
1808 struct in_addr gw)
1809{
1810 struct ifnet *ifp = GET_IFP(sc)(&(sc)->sc_if);
1811 struct in_aliasreq ifra;
1812 struct sockaddr_in *sin, default_sin;
1813 struct rt_addrinfo info;
1814 struct rtentry *rt;
1815 int rv;
1816
1817 memset(&ifra, 0, sizeof (ifra))__builtin_memset((&ifra), (0), (sizeof (ifra)));
1818 rv = in_ioctl(SIOCDIFADDR((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff
) << 16) | ((('i')) << 8) | ((25)))
, (caddr_t)&ifra, ifp, 1);
1819 if (rv != 0 && rv != EADDRNOTAVAIL49) {
1820 printf("%s: unable to delete IPv4 address, error %d\n",
1821 DEVNAM(ifp->if_softc)(((struct umb_softc *)(ifp->if_softc))->sc_dev.dv_xname
)
, rv);
1822 return rv;
1823 }
1824
1825 memset(&ifra, 0, sizeof (ifra))__builtin_memset((&ifra), (0), (sizeof (ifra)));
1826 sin = &ifra.ifra_addrifra_ifrau.ifrau_addr;
1827 sin->sin_family = AF_INET2;
1828 sin->sin_len = sizeof (*sin);
1829 sin->sin_addr = ip;
1830
1831 sin = &ifra.ifra_dstaddr;
1832 sin->sin_family = AF_INET2;
1833 sin->sin_len = sizeof (*sin);
1834 sin->sin_addr = gw;
1835
1836 sin = &ifra.ifra_mask;
1837 sin->sin_family = AF_INET2;
1838 sin->sin_len = sizeof (*sin);
1839 in_len2mask(&sin->sin_addr, prefixlen);
1840
1841 rv = in_ioctl(SIOCAIFADDR((unsigned long)0x80000000 | ((sizeof(struct ifaliasreq) &
0x1fff) << 16) | ((('i')) << 8) | ((26)))
, (caddr_t)&ifra, ifp, 1);
1842 if (rv != 0) {
1843 printf("%s: unable to set IPv4 address, error %d\n",
1844 DEVNAM(ifp->if_softc)(((struct umb_softc *)(ifp->if_softc))->sc_dev.dv_xname
)
, rv);
1845 return rv;
1846 }
1847
1848 memset(&default_sin, 0, sizeof(default_sin))__builtin_memset((&default_sin), (0), (sizeof(default_sin
)))
;
1849 default_sin.sin_family = AF_INET2;
1850 default_sin.sin_len = sizeof (default_sin);
1851
1852 memset(&info, 0, sizeof(info))__builtin_memset((&info), (0), (sizeof(info)));
1853 NET_LOCK()do { rw_enter_write(&netlock); } while (0);
1854 info.rti_flags = RTF_GATEWAY0x2 /* maybe | RTF_STATIC */;
1855 info.rti_ifa = ifa_ifwithaddr(sintosa(&ifra.ifra_addrifra_ifrau.ifrau_addr),
1856 ifp->if_rdomainif_data.ifi_rdomain);
1857 info.rti_info[RTAX_DST0] = sintosa(&default_sin);
1858 info.rti_info[RTAX_NETMASK2] = sintosa(&default_sin);
1859 info.rti_info[RTAX_GATEWAY1] = sintosa(&ifra.ifra_dstaddr);
1860
1861 rv = rtrequest(RTM_ADD0x1, &info, 0, &rt, ifp->if_rdomainif_data.ifi_rdomain);
1862 if (rv) {
1863 printf("%s: unable to set IPv4 default route, "
1864 "error %d\n", DEVNAM(ifp->if_softc)(((struct umb_softc *)(ifp->if_softc))->sc_dev.dv_xname
)
, rv);
1865 rtm_miss(RTM_MISS0x7, &info, 0, RTP_NONE0, 0, rv,
1866 ifp->if_rdomainif_data.ifi_rdomain);
1867 } else {
1868 /* Inform listeners of the new route */
1869 rtm_send(rt, RTM_ADD0x1, rv, ifp->if_rdomainif_data.ifi_rdomain);
1870 rtfree(rt);
1871 }
1872 NET_UNLOCK()do { rw_exit_write(&netlock); } while (0);
1873
1874 if (ifp->if_flags & IFF_DEBUG0x4) {
1875 char str[3][INET_ADDRSTRLEN16];
1876 log(LOG_INFO6, "%s: IPv4 addr %s, mask %s, gateway %s\n",
1877 DEVNAM(ifp->if_softc)(((struct umb_softc *)(ifp->if_softc))->sc_dev.dv_xname
)
,
1878 sockaddr_ntop(sintosa(&ifra.ifra_addrifra_ifrau.ifrau_addr), str[0],
1879 sizeof(str[0])),
1880 sockaddr_ntop(sintosa(&ifra.ifra_mask), str[1],
1881 sizeof(str[1])),
1882 sockaddr_ntop(sintosa(&ifra.ifra_dstaddr), str[2],
1883 sizeof(str[2])));
1884 }
1885 return 0;
1886}
1887
1888#ifdef INET61
1889int
1890umb_add_inet6_config(struct umb_softc *sc, struct in6_addr *ip, u_int prefixlen,
1891 struct in6_addr *gw)
1892{
1893 struct ifnet *ifp = GET_IFP(sc)(&(sc)->sc_if);
1894 struct in6_aliasreq ifra;
1895 struct sockaddr_in6 *sin6, default_sin6;
1896 struct rt_addrinfo info;
1897 struct rtentry *rt;
1898 int rv;
1899
1900 memset(&ifra, 0, sizeof (ifra))__builtin_memset((&ifra), (0), (sizeof (ifra)));
1901 sin6 = &ifra.ifra_addrifra_ifrau.ifrau_addr;
1902 sin6->sin6_family = AF_INET624;
1903 sin6->sin6_len = sizeof (*sin6);
1904 memcpy(&sin6->sin6_addr, ip, sizeof (sin6->sin6_addr))__builtin_memcpy((&sin6->sin6_addr), (ip), (sizeof (sin6
->sin6_addr)))
;
1905
1906 sin6 = &ifra.ifra_dstaddr;
1907 sin6->sin6_family = AF_INET624;
1908 sin6->sin6_len = sizeof (*sin6);
1909 memcpy(&sin6->sin6_addr, gw, sizeof (sin6->sin6_addr))__builtin_memcpy((&sin6->sin6_addr), (gw), (sizeof (sin6
->sin6_addr)))
;
1910
1911 /* XXX: in6_update_ifa() accepts only 128 bits for P2P interfaces. */
1912 prefixlen = 128;
1913
1914 sin6 = &ifra.ifra_prefixmask;
1915 sin6->sin6_family = AF_INET624;
1916 sin6->sin6_len = sizeof (*sin6);
1917 in6_prefixlen2mask(&sin6->sin6_addr, prefixlen);
1918
1919 ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME0xffffffff;
1920 ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME0xffffffff;
1921
1922 rv = in6_ioctl(SIOCAIFADDR_IN6((unsigned long)0x80000000 | ((sizeof(struct in6_aliasreq) &
0x1fff) << 16) | ((('i')) << 8) | ((26)))
, (caddr_t)&ifra, ifp, 1);
1923 if (rv != 0) {
1924 printf("%s: unable to set IPv6 address, error %d\n",
1925 DEVNAM(ifp->if_softc)(((struct umb_softc *)(ifp->if_softc))->sc_dev.dv_xname
)
, rv);
1926 return rv;
1927 }
1928
1929 memset(&default_sin6, 0, sizeof(default_sin6))__builtin_memset((&default_sin6), (0), (sizeof(default_sin6
)))
;
1930 default_sin6.sin6_family = AF_INET624;
1931 default_sin6.sin6_len = sizeof (default_sin6);
1932
1933 memset(&info, 0, sizeof(info))__builtin_memset((&info), (0), (sizeof(info)));
1934 NET_LOCK()do { rw_enter_write(&netlock); } while (0);
1935 info.rti_flags = RTF_GATEWAY0x2 /* maybe | RTF_STATIC */;
1936 info.rti_ifa = ifa_ifwithaddr(sin6tosa(&ifra.ifra_addrifra_ifrau.ifrau_addr),
1937 ifp->if_rdomainif_data.ifi_rdomain);
1938 info.rti_info[RTAX_DST0] = sin6tosa(&default_sin6);
1939 info.rti_info[RTAX_NETMASK2] = sin6tosa(&default_sin6);
1940 info.rti_info[RTAX_GATEWAY1] = sin6tosa(&ifra.ifra_dstaddr);
1941
1942 rv = rtrequest(RTM_ADD0x1, &info, 0, &rt, ifp->if_rdomainif_data.ifi_rdomain);
1943 if (rv) {
1944 printf("%s: unable to set IPv6 default route, "
1945 "error %d\n", DEVNAM(ifp->if_softc)(((struct umb_softc *)(ifp->if_softc))->sc_dev.dv_xname
)
, rv);
1946 rtm_miss(RTM_MISS0x7, &info, 0, RTP_NONE0, 0, rv,
1947 ifp->if_rdomainif_data.ifi_rdomain);
1948 } else {
1949 /* Inform listeners of the new route */
1950 rtm_send(rt, RTM_ADD0x1, rv, ifp->if_rdomainif_data.ifi_rdomain);
1951 rtfree(rt);
1952 }
1953 NET_UNLOCK()do { rw_exit_write(&netlock); } while (0);
1954
1955 if (ifp->if_flags & IFF_DEBUG0x4) {
1956 char str[3][INET6_ADDRSTRLEN46];
1957 log(LOG_INFO6, "%s: IPv6 addr %s, mask %s, gateway %s\n",
1958 DEVNAM(ifp->if_softc)(((struct umb_softc *)(ifp->if_softc))->sc_dev.dv_xname
)
,
1959 sockaddr_ntop(sin6tosa(&ifra.ifra_addrifra_ifrau.ifrau_addr), str[0],
1960 sizeof(str[0])),
1961 sockaddr_ntop(sin6tosa(&ifra.ifra_prefixmask), str[1],
1962 sizeof(str[1])),
1963 sockaddr_ntop(sin6tosa(&ifra.ifra_dstaddr), str[2],
1964 sizeof(str[2])));
1965 }
1966 return 0;
1967}
1968#endif
1969
1970void
1971umb_send_inet_proposal(struct umb_softc *sc, int af)
1972{
1973 struct ifnet *ifp = GET_IFP(sc)(&(sc)->sc_if);
1974 struct sockaddr_rtdns rtdns;
1975 struct rt_addrinfo info;
1976 int i, flag = 0;
1977 size_t sz = 0;
1978
1979 memset(&rtdns, 0, sizeof(rtdns))__builtin_memset((&rtdns), (0), (sizeof(rtdns)));
1980 memset(&info, 0, sizeof(info))__builtin_memset((&info), (0), (sizeof(info)));
1981
1982 for (i = 0; i < UMB_MAX_DNSSRV2; i++) {
1983 if (af == AF_INET2) {
1984 sz = sizeof (sc->sc_info.ipv4dns[i]);
1985 if (sc->sc_info.ipv4dns[i].s_addr == INADDR_ANY((u_int32_t) (__uint32_t)(__builtin_constant_p((u_int32_t)(0x00000000
)) ? (__uint32_t)(((__uint32_t)((u_int32_t)(0x00000000)) &
0xff) << 24 | ((__uint32_t)((u_int32_t)(0x00000000)) &
0xff00) << 8 | ((__uint32_t)((u_int32_t)(0x00000000)) &
0xff0000) >> 8 | ((__uint32_t)((u_int32_t)(0x00000000)
) & 0xff000000) >> 24) : __swap32md((u_int32_t)(0x00000000
))))
)
1986 break;
1987 memcpy(rtdns.sr_dns + i * sz, &sc->sc_info.ipv4dns[i],__builtin_memcpy((rtdns.sr_dns + i * sz), (&sc->sc_info
.ipv4dns[i]), (sz))
1988 sz)__builtin_memcpy((rtdns.sr_dns + i * sz), (&sc->sc_info
.ipv4dns[i]), (sz))
;
1989 flag = RTF_UP0x1;
1990#ifdef INET61
1991 } else if (af == AF_INET624) {
1992 sz = sizeof (sc->sc_info.ipv6dns[i]);
1993 if (IN6_ARE_ADDR_EQUAL(&sc->sc_info.ipv6dns[i],(__builtin_memcmp((&(&sc->sc_info.ipv6dns[i])->
__u6_addr.__u6_addr8[0]), (&(&in6addr_any)->__u6_addr
.__u6_addr8[0]), (sizeof(struct in6_addr))) == 0)
1994 &in6addr_any)(__builtin_memcmp((&(&sc->sc_info.ipv6dns[i])->
__u6_addr.__u6_addr8[0]), (&(&in6addr_any)->__u6_addr
.__u6_addr8[0]), (sizeof(struct in6_addr))) == 0)
)
1995 break;
1996 memcpy(rtdns.sr_dns + i * sz, &sc->sc_info.ipv6dns[i],__builtin_memcpy((rtdns.sr_dns + i * sz), (&sc->sc_info
.ipv6dns[i]), (sz))
1997 sz)__builtin_memcpy((rtdns.sr_dns + i * sz), (&sc->sc_info
.ipv6dns[i]), (sz))
;
1998 flag = RTF_UP0x1;
1999#endif
2000 }
2001 }
2002 rtdns.sr_family = af;
2003 rtdns.sr_len = 2 + i * sz;
2004 info.rti_info[RTAX_DNS12] = srtdnstosa(&rtdns);
2005
2006 rtm_proposal(ifp, &info, flag, RTP_PROPOSAL_UMB60);
2007}
2008
2009int
2010umb_decode_ip_configuration(struct umb_softc *sc, void *data, int len)
2011{
2012 struct mbim_cid_ip_configuration_info *ic = data;
2013 struct ifnet *ifp = GET_IFP(sc)(&(sc)->sc_if);
2014 int s;
2015 uint32_t avail_v4;
2016 uint32_t val;
2017 int n, i;
2018 int off;
2019 struct mbim_cid_ipv4_element ipv4elem;
2020 struct in_addr addr, gw;
2021 int state = -1;
2022 int rv;
2023 int hasmtu = 0;
2024#ifdef INET61
2025 uint32_t avail_v6;
2026 struct mbim_cid_ipv6_element ipv6elem;
2027 struct in6_addr addr6, gw6;
2028#endif
2029
2030 if (len < sizeof (*ic))
2031 return 0;
2032 if (letoh32(ic->sessionid)((__uint32_t)(ic->sessionid)) != umb_session_id) {
2033 DPRINTF("%s: ignore IP configuration for session id %d\n",do { } while (0)
2034 DEVNAM(sc), letoh32(ic->sessionid))do { } while (0);
2035 return 0;
2036 }
2037 s = splnet()splraise(0x4);
2038
2039 memset(sc->sc_info.ipv4dns, 0, sizeof (sc->sc_info.ipv4dns))__builtin_memset((sc->sc_info.ipv4dns), (0), (sizeof (sc->
sc_info.ipv4dns)))
;
2040 memset(sc->sc_info.ipv6dns, 0, sizeof (sc->sc_info.ipv6dns))__builtin_memset((sc->sc_info.ipv6dns), (0), (sizeof (sc->
sc_info.ipv6dns)))
;
2041
2042 /*
2043 * IPv4 configuration
2044 */
2045 avail_v4 = letoh32(ic->ipv4_available)((__uint32_t)(ic->ipv4_available));
2046 if ((avail_v4 & (MBIM_IPCONF_HAS_ADDRINFO0x0001 | MBIM_IPCONF_HAS_GWINFO0x0002)) ==
2047 (MBIM_IPCONF_HAS_ADDRINFO0x0001 | MBIM_IPCONF_HAS_GWINFO0x0002)) {
2048 n = letoh32(ic->ipv4_naddr)((__uint32_t)(ic->ipv4_naddr));
2049 off = letoh32(ic->ipv4_addroffs)((__uint32_t)(ic->ipv4_addroffs));
2050
2051 if (n == 0 || off + sizeof (ipv4elem) > len)
2052 goto tryv6;
2053 if (n != 1 && ifp->if_flags & IFF_DEBUG0x4)
2054 log(LOG_INFO6, "%s: more than one IPv4 addr: %d\n",
2055 DEVNAM(ifp->if_softc)(((struct umb_softc *)(ifp->if_softc))->sc_dev.dv_xname
)
, n);
2056
2057 /* Only pick the first one */
2058 memcpy(&ipv4elem, data + off, sizeof (ipv4elem))__builtin_memcpy((&ipv4elem), (data + off), (sizeof (ipv4elem
)))
;
2059 ipv4elem.prefixlen = letoh32(ipv4elem.prefixlen)((__uint32_t)(ipv4elem.prefixlen));
2060 addr.s_addr = ipv4elem.addr;
2061
2062 off = letoh32(ic->ipv4_gwoffs)((__uint32_t)(ic->ipv4_gwoffs));
2063 if (off + sizeof (gw) > len)
2064 goto done;
2065 memcpy(&gw, data + off, sizeof(gw))__builtin_memcpy((&gw), (data + off), (sizeof(gw)));
2066
2067 rv = umb_add_inet_config(sc, addr, ipv4elem.prefixlen, gw);
2068 if (rv == 0)
2069 state = UMB_S_UP;
2070
2071 }
2072
2073 memset(sc->sc_info.ipv4dns, 0, sizeof (sc->sc_info.ipv4dns))__builtin_memset((sc->sc_info.ipv4dns), (0), (sizeof (sc->
sc_info.ipv4dns)))
;
2074 if (avail_v4 & MBIM_IPCONF_HAS_DNSINFO0x0004) {
2075 n = letoh32(ic->ipv4_ndnssrv)((__uint32_t)(ic->ipv4_ndnssrv));
2076 off = letoh32(ic->ipv4_dnssrvoffs)((__uint32_t)(ic->ipv4_dnssrvoffs));
2077 i = 0;
2078 while (n-- > 0) {
2079 if (off + sizeof (addr) > len)
2080 break;
2081 memcpy(&addr, data + off, sizeof(addr))__builtin_memcpy((&addr), (data + off), (sizeof(addr)));
2082 if (i < UMB_MAX_DNSSRV2)
2083 sc->sc_info.ipv4dns[i++] = addr;
2084 off += sizeof(addr);
2085 if (ifp->if_flags & IFF_DEBUG0x4) {
2086 char str[INET_ADDRSTRLEN16];
2087 log(LOG_INFO6, "%s: IPv4 nameserver %s\n",
2088 DEVNAM(ifp->if_softc)(((struct umb_softc *)(ifp->if_softc))->sc_dev.dv_xname
)
, inet_ntop(AF_INET2,
2089 &addr, str, sizeof(str)));
2090 }
2091 }
2092 umb_send_inet_proposal(sc, AF_INET2);
2093 }
2094 if ((avail_v4 & MBIM_IPCONF_HAS_MTUINFO0x0008)) {
2095 val = letoh32(ic->ipv4_mtu)((__uint32_t)(ic->ipv4_mtu));
2096 if (ifp->if_hardmtu != val && val <= sc->sc_maxpktlen) {
2097 hasmtu = 1;
2098 ifp->if_hardmtu = val;
2099 if (ifp->if_mtuif_data.ifi_mtu > val)
2100 ifp->if_mtuif_data.ifi_mtu = val;
2101 }
2102 }
2103
2104tryv6:;
2105#ifdef INET61
2106 /*
2107 * IPv6 configuration
2108 */
2109 avail_v6 = letoh32(ic->ipv6_available)((__uint32_t)(ic->ipv6_available));
2110 if (avail_v6 == 0) {
2111 if (ifp->if_flags & IFF_DEBUG0x4)
2112 log(LOG_INFO6, "%s: ISP or WWAN module offers no IPv6 "
2113 "support\n", DEVNAM(ifp->if_softc)(((struct umb_softc *)(ifp->if_softc))->sc_dev.dv_xname
)
);
2114 goto done;
2115 }
2116
2117 if ((avail_v6 & (MBIM_IPCONF_HAS_ADDRINFO0x0001 | MBIM_IPCONF_HAS_GWINFO0x0002)) ==
2118 (MBIM_IPCONF_HAS_ADDRINFO0x0001 | MBIM_IPCONF_HAS_GWINFO0x0002)) {
2119 n = letoh32(ic->ipv6_naddr)((__uint32_t)(ic->ipv6_naddr));
2120 off = letoh32(ic->ipv6_addroffs)((__uint32_t)(ic->ipv6_addroffs));
2121
2122 if (n == 0 || off + sizeof (ipv6elem) > len)
2123 goto done;
2124 if (n != 1 && ifp->if_flags & IFF_DEBUG0x4)
2125 log(LOG_INFO6, "%s: more than one IPv6 addr: %d\n",
2126 DEVNAM(ifp->if_softc)(((struct umb_softc *)(ifp->if_softc))->sc_dev.dv_xname
)
, n);
2127
2128 /* Only pick the first one */
2129 memcpy(&ipv6elem, data + off, sizeof (ipv6elem))__builtin_memcpy((&ipv6elem), (data + off), (sizeof (ipv6elem
)))
;
2130 memcpy(&addr6, ipv6elem.addr, sizeof (addr6))__builtin_memcpy((&addr6), (ipv6elem.addr), (sizeof (addr6
)))
;
2131
2132 off = letoh32(ic->ipv6_gwoffs)((__uint32_t)(ic->ipv6_gwoffs));
2133 if (off + sizeof (gw6) > len)
2134 goto done;
2135 memcpy(&gw6, data + off, sizeof (gw6))__builtin_memcpy((&gw6), (data + off), (sizeof (gw6)));
2136
2137 rv = umb_add_inet6_config(sc, &addr6, ipv6elem.prefixlen, &gw6);
2138 if (rv == 0)
2139 state = UMB_S_UP;
2140 }
2141
2142 if (avail_v6 & MBIM_IPCONF_HAS_DNSINFO0x0004) {
2143 n = letoh32(ic->ipv6_ndnssrv)((__uint32_t)(ic->ipv6_ndnssrv));
2144 off = letoh32(ic->ipv6_dnssrvoffs)((__uint32_t)(ic->ipv6_dnssrvoffs));
2145 i = 0;
2146 while (n-- > 0) {
2147 if (off + sizeof (addr6) > len)
2148 break;
2149 memcpy(&addr6, data + off, sizeof(addr6))__builtin_memcpy((&addr6), (data + off), (sizeof(addr6)));
2150 if (i < UMB_MAX_DNSSRV2)
2151 sc->sc_info.ipv6dns[i++] = addr6;
2152 off += sizeof(addr6);
2153 if (ifp->if_flags & IFF_DEBUG0x4) {
2154 char str[INET6_ADDRSTRLEN46];
2155 log(LOG_INFO6, "%s: IPv6 nameserver %s\n",
2156 DEVNAM(ifp->if_softc)(((struct umb_softc *)(ifp->if_softc))->sc_dev.dv_xname
)
, inet_ntop(AF_INET624,
2157 &addr6, str, sizeof(str)));
2158 }
2159 }
2160 umb_send_inet_proposal(sc, AF_INET624);
2161 }
2162
2163 if ((avail_v6 & MBIM_IPCONF_HAS_MTUINFO0x0008)) {
2164 val = letoh32(ic->ipv6_mtu)((__uint32_t)(ic->ipv6_mtu));
2165 if (ifp->if_hardmtu != val && val <= sc->sc_maxpktlen) {
2166 hasmtu = 1;
2167 ifp->if_hardmtu = val;
2168 if (ifp->if_mtuif_data.ifi_mtu > val)
2169 ifp->if_mtuif_data.ifi_mtu = val;
2170 }
2171 }
2172#endif
2173
2174done:
2175 if (hasmtu && (ifp->if_flags & IFF_DEBUG0x4))
2176 log(LOG_INFO6, "%s: MTU %d\n", DEVNAM(sc)(((struct umb_softc *)(sc))->sc_dev.dv_xname), ifp->if_hardmtu);
2177
2178 if (state != -1)
2179 umb_newstate(sc, state, 0);
2180
2181 splx(s)spllower(s);
2182 return 1;
2183}
2184
2185void
2186umb_rx(struct umb_softc *sc)
2187{
2188 usbd_setup_xfer(sc->sc_rx_xfer, sc->sc_rx_pipe, sc, sc->sc_rx_buf,
2189 sc->sc_rx_bufsz, USBD_SHORT_XFER_OK0x04 | USBD_NO_COPY0x01,
2190 USBD_NO_TIMEOUT0, umb_rxeof);
2191 usbd_transfer(sc->sc_rx_xfer);
2192}
2193
2194void
2195umb_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
2196{
2197 struct umb_softc *sc = priv;
2198 struct ifnet *ifp = GET_IFP(sc)(&(sc)->sc_if);
2199
2200 if (usbd_is_dying(sc->sc_udev) || !(ifp->if_flags & IFF_RUNNING0x40))
2201 return;
2202
2203 if (status != USBD_NORMAL_COMPLETION) {
2204 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
2205 return;
2206 DPRINTF("%s: rx error: %s\n", DEVNAM(sc), usbd_errstr(status))do { } while (0);
2207 if (status == USBD_STALLED)
2208 usbd_clear_endpoint_stall_async(sc->sc_rx_pipe);
2209 if (++sc->sc_rx_nerr > 100) {
2210 log(LOG_ERR3, "%s: too many rx errors, disabling\n",
2211 DEVNAM(sc)(((struct umb_softc *)(sc))->sc_dev.dv_xname));
2212 usbd_deactivate(sc->sc_udev);
2213 }
2214 } else {
2215 sc->sc_rx_nerr = 0;
2216 umb_decap(sc, xfer);
2217 }
2218
2219 umb_rx(sc);
2220 return;
2221}
2222
2223int
2224umb_encap(struct umb_softc *sc, int ndgram)
2225{
2226 struct ncm_header16 *hdr16 = NULL((void *)0);
2227 struct ncm_header32 *hdr32 = NULL((void *)0);
2228 struct ncm_pointer16 *ptr16 = NULL((void *)0);
2229 struct ncm_pointer32 *ptr32 = NULL((void *)0);
2230 struct ncm_pointer16_dgram *dgram16 = NULL((void *)0);
2231 struct ncm_pointer32_dgram *dgram32 = NULL((void *)0);
28
'dgram32' initialized to a null pointer value
2232 int offs = 0, plen = 0;
2233 int dgoffs = 0, poffs;
2234 struct mbuf *m;
2235 usbd_status err;
2236
2237 /* All size constraints have been validated by the caller! */
2238
2239 /* NCM Header */
2240 switch (sc->sc_ncm_format) {
29
'Default' branch taken. Execution continues on line 2258
2241 case NCM_FORMAT_NTB160x00:
2242 hdr16 = sc->sc_tx_buf;
2243 USETDW(hdr16->dwSignature, NCM_HDR16_SIG)(*(u_int32_t *)(hdr16->dwSignature) = (0x484d434e));
2244 USETW(hdr16->wHeaderLength, sizeof (*hdr16))(*(u_int16_t *)(hdr16->wHeaderLength) = (sizeof (*hdr16)));
2245 USETW(hdr16->wSequence, sc->sc_tx_seq)(*(u_int16_t *)(hdr16->wSequence) = (sc->sc_tx_seq));
2246 USETW(hdr16->wBlockLength, 0)(*(u_int16_t *)(hdr16->wBlockLength) = (0));
2247 offs = sizeof (*hdr16);
2248 break;
2249 case NCM_FORMAT_NTB320x01:
2250 hdr32 = sc->sc_tx_buf;
2251 USETDW(hdr32->dwSignature, NCM_HDR32_SIG)(*(u_int32_t *)(hdr32->dwSignature) = (0x686d636e));
2252 USETW(hdr32->wHeaderLength, sizeof (*hdr32))(*(u_int16_t *)(hdr32->wHeaderLength) = (sizeof (*hdr32)));
2253 USETW(hdr32->wSequence, sc->sc_tx_seq)(*(u_int16_t *)(hdr32->wSequence) = (sc->sc_tx_seq));
2254 USETDW(hdr32->dwBlockLength, 0)(*(u_int32_t *)(hdr32->dwBlockLength) = (0));
2255 offs = sizeof (*hdr32);
2256 break;
2257 }
2258 offs += umb_padding(sc->sc_tx_buf, sc->sc_tx_bufsz, offs,
2259 sc->sc_align, 0);
2260
2261 if (sc->sc_flags & UMBFLG_NDP_AT_END0x0004) {
30
Assuming the condition is false
31
Taking false branch
2262 dgoffs = offs;
2263
2264 /*
2265 * Calculate space needed for datagrams.
2266 *
2267 * XXX cannot use ml_len(&sc->sc_tx_ml), since it ignores
2268 * the padding requirements.
2269 */
2270 poffs = dgoffs;
2271 MBUF_LIST_FOREACH(&sc->sc_tx_ml, m)for ((m) = ((&sc->sc_tx_ml)->ml_head); (m) != ((void
*)0); (m) = ((m)->m_hdr.mh_nextpkt))
{
2272 poffs += umb_padding(sc->sc_tx_buf, sc->sc_tx_bufsz,
2273 poffs, sc->sc_ndp_div, sc->sc_ndp_remainder);
2274 poffs += m->m_pkthdrM_dat.MH.MH_pkthdr.len;
2275 }
2276 poffs += umb_padding(sc->sc_tx_buf, sc->sc_tx_bufsz,
2277 poffs, sc->sc_ndp_div, sc->sc_ndp_remainder);
2278 } else
2279 poffs = offs;
2280
2281 /* NCM Pointer */
2282 switch (sc->sc_ncm_format) {
2283 case NCM_FORMAT_NTB160x00:
2284 USETW(hdr16->wNdpIndex, poffs)(*(u_int16_t *)(hdr16->wNdpIndex) = (poffs));
2285 ptr16 = (struct ncm_pointer16 *)(sc->sc_tx_buf + poffs);
2286 plen = sizeof(*ptr16) + ndgram * sizeof(*dgram16);
2287 USETDW(ptr16->dwSignature, MBIM_NCM_NTH16_SIG(umb_session_id))(*(u_int32_t *)(ptr16->dwSignature) = (((((umb_session_id)
& 0xff) << 24) | 0x00535049)))
;
2288 USETW(ptr16->wLength, plen)(*(u_int16_t *)(ptr16->wLength) = (plen));
2289 USETW(ptr16->wNextNdpIndex, 0)(*(u_int16_t *)(ptr16->wNextNdpIndex) = (0));
2290 dgram16 = ptr16->dgram;
2291 break;
2292 case NCM_FORMAT_NTB320x01:
2293 USETDW(hdr32->dwNdpIndex, poffs)(*(u_int32_t *)(hdr32->dwNdpIndex) = (poffs));
2294 ptr32 = (struct ncm_pointer32 *)(sc->sc_tx_buf + poffs);
2295 plen = sizeof(*ptr32) + ndgram * sizeof(*dgram32);
2296 USETDW(ptr32->dwSignature, MBIM_NCM_NTH32_SIG(umb_session_id))(*(u_int32_t *)(ptr32->dwSignature) = (((((umb_session_id)
& 0xff) << 24) | 0x00737069)))
;
2297 USETW(ptr32->wLength, plen)(*(u_int16_t *)(ptr32->wLength) = (plen));
2298 USETW(ptr32->wReserved6, 0)(*(u_int16_t *)(ptr32->wReserved6) = (0));
2299 USETDW(ptr32->dwNextNdpIndex, 0)(*(u_int32_t *)(ptr32->dwNextNdpIndex) = (0));
2300 USETDW(ptr32->dwReserved12, 0)(*(u_int32_t *)(ptr32->dwReserved12) = (0));
2301 dgram32 = ptr32->dgram;
2302 break;
2303 }
2304
2305 if (!(sc->sc_flags & UMBFLG_NDP_AT_END0x0004))
32
Taking true branch
2306 dgoffs = offs + plen;
2307
2308 /* Encap mbufs to NCM dgrams */
2309 sc->sc_tx_seq++;
2310 while ((m = ml_dequeue(&sc->sc_tx_ml)) != NULL((void *)0)) {
33
Assuming the condition is false
34
Loop condition is false. Execution continues on line 2330
2311 dgoffs += umb_padding(sc->sc_tx_buf, sc->sc_tx_bufsz, dgoffs,
2312 sc->sc_ndp_div, sc->sc_ndp_remainder);
2313 switch (sc->sc_ncm_format) {
2314 case NCM_FORMAT_NTB160x00:
2315 USETW(dgram16->wDatagramIndex, dgoffs)(*(u_int16_t *)(dgram16->wDatagramIndex) = (dgoffs));
2316 USETW(dgram16->wDatagramLen, m->m_pkthdr.len)(*(u_int16_t *)(dgram16->wDatagramLen) = (m->M_dat.MH.MH_pkthdr
.len))
;
2317 dgram16++;
2318 break;
2319 case NCM_FORMAT_NTB320x01:
2320 USETDW(dgram32->dwDatagramIndex, dgoffs)(*(u_int32_t *)(dgram32->dwDatagramIndex) = (dgoffs));
2321 USETDW(dgram32->dwDatagramLen, m->m_pkthdr.len)(*(u_int32_t *)(dgram32->dwDatagramLen) = (m->M_dat.MH.
MH_pkthdr.len))
;
2322 dgram32++;
2323 break;
2324 }
2325 m_copydata(m, 0, m->m_pkthdrM_dat.MH.MH_pkthdr.len, sc->sc_tx_buf + dgoffs);
2326 dgoffs += m->m_pkthdrM_dat.MH.MH_pkthdr.len;
2327 m_freem(m);
2328 }
2329
2330 if (sc->sc_flags & UMBFLG_NDP_AT_END0x0004)
35
Assuming the condition is false
36
Taking false branch
2331 offs = poffs + plen;
2332 else
2333 offs = dgoffs;
2334
2335 /* Terminating pointer and datagram size */
2336 switch (sc->sc_ncm_format) {
37
Control jumps to 'case 1:' at line 2343
2337 case NCM_FORMAT_NTB160x00:
2338 USETW(dgram16->wDatagramIndex, 0)(*(u_int16_t *)(dgram16->wDatagramIndex) = (0));
2339 USETW(dgram16->wDatagramLen, 0)(*(u_int16_t *)(dgram16->wDatagramLen) = (0));
2340 USETW(hdr16->wBlockLength, offs)(*(u_int16_t *)(hdr16->wBlockLength) = (offs));
2341 KASSERT(dgram16 - ptr16->dgram == ndgram)((dgram16 - ptr16->dgram == ndgram) ? (void)0 : __assert("diagnostic "
, "/usr/src/sys/dev/usb/if_umb.c", 2341, "dgram16 - ptr16->dgram == ndgram"
))
;
2342 break;
2343 case NCM_FORMAT_NTB320x01:
2344 USETDW(dgram32->dwDatagramIndex, 0)(*(u_int32_t *)(dgram32->dwDatagramIndex) = (0));
38
Dereference of null pointer
2345 USETDW(dgram32->dwDatagramLen, 0)(*(u_int32_t *)(dgram32->dwDatagramLen) = (0));
2346 USETDW(hdr32->dwBlockLength, offs)(*(u_int32_t *)(hdr32->dwBlockLength) = (offs));
2347 KASSERT(dgram32 - ptr32->dgram == ndgram)((dgram32 - ptr32->dgram == ndgram) ? (void)0 : __assert("diagnostic "
, "/usr/src/sys/dev/usb/if_umb.c", 2347, "dgram32 - ptr32->dgram == ndgram"
))
;
2348 break;
2349 }
2350
2351 DPRINTFN(3, "%s: encap %d bytes\n", DEVNAM(sc), offs)do { } while (0);
2352 DDUMPN(5, sc->sc_tx_buf, offs)do { } while (0);
2353 KASSERT(offs <= sc->sc_tx_bufsz)((offs <= sc->sc_tx_bufsz) ? (void)0 : __assert("diagnostic "
, "/usr/src/sys/dev/usb/if_umb.c", 2353, "offs <= sc->sc_tx_bufsz"
))
;
2354
2355 usbd_setup_xfer(sc->sc_tx_xfer, sc->sc_tx_pipe, sc, sc->sc_tx_buf, offs,
2356 USBD_FORCE_SHORT_XFER0x08 | USBD_NO_COPY0x01, umb_xfer_tout, umb_txeof);
2357 err = usbd_transfer(sc->sc_tx_xfer);
2358 if (err != USBD_IN_PROGRESS) {
2359 DPRINTF("%s: start tx error: %s\n", DEVNAM(sc),do { } while (0)
2360 usbd_errstr(err))do { } while (0);
2361 ml_purge(&sc->sc_tx_ml);
2362 return 0;
2363 }
2364 return 1;
2365}
2366
2367void
2368umb_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
2369{
2370 struct umb_softc *sc = priv;
2371 struct ifnet *ifp = GET_IFP(sc)(&(sc)->sc_if);
2372 int s;
2373
2374 s = splnet()splraise(0x4);
2375 ml_purge(&sc->sc_tx_ml);
2376 ifq_clr_oactive(&ifp->if_snd);
2377 ifp->if_timer = 0;
2378
2379 if (status != USBD_NORMAL_COMPLETION) {
1
Assuming 'status' is equal to USBD_NORMAL_COMPLETION
2
Taking false branch
2380 if (status != USBD_NOT_STARTED && status != USBD_CANCELLED) {
2381 ifp->if_oerrorsif_data.ifi_oerrors++;
2382 DPRINTF("%s: tx error: %s\n", DEVNAM(sc),do { } while (0)
2383 usbd_errstr(status))do { } while (0);
2384 if (status == USBD_STALLED)
2385 usbd_clear_endpoint_stall_async(sc->sc_tx_pipe);
2386 }
2387 }
2388 if (ifq_empty(&ifp->if_snd)(({ typeof((&ifp->if_snd)->ifq_len) __tmp = *(volatile
typeof((&ifp->if_snd)->ifq_len) *)&((&ifp->
if_snd)->ifq_len); membar_datadep_consumer(); __tmp; }) ==
0)
== 0)
3
Assuming the condition is false
4
Taking true branch
2389 umb_start(ifp);
5
Calling 'umb_start'
2390
2391 splx(s)spllower(s);
2392}
2393
2394void
2395umb_decap(struct umb_softc *sc, struct usbd_xfer *xfer)
2396{
2397 struct ifnet *ifp = GET_IFP(sc)(&(sc)->sc_if);
2398 int s;
2399 void *buf;
2400 uint32_t len;
2401 char *dp;
2402 struct ncm_header16 *hdr16;
2403 struct ncm_header32 *hdr32;
2404 struct ncm_pointer16 *ptr16;
2405 struct ncm_pointer16_dgram *dgram16;
2406 struct ncm_pointer32_dgram *dgram32;
2407 uint32_t hsig, psig;
2408 int blen;
2409 int ptrlen, ptroff, dgentryoff;
2410 uint32_t doff, dlen;
2411 struct mbuf_list ml = MBUF_LIST_INITIALIZER(){ ((void *)0), ((void *)0), 0 };
2412 struct mbuf *m;
2413
2414 usbd_get_xfer_status(xfer, NULL((void *)0), &buf, &len, NULL((void *)0));
2415 DPRINTFN(4, "%s: recv %d bytes\n", DEVNAM(sc), len)do { } while (0);
2416 DDUMPN(5, buf, len)do { } while (0);
2417 s = splnet()splraise(0x4);
2418 if (len < sizeof (*hdr16))
2419 goto toosmall;
2420
2421 hdr16 = (struct ncm_header16 *)buf;
2422 hsig = UGETDW(hdr16->dwSignature)(*(u_int32_t *)(hdr16->dwSignature));
2423
2424 switch (hsig) {
2425 case NCM_HDR16_SIG0x484d434e:
2426 blen = UGETW(hdr16->wBlockLength)(*(u_int16_t *)(hdr16->wBlockLength));
2427 ptroff = UGETW(hdr16->wNdpIndex)(*(u_int16_t *)(hdr16->wNdpIndex));
2428 if (UGETW(hdr16->wHeaderLength)(*(u_int16_t *)(hdr16->wHeaderLength)) != sizeof (*hdr16)) {
2429 DPRINTF("%s: bad header len %d for NTH16 (exp %zu)\n",do { } while (0)
2430 DEVNAM(sc), UGETW(hdr16->wHeaderLength),do { } while (0)
2431 sizeof (*hdr16))do { } while (0);
2432 goto fail;
2433 }
2434 break;
2435 case NCM_HDR32_SIG0x686d636e:
2436 if (len < sizeof (*hdr32))
2437 goto toosmall;
2438 hdr32 = (struct ncm_header32 *)hdr16;
2439 blen = UGETDW(hdr32->dwBlockLength)(*(u_int32_t *)(hdr32->dwBlockLength));
2440 ptroff = UGETDW(hdr32->dwNdpIndex)(*(u_int32_t *)(hdr32->dwNdpIndex));
2441 if (UGETW(hdr32->wHeaderLength)(*(u_int16_t *)(hdr32->wHeaderLength)) != sizeof (*hdr32)) {
2442 DPRINTF("%s: bad header len %d for NTH32 (exp %zu)\n",do { } while (0)
2443 DEVNAM(sc), UGETW(hdr32->wHeaderLength),do { } while (0)
2444 sizeof (*hdr32))do { } while (0);
2445 goto fail;
2446 }
2447 break;
2448 default:
2449 DPRINTF("%s: unsupported NCM header signature (0x%08x)\n",do { } while (0)
2450 DEVNAM(sc), hsig)do { } while (0);
2451 goto fail;
2452 }
2453 if (blen != 0 && len < blen) {
2454 DPRINTF("%s: bad NTB len (%d) for %d bytes of data\n",do { } while (0)
2455 DEVNAM(sc), blen, len)do { } while (0);
2456 goto fail;
2457 }
2458
2459 ptr16 = (struct ncm_pointer16 *)(buf + ptroff);
2460 psig = UGETDW(ptr16->dwSignature)(*(u_int32_t *)(ptr16->dwSignature));
2461 ptrlen = UGETW(ptr16->wLength)(*(u_int16_t *)(ptr16->wLength));
2462 if (len < ptrlen + ptroff)
2463 goto toosmall;
2464 if (!MBIM_NCM_NTH16_ISISG(psig)(((psig) & 0x00ffffff) == 0x00535049) && !MBIM_NCM_NTH32_ISISG(psig)(((psig) & 0x00ffffff) == 0x00737069)) {
2465 DPRINTF("%s: unsupported NCM pointer signature (0x%08x)\n",do { } while (0)
2466 DEVNAM(sc), psig)do { } while (0);
2467 goto fail;
2468 }
2469
2470 switch (hsig) {
2471 case NCM_HDR16_SIG0x484d434e:
2472 dgentryoff = offsetof(struct ncm_pointer16, dgram)__builtin_offsetof(struct ncm_pointer16, dgram);
2473 break;
2474 case NCM_HDR32_SIG0x686d636e:
2475 dgentryoff = offsetof(struct ncm_pointer32, dgram)__builtin_offsetof(struct ncm_pointer32, dgram);
2476 break;
2477 default:
2478 goto fail;
2479 }
2480
2481 while (dgentryoff < ptrlen) {
2482 switch (hsig) {
2483 case NCM_HDR16_SIG0x484d434e:
2484 if (ptroff + dgentryoff < sizeof (*dgram16))
2485 goto done;
2486 dgram16 = (struct ncm_pointer16_dgram *)
2487 (buf + ptroff + dgentryoff);
2488 dgentryoff += sizeof (*dgram16);
2489 dlen = UGETW(dgram16->wDatagramLen)(*(u_int16_t *)(dgram16->wDatagramLen));
2490 doff = UGETW(dgram16->wDatagramIndex)(*(u_int16_t *)(dgram16->wDatagramIndex));
2491 break;
2492 case NCM_HDR32_SIG0x686d636e:
2493 if (ptroff + dgentryoff < sizeof (*dgram32))
2494 goto done;
2495 dgram32 = (struct ncm_pointer32_dgram *)
2496 (buf + ptroff + dgentryoff);
2497 dgentryoff += sizeof (*dgram32);
2498 dlen = UGETDW(dgram32->dwDatagramLen)(*(u_int32_t *)(dgram32->dwDatagramLen));
2499 doff = UGETDW(dgram32->dwDatagramIndex)(*(u_int32_t *)(dgram32->dwDatagramIndex));
2500 break;
2501 default:
2502 ifp->if_ierrorsif_data.ifi_ierrors++;
2503 goto done;
2504 }
2505
2506 /* Terminating zero entry */
2507 if (dlen == 0 || doff == 0)
2508 break;
2509 if (len < dlen + doff) {
2510 /* Skip giant datagram but continue processing */
2511 DPRINTF("%s: datagram too large (%d @ off %d)\n",do { } while (0)
2512 DEVNAM(sc), dlen, doff)do { } while (0);
2513 continue;
2514 }
2515
2516 dp = buf + doff;
2517 DPRINTFN(3, "%s: decap %d bytes\n", DEVNAM(sc), dlen)do { } while (0);
2518 m = m_devget(dp, dlen, sizeof(uint32_t));
2519 if (m == NULL((void *)0)) {
2520 ifp->if_iqdropsif_data.ifi_iqdrops++;
2521 continue;
2522 }
2523 switch (*dp & 0xf0) {
2524 case 4 << 4:
2525 m->m_pkthdrM_dat.MH.MH_pkthdr.ph_family = AF_INET2;
2526 break;
2527 case 6 << 4:
2528 m->m_pkthdrM_dat.MH.MH_pkthdr.ph_family = AF_INET624;
2529 break;
2530 }
2531 ml_enqueue(&ml, m);
2532 }
2533done:
2534 if_input(ifp, &ml);
2535 splx(s)spllower(s);
2536 return;
2537toosmall:
2538 DPRINTF("%s: packet too small (%d)\n", DEVNAM(sc), len)do { } while (0);
2539fail:
2540 ifp->if_ierrorsif_data.ifi_ierrors++;
2541 splx(s)spllower(s);
2542}
2543
2544usbd_status
2545umb_send_encap_command(struct umb_softc *sc, void *data, int len)
2546{
2547 struct usbd_xfer *xfer;
2548 usb_device_request_t req;
2549 char *buf;
2550
2551 if (len > sc->sc_ctrl_len)
2552 return USBD_INVAL;
2553
2554 if ((xfer = usbd_alloc_xfer(sc->sc_udev)) == NULL((void *)0))
2555 return USBD_NOMEM;
2556 if ((buf = usbd_alloc_buffer(xfer, len)) == NULL((void *)0)) {
2557 usbd_free_xfer(xfer);
2558 return USBD_NOMEM;
2559 }
2560 memcpy(buf, data, len)__builtin_memcpy((buf), (data), (len));
2561
2562 /* XXX FIXME: if (total len > sc->sc_ctrl_len) => must fragment */
2563 req.bmRequestType = UT_WRITE_CLASS_INTERFACE(0x00 | 0x20 | 0x01);
2564 req.bRequest = UCDC_SEND_ENCAPSULATED_COMMAND0x00;
2565 USETW(req.wValue, 0)(*(u_int16_t *)(req.wValue) = (0));
2566 USETW(req.wIndex, sc->sc_ctrl_ifaceno)(*(u_int16_t *)(req.wIndex) = (sc->sc_ctrl_ifaceno));
2567 USETW(req.wLength, len)(*(u_int16_t *)(req.wLength) = (len));
2568 DELAY(umb_delay)(*delay_func)(umb_delay);
2569 return usbd_request_async(xfer, &req, NULL((void *)0), NULL((void *)0));
2570}
2571
2572int
2573umb_get_encap_response(struct umb_softc *sc, void *buf, int *len)
2574{
2575 usb_device_request_t req;
2576 usbd_status err;
2577
2578 req.bmRequestType = UT_READ_CLASS_INTERFACE(0x80 | 0x20 | 0x01);
2579 req.bRequest = UCDC_GET_ENCAPSULATED_RESPONSE0x01;
2580 USETW(req.wValue, 0)(*(u_int16_t *)(req.wValue) = (0));
2581 USETW(req.wIndex, sc->sc_ctrl_ifaceno)(*(u_int16_t *)(req.wIndex) = (sc->sc_ctrl_ifaceno));
2582 USETW(req.wLength, *len)(*(u_int16_t *)(req.wLength) = (*len));
2583 /* XXX FIXME: re-assemble fragments */
2584
2585 DELAY(umb_delay)(*delay_func)(umb_delay);
2586 err = usbd_do_request_flags(sc->sc_udev, &req, buf, USBD_SHORT_XFER_OK0x04,
2587 len, umb_xfer_tout);
2588 if (err == USBD_NORMAL_COMPLETION)
2589 return 1;
2590 DPRINTF("%s: ctrl recv: %s\n", DEVNAM(sc), usbd_errstr(err))do { } while (0);
2591 return 0;
2592}
2593
2594void
2595umb_ctrl_msg(struct umb_softc *sc, uint32_t req, void *data, int len)
2596{
2597 struct ifnet *ifp = GET_IFP(sc)(&(sc)->sc_if);
2598 uint32_t tid;
2599 struct mbim_msghdr *hdr = data;
2600 usbd_status err;
2601 int s;
2602
2603 assertwaitok();
2604 if (usbd_is_dying(sc->sc_udev))
2605 return;
2606 if (len < sizeof (*hdr))
2607 return;
2608 tid = ++sc->sc_tid;
2609
2610 hdr->type = htole32(req)((__uint32_t)(req));
2611 hdr->len = htole32(len)((__uint32_t)(len));
2612 hdr->tid = htole32(tid)((__uint32_t)(tid));
2613
2614#ifdef UMB_DEBUG
2615 if (umb_debug) {
2616 const char *op, *str;
2617 if (req == MBIM_COMMAND_MSG3U) {
2618 struct mbim_h2f_cmd *c = data;
2619 if (letoh32(c->op)((__uint32_t)(c->op)) == MBIM_CMDOP_SET1)
2620 op = "set";
2621 else
2622 op = "qry";
2623 str = umb_cid2str(letoh32(c->cid))umb_val2descr(umb_cids, (((__uint32_t)(c->cid))));
2624 } else {
2625 op = "snd";
2626 str = umb_request2str(req)umb_val2descr(umb_messages, (req));
2627 }
2628 DPRINTF("%s: -> %s %s (tid %u)\n", DEVNAM(sc), op, str, tid)do { } while (0);
2629 }
2630#endif
2631 s = splusb()splraise(0x2);
2632 err = umb_send_encap_command(sc, data, len);
2633 splx(s)spllower(s);
2634 if (err != USBD_NORMAL_COMPLETION) {
2635 if (ifp->if_flags & IFF_DEBUG0x4)
2636 log(LOG_ERR3, "%s: send %s msg (tid %u) failed: %s\n",
2637 DEVNAM(sc)(((struct umb_softc *)(sc))->sc_dev.dv_xname), umb_request2str(req)umb_val2descr(umb_messages, (req)), tid,
2638 usbd_errstr(err));
2639
2640 /* will affect other transactions, too */
2641 usbd_abort_pipe(sc->sc_udev->default_pipe);
2642 } else {
2643 DPRINTFN(2, "%s: sent %s (tid %u)\n", DEVNAM(sc),do { } while (0)
2644 umb_request2str(req), tid)do { } while (0);
2645 DDUMPN(3, data, len)do { } while (0);
2646 }
2647 return;
2648}
2649
2650void
2651umb_open(struct umb_softc *sc)
2652{
2653 struct mbim_h2f_openmsg msg;
2654
2655 memset(&msg, 0, sizeof (msg))__builtin_memset((&msg), (0), (sizeof (msg)));
2656 msg.maxlen = htole32(sc->sc_ctrl_len)((__uint32_t)(sc->sc_ctrl_len));
2657 umb_ctrl_msg(sc, MBIM_OPEN_MSG1U, &msg, sizeof (msg));
2658 return;
2659}
2660
2661void
2662umb_close(struct umb_softc *sc)
2663{
2664 struct mbim_h2f_closemsg msg;
2665
2666 memset(&msg, 0, sizeof (msg))__builtin_memset((&msg), (0), (sizeof (msg)));
2667 umb_ctrl_msg(sc, MBIM_CLOSE_MSG2U, &msg, sizeof (msg));
2668}
2669
2670int
2671umb_setpin(struct umb_softc *sc, int op, int is_puk, void *pin, int pinlen,
2672 void *newpin, int newpinlen)
2673{
2674 struct mbim_cid_pin cp;
2675 int off;
2676
2677 if (pinlen == 0)
2678 return 0;
2679 if (pinlen < 0 || pinlen > MBIM_PIN_MAXLEN32 ||
2680 newpinlen < 0 || newpinlen > MBIM_PIN_MAXLEN32 ||
2681 op < 0 || op > MBIM_PIN_OP_CHANGE3 ||
2682 (is_puk && op != MBIM_PIN_OP_ENTER0))
2683 return EINVAL22;
2684
2685 memset(&cp, 0, sizeof (cp))__builtin_memset((&cp), (0), (sizeof (cp)));
2686 cp.type = htole32(is_puk ? MBIM_PIN_TYPE_PUK1 : MBIM_PIN_TYPE_PIN1)((__uint32_t)(is_puk ? 11 : 2));
2687
2688 off = offsetof(struct mbim_cid_pin, data)__builtin_offsetof(struct mbim_cid_pin, data);
2689 if (!umb_addstr(&cp, sizeof (cp), &off, pin, pinlen,
2690 &cp.pin_offs, &cp.pin_size))
2691 return EINVAL22;
2692
2693 cp.op = htole32(op)((__uint32_t)(op));
2694 if (newpinlen) {
2695 if (!umb_addstr(&cp, sizeof (cp), &off, newpin, newpinlen,
2696 &cp.newpin_offs, &cp.newpin_size))
2697 return EINVAL22;
2698 } else {
2699 if ((op == MBIM_PIN_OP_CHANGE3) || is_puk)
2700 return EINVAL22;
2701 if (!umb_addstr(&cp, sizeof (cp), &off, NULL((void *)0), 0,
2702 &cp.newpin_offs, &cp.newpin_size))
2703 return EINVAL22;
2704 }
2705 umb_cmd(sc, MBIM_CID_PIN4, MBIM_CMDOP_SET1, &cp, off);
2706 return 0;
2707}
2708
2709void
2710umb_setdataclass(struct umb_softc *sc)
2711{
2712 struct mbim_cid_registration_state rs;
2713 uint32_t classes;
2714
2715 if (sc->sc_info.supportedclasses == MBIM_DATACLASS_NONE0x00000000)
2716 return;
2717
2718 memset(&rs, 0, sizeof (rs))__builtin_memset((&rs), (0), (sizeof (rs)));
2719 rs.regaction = htole32(MBIM_REGACTION_AUTOMATIC)((__uint32_t)(0));
2720 classes = sc->sc_info.supportedclasses;
2721 if (sc->sc_info.preferredclasses != MBIM_DATACLASS_NONE0x00000000)
2722 classes &= sc->sc_info.preferredclasses;
2723 rs.data_class = htole32(classes)((__uint32_t)(classes));
2724 umb_cmd(sc, MBIM_CID_REGISTER_STATE9, MBIM_CMDOP_SET1, &rs, sizeof (rs));
2725}
2726
2727void
2728umb_radio(struct umb_softc *sc, int on)
2729{
2730 struct mbim_cid_radio_state s;
2731
2732 DPRINTF("%s: set radio %s\n", DEVNAM(sc), on ? "on" : "off")do { } while (0);
2733 memset(&s, 0, sizeof (s))__builtin_memset((&s), (0), (sizeof (s)));
2734 s.state = htole32(on ? MBIM_RADIO_STATE_ON : MBIM_RADIO_STATE_OFF)((__uint32_t)(on ? 1 : 0));
2735 umb_cmd(sc, MBIM_CID_RADIO_STATE3, MBIM_CMDOP_SET1, &s, sizeof (s));
2736}
2737
2738void
2739umb_allocate_cid(struct umb_softc *sc)
2740{
2741 umb_cmd1(sc, MBIM_CID_DEVICE_CAPS1, MBIM_CMDOP_SET1,
2742 umb_qmi_alloc_cid, sizeof (umb_qmi_alloc_cid), umb_uuid_qmi_mbim);
2743}
2744
2745void
2746umb_send_fcc_auth(struct umb_softc *sc)
2747{
2748 uint8_t fccauth[sizeof (umb_qmi_fcc_auth)];
2749
2750 if (sc->sc_cid == -1) {
2751 DPRINTF("%s: missing CID, cannot send FCC auth\n", DEVNAM(sc))do { } while (0);
2752 umb_allocate_cid(sc);
2753 return;
2754 }
2755 memcpy(fccauth, umb_qmi_fcc_auth, sizeof (fccauth))__builtin_memcpy((fccauth), (umb_qmi_fcc_auth), (sizeof (fccauth
)))
;
2756 fccauth[UMB_QMI_CID_OFFS5] = sc->sc_cid;
2757 umb_cmd1(sc, MBIM_CID_DEVICE_CAPS1, MBIM_CMDOP_SET1,
2758 fccauth, sizeof (fccauth), umb_uuid_qmi_mbim);
2759}
2760
2761void
2762umb_packet_service(struct umb_softc *sc, int attach)
2763{
2764 struct mbim_cid_packet_service s;
2765
2766 DPRINTF("%s: %s packet service\n", DEVNAM(sc),do { } while (0)
2767 attach ? "attach" : "detach")do { } while (0);
2768 memset(&s, 0, sizeof (s))__builtin_memset((&s), (0), (sizeof (s)));
2769 s.action = htole32(attach ?((__uint32_t)(attach ? 0 : 1))
2770 MBIM_PKTSERVICE_ACTION_ATTACH : MBIM_PKTSERVICE_ACTION_DETACH)((__uint32_t)(attach ? 0 : 1));
2771 umb_cmd(sc, MBIM_CID_PACKET_SERVICE10, MBIM_CMDOP_SET1, &s, sizeof (s));
2772}
2773
2774void
2775umb_connect(struct umb_softc *sc)
2776{
2777 struct ifnet *ifp = GET_IFP(sc)(&(sc)->sc_if);
2778
2779 if (sc->sc_info.regstate == MBIM_REGSTATE_ROAMING4 && !sc->sc_roamingsc_info.enable_roaming) {
2780 log(LOG_INFO6, "%s: connection disabled in roaming network\n",
2781 DEVNAM(sc)(((struct umb_softc *)(sc))->sc_dev.dv_xname));
2782 return;
2783 }
2784 if (ifp->if_flags & IFF_DEBUG0x4)
2785 log(LOG_DEBUG7, "%s: connecting ...\n", DEVNAM(sc)(((struct umb_softc *)(sc))->sc_dev.dv_xname));
2786 umb_send_connect(sc, MBIM_CONNECT_ACTIVATE1);
2787}
2788
2789void
2790umb_disconnect(struct umb_softc *sc)
2791{
2792 struct ifnet *ifp = GET_IFP(sc)(&(sc)->sc_if);
2793
2794 if (ifp->if_flags & IFF_DEBUG0x4)
2795 log(LOG_DEBUG7, "%s: disconnecting ...\n", DEVNAM(sc)(((struct umb_softc *)(sc))->sc_dev.dv_xname));
2796 umb_send_connect(sc, MBIM_CONNECT_DEACTIVATE0);
2797}
2798
2799void
2800umb_send_connect(struct umb_softc *sc, int command)
2801{
2802 struct mbim_cid_connect *c;
2803 int off;
2804
2805 /* Too large or the stack */
2806 c = malloc(sizeof (*c), M_USBDEV102, M_WAIT0x0001|M_ZERO0x0008);
2807 c->sessionid = htole32(umb_session_id)((__uint32_t)(umb_session_id));
2808 c->command = htole32(command)((__uint32_t)(command));
2809 off = offsetof(struct mbim_cid_connect, data)__builtin_offsetof(struct mbim_cid_connect, data);
2810 if (!umb_addstr(c, sizeof (*c), &off, sc->sc_info.apn,
2811 sc->sc_info.apnlen, &c->access_offs, &c->access_size))
2812 goto done;
2813 /* XXX FIXME: support user name and passphrase */
2814 c->user_offs = htole32(0)((__uint32_t)(0));
2815 c->user_size = htole32(0)((__uint32_t)(0));
2816 c->passwd_offs = htole32(0)((__uint32_t)(0));
2817 c->passwd_size = htole32(0)((__uint32_t)(0));
2818 c->authprot = htole32(MBIM_AUTHPROT_NONE)((__uint32_t)(0));
2819 c->compression = htole32(MBIM_COMPRESSION_NONE)((__uint32_t)(0));
2820 c->iptype = htole32(MBIM_CONTEXT_IPTYPE_IPV4)((__uint32_t)(1));
2821#ifdef INET61
2822 /* XXX FIXME: support IPv6-only mode, too */
2823 if ((sc->sc_flags & UMBFLG_NO_INET60x0002) == 0 &&
2824 in6ifa_ifpforlinklocal(GET_IFP(sc)(&(sc)->sc_if), 0) != NULL((void *)0))
2825 c->iptype = htole32(MBIM_CONTEXT_IPTYPE_IPV4V6)((__uint32_t)(3));
2826#endif
2827 memcpy(c->context, umb_uuid_context_internet, sizeof (c->context))__builtin_memcpy((c->context), (umb_uuid_context_internet)
, (sizeof (c->context)))
;
2828 umb_cmd(sc, MBIM_CID_CONNECT12, MBIM_CMDOP_SET1, c, off);
2829done:
2830 free(c, M_USBDEV102, sizeof (*c));
2831 return;
2832}
2833
2834void
2835umb_qry_ipconfig(struct umb_softc *sc)
2836{
2837 struct mbim_cid_ip_configuration_info ipc;
2838
2839 memset(&ipc, 0, sizeof (ipc))__builtin_memset((&ipc), (0), (sizeof (ipc)));
2840 ipc.sessionid = htole32(umb_session_id)((__uint32_t)(umb_session_id));
2841 umb_cmd(sc, MBIM_CID_IP_CONFIGURATION15, MBIM_CMDOP_QRY0,
2842 &ipc, sizeof (ipc));
2843}
2844
2845void
2846umb_cmd(struct umb_softc *sc, int cid, int op, void *data, int len)
2847{
2848 umb_cmd1(sc, cid, op, data, len, umb_uuid_basic_connect);
2849}
2850
2851void
2852umb_cmd1(struct umb_softc *sc, int cid, int op, void *data, int len,
2853 uint8_t *uuid)
2854{
2855 struct mbim_h2f_cmd *cmd;
2856 int totlen;
2857
2858 /* XXX FIXME support sending fragments */
2859 if (sizeof (*cmd) + len > sc->sc_ctrl_len) {
2860 DPRINTF("%s: set %s msg too long: cannot send\n",do { } while (0)
2861 DEVNAM(sc), umb_cid2str(cid))do { } while (0);
2862 return;
2863 }
2864 cmd = sc->sc_ctrl_msg;
2865 memset(cmd, 0, sizeof (*cmd))__builtin_memset((cmd), (0), (sizeof (*cmd)));
2866 cmd->frag.nfrag = htole32(1)((__uint32_t)(1));
2867 memcpy(cmd->devid, uuid, sizeof (cmd->devid))__builtin_memcpy((cmd->devid), (uuid), (sizeof (cmd->devid
)))
;
2868 cmd->cid = htole32(cid)((__uint32_t)(cid));
2869 cmd->op = htole32(op)((__uint32_t)(op));
2870 cmd->infolen = htole32(len)((__uint32_t)(len));
2871 totlen = sizeof (*cmd);
2872 if (len > 0) {
2873 memcpy(cmd + 1, data, len)__builtin_memcpy((cmd + 1), (data), (len));
2874 totlen += len;
2875 }
2876 umb_ctrl_msg(sc, MBIM_COMMAND_MSG3U, cmd, totlen);
2877}
2878
2879void
2880umb_command_done(struct umb_softc *sc, void *data, int len)
2881{
2882 struct mbim_f2h_cmddone *cmd = data;
2883 struct ifnet *ifp = GET_IFP(sc)(&(sc)->sc_if);
2884 uint32_t status;
2885 uint32_t cid;
2886 uint32_t infolen;
2887 int qmimsg = 0;
2888
2889 if (len < sizeof (*cmd)) {
2890 DPRINTF("%s: discard short %s message\n", DEVNAM(sc),do { } while (0)
2891 umb_request2str(letoh32(cmd->hdr.type)))do { } while (0);
2892 return;
2893 }
2894 cid = letoh32(cmd->cid)((__uint32_t)(cmd->cid));
2895 if (memcmp(cmd->devid, umb_uuid_basic_connect, sizeof (cmd->devid))__builtin_memcmp((cmd->devid), (umb_uuid_basic_connect), (
sizeof (cmd->devid)))
) {
2896 if (memcmp(cmd->devid, umb_uuid_qmi_mbim,__builtin_memcmp((cmd->devid), (umb_uuid_qmi_mbim), (sizeof
(cmd->devid)))
2897 sizeof (cmd->devid))__builtin_memcmp((cmd->devid), (umb_uuid_qmi_mbim), (sizeof
(cmd->devid)))
) {
2898 DPRINTF("%s: discard %s message for other UUID '%s'\n",do { } while (0)
2899 DEVNAM(sc), umb_request2str(letoh32(cmd->hdr.type)),do { } while (0)
2900 umb_uuid2str(cmd->devid))do { } while (0);
2901 return;
2902 } else
2903 qmimsg = 1;
2904 }
2905
2906 status = letoh32(cmd->status)((__uint32_t)(cmd->status));
2907 switch (status) {
2908 case MBIM_STATUS_SUCCESS0:
2909 break;
2910#ifdef INET61
2911 case MBIM_STATUS_NO_DEVICE_SUPPORT9:
2912 if ((cid == MBIM_CID_CONNECT12) &&
2913 (sc->sc_flags & UMBFLG_NO_INET60x0002) == 0) {
2914 sc->sc_flags |= UMBFLG_NO_INET60x0002;
2915 if (ifp->if_flags & IFF_DEBUG0x4)
2916 log(LOG_ERR3,
2917 "%s: device does not support IPv6\n",
2918 DEVNAM(sc)(((struct umb_softc *)(sc))->sc_dev.dv_xname));
2919 }
2920 /* Re-trigger the connect, this time IPv4 only */
2921 usb_add_task(sc->sc_udev, &sc->sc_umb_task);
2922 return;
2923#endif
2924 case MBIM_STATUS_NOT_INITIALIZED14:
2925 if (ifp->if_flags & IFF_DEBUG0x4)
2926 log(LOG_ERR3, "%s: SIM not initialized (PIN missing)\n",
2927 DEVNAM(sc)(((struct umb_softc *)(sc))->sc_dev.dv_xname));
2928 return;
2929 case MBIM_STATUS_PIN_REQUIRED5:
2930 sc->sc_info.pin_state = UMB_PIN_REQUIRED0;
2931 /*FALLTHROUGH*/
2932 default:
2933 if (ifp->if_flags & IFF_DEBUG0x4)
2934 log(LOG_ERR3, "%s: set/qry %s failed: %s\n", DEVNAM(sc)(((struct umb_softc *)(sc))->sc_dev.dv_xname),
2935 umb_cid2str(cid)umb_val2descr(umb_cids, (cid)), umb_status2str(status)umb_val2descr(umb_status, (status)));
2936 return;
2937 }
2938
2939 infolen = letoh32(cmd->infolen)((__uint32_t)(cmd->infolen));
2940 if (len < sizeof (*cmd) + infolen) {
2941 DPRINTF("%s: discard truncated %s message (want %d, got %d)\n",do { } while (0)
2942 DEVNAM(sc), umb_cid2str(cid),do { } while (0)
2943 (int)sizeof (*cmd) + infolen, len)do { } while (0);
2944 return;
2945 }
2946 if (qmimsg) {
2947 if (sc->sc_flags & UMBFLG_FCC_AUTH_REQUIRED0x0001)
2948 umb_decode_qmi(sc, cmd->info, infolen);
2949 } else {
2950 DPRINTFN(2, "%s: set/qry %s done\n", DEVNAM(sc),do { } while (0)
2951 umb_cid2str(cid))do { } while (0);
2952 umb_decode_cid(sc, cid, cmd->info, infolen);
2953 }
2954}
2955
2956void
2957umb_decode_cid(struct umb_softc *sc, uint32_t cid, void *data, int len)
2958{
2959 int ok = 1;
2960
2961 switch (cid) {
2962 case MBIM_CID_DEVICE_CAPS1:
2963 ok = umb_decode_devices_caps(sc, data, len);
2964 break;
2965 case MBIM_CID_SUBSCRIBER_READY_STATUS2:
2966 ok = umb_decode_subscriber_status(sc, data, len);
2967 break;
2968 case MBIM_CID_RADIO_STATE3:
2969 ok = umb_decode_radio_state(sc, data, len);
2970 break;
2971 case MBIM_CID_PIN4:
2972 ok = umb_decode_pin(sc, data, len);
2973 break;
2974 case MBIM_CID_REGISTER_STATE9:
2975 ok = umb_decode_register_state(sc, data, len);
2976 break;
2977 case MBIM_CID_PACKET_SERVICE10:
2978 ok = umb_decode_packet_service(sc, data, len);
2979 break;
2980 case MBIM_CID_SIGNAL_STATE11:
2981 ok = umb_decode_signal_state(sc, data, len);
2982 break;
2983 case MBIM_CID_CONNECT12:
2984 ok = umb_decode_connect_info(sc, data, len);
2985 break;
2986 case MBIM_CID_IP_CONFIGURATION15:
2987 ok = umb_decode_ip_configuration(sc, data, len);
2988 break;
2989 default:
2990 /*
2991 * Note: the above list is incomplete and only contains
2992 * mandatory CIDs from the BASIC_CONNECT set.
2993 * So alternate values are not unusual.
2994 */
2995 DPRINTFN(4, "%s: ignore %s\n", DEVNAM(sc), umb_cid2str(cid))do { } while (0);
2996 break;
2997 }
2998 if (!ok)
2999 DPRINTF("%s: discard %s with bad info length %d\n",do { } while (0)
3000 DEVNAM(sc), umb_cid2str(cid), len)do { } while (0);
3001 return;
3002}
3003
3004void
3005umb_decode_qmi(struct umb_softc *sc, uint8_t *data, int len)
3006{
3007 uint8_t srv;
3008 uint16_t msg, tlvlen;
3009 uint32_t val;
3010
3011#define UMB_QMI_QMUXLEN6 6
3012 if (len < UMB_QMI_QMUXLEN6)
3013 goto tooshort;
3014
3015 srv = data[4];
3016 data += UMB_QMI_QMUXLEN6;
3017 len -= UMB_QMI_QMUXLEN6;
3018
3019#define UMB_GET16(p)((uint16_t)*p | (uint16_t)*(p + 1) << 8) ((uint16_t)*p | (uint16_t)*(p + 1) << 8)
3020#define UMB_GET32(p)((uint32_t)*p | (uint32_t)*(p + 1) << 8 | (uint32_t)*(p
+ 2) << 16 |(uint32_t)*(p + 3) << 24)
((uint32_t)*p | (uint32_t)*(p + 1) << 8 | \
3021 (uint32_t)*(p + 2) << 16 |(uint32_t)*(p + 3) << 24)
3022 switch (srv) {
3023 case 0: /* ctl */
3024#define UMB_QMI_CTLLEN6 6
3025 if (len < UMB_QMI_CTLLEN6)
3026 goto tooshort;
3027 msg = UMB_GET16(&data[2])((uint16_t)*&data[2] | (uint16_t)*(&data[2] + 1) <<
8)
;
3028 tlvlen = UMB_GET16(&data[4])((uint16_t)*&data[4] | (uint16_t)*(&data[4] + 1) <<
8)
;
3029 data += UMB_QMI_CTLLEN6;
3030 len -= UMB_QMI_CTLLEN6;
3031 break;
3032 case 2: /* dms */
3033#define UMB_QMI_DMSLEN7 7
3034 if (len < UMB_QMI_DMSLEN7)
3035 goto tooshort;
3036 msg = UMB_GET16(&data[3])((uint16_t)*&data[3] | (uint16_t)*(&data[3] + 1) <<
8)
;
3037 tlvlen = UMB_GET16(&data[5])((uint16_t)*&data[5] | (uint16_t)*(&data[5] + 1) <<
8)
;
3038 data += UMB_QMI_DMSLEN7;
3039 len -= UMB_QMI_DMSLEN7;
3040 break;
3041 default:
3042 DPRINTF("%s: discard QMI message for unknown service type %d\n",do { } while (0)
3043 DEVNAM(sc), srv)do { } while (0);
3044 return;
3045 }
3046
3047 if (len < tlvlen)
3048 goto tooshort;
3049
3050#define UMB_QMI_TLVLEN3 3
3051 while (len > 0) {
3052 if (len < UMB_QMI_TLVLEN3)
3053 goto tooshort;
3054 tlvlen = UMB_GET16(&data[1])((uint16_t)*&data[1] | (uint16_t)*(&data[1] + 1) <<
8)
;
3055 if (len < UMB_QMI_TLVLEN3 + tlvlen)
3056 goto tooshort;
3057 switch (data[0]) {
3058 case 1: /* allocation info */
3059 if (msg == 0x0022) { /* Allocate CID */
3060 if (tlvlen != 2 || data[3] != 2) /* dms */
3061 break;
3062 sc->sc_cid = data[4];
3063 DPRINTF("%s: QMI CID %d allocated\n",do { } while (0)
3064 DEVNAM(sc), sc->sc_cid)do { } while (0);
3065 umb_newstate(sc, UMB_S_CID, UMB_NS_DONT_DROP0x0001);
3066 }
3067 break;
3068 case 2: /* response */
3069 if (tlvlen != sizeof (val))
3070 break;
3071 val = UMB_GET32(&data[3])((uint32_t)*&data[3] | (uint32_t)*(&data[3] + 1) <<
8 | (uint32_t)*(&data[3] + 2) << 16 |(uint32_t)*(&
data[3] + 3) << 24)
;
3072 switch (msg) {
3073 case 0x0022: /* Allocate CID */
3074 if (val != 0) {
3075 log(LOG_ERR3, "%s: allocation of QMI CID"
3076 " failed, error 0x%x\n", DEVNAM(sc)(((struct umb_softc *)(sc))->sc_dev.dv_xname),
3077 val);
3078 /* XXX how to proceed? */
3079 return;
3080 }
3081 break;
3082 case 0x555f: /* Send FCC Authentication */
3083 if (val == 0)
3084 DPRINTF("%s: send FCC "do { } while (0)
3085 "Authentication succeeded\n",do { } while (0)
3086 DEVNAM(sc))do { } while (0);
3087 else if (val == 0x001a0001)
3088 DPRINTF("%s: FCC Authentication "do { } while (0)
3089 "not required\n", DEVNAM(sc))do { } while (0);
3090 else
3091 log(LOG_INFO6, "%s: send FCC "
3092 "Authentication failed, "
3093 "error 0x%x\n", DEVNAM(sc)(((struct umb_softc *)(sc))->sc_dev.dv_xname), val);
3094
3095 /* FCC Auth is needed only once after power-on*/
3096 sc->sc_flags &= ~UMBFLG_FCC_AUTH_REQUIRED0x0001;
3097
3098 /* Try to proceed anyway */
3099 DPRINTF("%s: init: turning radio on ...\n",do { } while (0)
3100 DEVNAM(sc))do { } while (0);
3101 umb_radio(sc, 1);
3102 break;
3103 default:
3104 break;
3105 }
3106 break;
3107 default:
3108 break;
3109 }
3110 data += UMB_QMI_TLVLEN3 + tlvlen;
3111 len -= UMB_QMI_TLVLEN3 + tlvlen;
3112 }
3113 return;
3114
3115tooshort:
3116 DPRINTF("%s: discard short QMI message\n", DEVNAM(sc))do { } while (0);
3117 return;
3118}
3119
3120void
3121umb_intr(struct usbd_xfer *xfer, void *priv, usbd_status status)
3122{
3123 struct umb_softc *sc = priv;
3124 struct ifnet *ifp = GET_IFP(sc)(&(sc)->sc_if);
3125 int total_len;
3126
3127 if (status != USBD_NORMAL_COMPLETION) {
3128 DPRINTF("%s: notification error: %s\n", DEVNAM(sc),do { } while (0)
3129 usbd_errstr(status))do { } while (0);
3130 if (status == USBD_STALLED)
3131 usbd_clear_endpoint_stall_async(sc->sc_ctrl_pipe);
3132 return;
3133 }
3134 usbd_get_xfer_status(xfer, NULL((void *)0), NULL((void *)0), &total_len, NULL((void *)0));
3135 if (total_len < UCDC_NOTIFICATION_LENGTH8) {
3136 DPRINTF("%s: short notification (%d<%d)\n", DEVNAM(sc),do { } while (0)
3137 total_len, UCDC_NOTIFICATION_LENGTH)do { } while (0);
3138 return;
3139 }
3140 if (sc->sc_intr_msg.bmRequestType != UCDC_NOTIFICATION0xa1) {
3141 DPRINTF("%s: unexpected notification (type=0x%02x)\n",do { } while (0)
3142 DEVNAM(sc), sc->sc_intr_msg.bmRequestType)do { } while (0);
3143 return;
3144 }
3145
3146 switch (sc->sc_intr_msg.bNotification) {
3147 case UCDC_N_NETWORK_CONNECTION0x00:
3148 if (ifp->if_flags & IFF_DEBUG0x4)
3149 log(LOG_DEBUG7, "%s: network %sconnected\n", DEVNAM(sc)(((struct umb_softc *)(sc))->sc_dev.dv_xname),
3150 UGETW(sc->sc_intr_msg.wValue)(*(u_int16_t *)(sc->sc_intr_msg.wValue)) ? "" : "dis");
3151 break;
3152 case UCDC_N_RESPONSE_AVAILABLE0x01:
3153 DPRINTFN(2, "%s: umb_intr: response available\n", DEVNAM(sc))do { } while (0);
3154 ++sc->sc_nresp;
3155 usb_add_task(sc->sc_udev, &sc->sc_get_response_task);
3156 break;
3157 case UCDC_N_CONNECTION_SPEED_CHANGE0x2a:
3158 DPRINTFN(2, "%s: umb_intr: connection speed changed\n",do { } while (0)
3159 DEVNAM(sc))do { } while (0);
3160 break;
3161 default:
3162 DPRINTF("%s: unexpected notification (0x%02x)\n",do { } while (0)
3163 DEVNAM(sc), sc->sc_intr_msg.bNotification)do { } while (0);
3164 break;
3165 }
3166}
3167
3168/*
3169 * Diagnostic routines
3170 */
3171#ifdef UMB_DEBUG
3172char *
3173umb_uuid2str(uint8_t uuid[MBIM_UUID_LEN16])
3174{
3175 static char uuidstr[2 * MBIM_UUID_LEN16 + 5];
3176
3177#define UUID_BFMT "%02X"
3178#define UUID_SEP "-"
3179 snprintf(uuidstr, sizeof (uuidstr),
3180 UUID_BFMT UUID_BFMT UUID_BFMT UUID_BFMT UUID_SEP
3181 UUID_BFMT UUID_BFMT UUID_SEP
3182 UUID_BFMT UUID_BFMT UUID_SEP
3183 UUID_BFMT UUID_BFMT UUID_SEP
3184 UUID_BFMT UUID_BFMT UUID_BFMT UUID_BFMT UUID_BFMT UUID_BFMT,
3185 uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5],
3186 uuid[6], uuid[7], uuid[8], uuid[9], uuid[10], uuid[11],
3187 uuid[12], uuid[13], uuid[14], uuid[15]);
3188 return uuidstr;
3189}
3190
3191void
3192umb_dump(void *buf, int len)
3193{
3194 int i = 0;
3195 uint8_t *c = buf;
3196
3197 if (len == 0)
3198 return;
3199 while (i < len) {
3200 if ((i % 16) == 0) {
3201 if (i > 0)
3202 addlog("\n");
3203 log(LOG_DEBUG7, "%4d: ", i);
3204 }
3205 addlog(" %02x", *c);
3206 c++;
3207 i++;
3208 }
3209 addlog("\n");
3210}
3211#endif /* UMB_DEBUG */
3212
3213#if NKSTAT1 > 0
3214
3215void
3216umb_kstat_attach(struct umb_softc *sc)
3217{
3218 struct kstat *ks;
3219 struct umb_kstat_signal *uks;
3220
3221 rw_init(&sc->sc_kstat_lock, "umbkstat")_rw_init_flags(&sc->sc_kstat_lock, "umbkstat", 0, ((void
*)0))
;
3222
3223 ks = kstat_create(DEVNAM(sc)(((struct umb_softc *)(sc))->sc_dev.dv_xname), 0, "mbim-signal", 0, KSTAT_T_KV1, 0);
3224 if (ks == NULL((void *)0))
3225 return;
3226
3227 uks = malloc(sizeof(*uks), M_DEVBUF2, M_WAITOK0x0001|M_ZERO0x0008);
3228 kstat_kv_init(&uks->rssi, "rssi", KSTAT_KV_T_NULL);
3229 kstat_kv_init(&uks->error_rate, "error rate", KSTAT_KV_T_NULL);
3230 kstat_kv_init(&uks->reports, "reports", KSTAT_KV_T_COUNTER64);
3231
3232 kstat_set_rlock(ks, &sc->sc_kstat_lock);
3233 ks->ks_data = uks;
3234 ks->ks_datalen = sizeof(*uks);
3235 ks->ks_read = kstat_read_nop;
3236
3237 ks->ks_softc = sc;
3238 sc->sc_kstat_signal = ks;
3239 kstat_install(ks);
3240}
3241
3242void
3243umb_kstat_detach(struct umb_softc *sc)
3244{
3245 struct kstat *ks = sc->sc_kstat_signal;
3246 struct umb_kstat_signal *uks;
3247
3248 if (ks == NULL((void *)0))
3249 return;
3250
3251 kstat_remove(ks);
3252 sc->sc_kstat_signal = NULL((void *)0);
3253
3254 uks = ks->ks_data;
3255 free(uks, M_DEVBUF2, sizeof(*uks));
3256
3257 kstat_destroy(ks);
3258}
3259#endif /* NKSTAT > 0 */