1 /******************************************************************************
2 @file mbim-cm.c
3 @brief MIBIM drivers.
4
5 DESCRIPTION
6 Connectivity Management Tool for USB network adapter of Quectel wireless cellular modules.
7
8 INITIALIZATION AND SEQUENCING REQUIREMENTS
9 None.
10
11 ---------------------------------------------------------------------------
12 Copyright (c) 2016 - 2020 Quectel Wireless Solution, Co., Ltd. All Rights Reserved.
13 Quectel Wireless Solution Proprietary and Confidential.
14 ---------------------------------------------------------------------------
15 ******************************************************************************/
16 #include <unistd.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <ctype.h>
21 #include <fcntl.h>
22 #include <stddef.h>
23 #include <pthread.h>
24 #include <errno.h>
25 #include <time.h>
26 #include <signal.h>
27 #include <getopt.h>
28 #include <poll.h>
29 #include <sys/time.h>
30 #include <endian.h>
31 #include <time.h>
32 #include <sys/types.h>
33 #include <limits.h>
34 #include <inttypes.h>
35 #include "QMIThread.h"
36
37 #ifndef htole32
38 #if __BYTE_ORDER == __LITTLE_ENDIAN
39 #define htole16(x) (uint16_t)(x)
40 #define le16toh(x) (uint16_t)(x)
41 #define letoh16(x) (uint16_t)(x)
42 #define htole32(x) (uint32_t)(x)
43 #define le32toh(x) (uint32_t)(x)
44 #define letoh32(x) (uint32_t)(x)
45 #define htole64(x) (uint64_t)(x)
46 #define le64toh(x) (uint64_t)(x)
47 #define letoh64(x) (uint64_t)(x)
48 #else
__bswap16(uint16_t __x)49 static __inline uint16_t __bswap16(uint16_t __x) {
50 return (__x<<8) | (__x>>8);
51 }
52
__bswap32(uint32_t __x)53 static __inline uint32_t __bswap32(uint32_t __x) {
54 return (__x>>24) | (__x>>8&0xff00) | (__x<<8&0xff0000) | (__x<<24);
55 }
56
__bswap64(uint64_t __x)57 static __inline uint64_t __bswap64(uint64_t __x) {
58 return (__bswap32(__x)+0ULL<<32) | (__bswap32(__x>>32));
59 }
60
61 #define htole16(x) __bswap16(x)
62 #define le16toh(x) __bswap16(x)
63 #define letoh16(x) __bswap16(x)
64 #define htole32(x) __bswap32(x)
65 #define le32toh(x) __bswap32(x)
66 #define letoh32(x) __bswap32(x)
67 #define htole64(x) __bswap64(x)
68 #define le64toh(x) __bswap64(x)
69 #define letoh64(x) __bswap64(x)
70 #endif
71 #endif
72
73 #define mbim_debug dbg_time
74
75 #define UUID_BASIC_CONNECT "a289cc33-bcbb-8b4f-b6b0-133ec2aae6df"
76 //https://docs.microsoft.com/en-us/windows-hardware/drivers/network/mb-5g-data-class-support
77 #define UUID_BASIC_CONNECT_EXT "3d01dcc5-fef5-4d05-0d3a-bef7058e9aaf"
78 #define UUID_SMS "533fbeeb-14fe-4467-9f90-33a223e56c3f"
79 #define UUID_USSD "e550a0c8-5e82-479e-82f7-10abf4c3351f"
80 #define UUID_PHONEBOOK "4bf38476-1e6a-41db-b1d8-bed289c25bdb"
81 #define UUID_STK "d8f20131-fcb5-4e17-8602-d6ed3816164c"
82 #define UUID_AUTH "1d2b5ff7-0aa1-48b2-aa52-50f15767174e"
83 #define UUID_DSS "c08a26dd-7718-4382-8482-6e0d583c4d0e"
84 #define uuid_ext_qmux "d1a30bc2-f97a-6e43-bf65-c7e24fb0f0d3"
85 #define uuid_mshsd "883b7c26-985f-43fa-9804-27d7fb80959c"
86 #define uuid_qmbe "2d0c12c9-0e6a-495a-915c-8d174fe5d63c"
87 #define UUID_MSFWID "e9f7dea2-feaf-4009-93ce-90a3694103b6"
88 #define uuid_atds "5967bdcc-7fd2-49a2-9f5c-b2e70e527db3"
89 #define uuid_qdu "6427015f-579d-48f5-8c54-f43ed1e76f83"
90 #define UUID_MS_UICC_LOW_LEVEL "c2f6588e-f037-4bc9-8665-f4d44bd09367"
91 #define UUID_MS_SARControl "68223D04-9F6C-4E0F-822D-28441FB72340"
92 #define UUID_VOICEEXTENSIONS "8d8b9eba-37be-449b-8f1e-61cb034a702e"
93 #define UUID_LIBMBIM_PROXY "838cf7fb-8d0d-4d7f-871e-d71dbefbb39b"
94
95 #define UUID_MBIMContextTypeInternet "7E5E2A7E-4E6F-7272-736B-656E7E5E2A7E"
96
97 typedef unsigned char UINT8;
98 typedef unsigned short UINT16;
99 typedef unsigned int UINT32;
100 typedef unsigned long long UINT64;
101
102 #define STRINGFY(v) #v
103 /* The function name will be _ENUM_NAMEStr */
104 #define enumstrfunc(_ENUM_NAME, _ENUM_MEMS) \
105 static const char *_ENUM_NAME##Str(int _val) { \
106 struct { int val;char *name;} _enumstr[] = { _ENUM_MEMS }; \
107 int idx; for (idx = 0; idx < (int)(sizeof(_enumstr)/sizeof(_enumstr[0])); idx++) { \
108 if (_val == _enumstr[idx].val) return _enumstr[idx].name;} \
109 return STRINGFY(_ENUM_NAME##Unknow); \
110 }
111
112 #pragma pack(4)
113 typedef enum {
114 MBIM_CID_CMD_TYPE_QUERY = 0,
115 MBIM_CID_CMD_TYPE_SET = 1,
116 } MBIM_CID_CMD_TYPE_E;
117
118 //Set Query Notification
119 #define UUID_BASIC_CONNECT_CIDs \
120 MBIM_ENUM_HELPER(MBIM_CID_DEVICE_CAPS, 1) \
121 MBIM_ENUM_HELPER(MBIM_CID_SUBSCRIBER_READY_STATUS, 2) \
122 MBIM_ENUM_HELPER(MBIM_CID_RADIO_STATE, 3) \
123 MBIM_ENUM_HELPER(MBIM_CID_PIN, 4) \
124 MBIM_ENUM_HELPER(MBIM_CID_PIN_LIS, 5) \
125 MBIM_ENUM_HELPER(MBIM_CID_HOME_PROVIDER, 6) \
126 MBIM_ENUM_HELPER(MBIM_CID_PREFERRED_PROVIDERS, 7) \
127 MBIM_ENUM_HELPER(MBIM_CID_VISIBLE_PROVIDERS, 8) \
128 MBIM_ENUM_HELPER(MBIM_CID_REGISTER_STATE, 9) \
129 MBIM_ENUM_HELPER(MBIM_CID_PACKET_SERVICE, 10) \
130 MBIM_ENUM_HELPER(MBIM_CID_SIGNAL_STATE, 11) \
131 MBIM_ENUM_HELPER(MBIM_CID_CONNECT, 12) \
132 MBIM_ENUM_HELPER(MBIM_CID_PROVISIONED_CONTEXTS, 13) \
133 MBIM_ENUM_HELPER(MBIM_CID_SERVICE_ACTIVATION, 14) \
134 MBIM_ENUM_HELPER(MBIM_CID_IP_CONFIGURATION, 15) \
135 MBIM_ENUM_HELPER(MBIM_CID_DEVICE_SERVICES, 16) \
136 MBIM_ENUM_HELPER(MBIM_CID_DEVICE_SERVICE_SUBSCRIBE_LIST, 19) \
137 MBIM_ENUM_HELPER(MBIM_CID_PACKET_STATISTICS, 20) \
138 MBIM_ENUM_HELPER(MBIM_CID_NETWORK_IDLE_HINT, 21) \
139 MBIM_ENUM_HELPER(MBIM_CID_EMERGENCY_MODE, 22) \
140 MBIM_ENUM_HELPER(MBIM_CID_IP_PACKET_FILTERS, 23) \
141 MBIM_ENUM_HELPER(MBIM_CID_MULTICARRIER_PROVIDERS, 24)
142
143 #define MBIM_ENUM_HELPER(k, v) k = v,
144 typedef enum{
145 UUID_BASIC_CONNECT_CIDs
146 } UUID_BASIC_CONNECT_CID_E;
147 #undef MBIM_ENUM_HELPER
148 #define MBIM_ENUM_HELPER(k, v) {k, #k},
149 enumstrfunc(CID2, UUID_BASIC_CONNECT_CIDs);
150 #undef MBIM_ENUM_HELPER
151
152 static int mbim_ms_version = 1;
153
154 #define UUID_BASIC_CONNECT_EXT_CIDs \
155 MBIM_ENUM_HELPER(MBIM_CID_MS_PROVISIONED_CONTEXT_V2, 1) \
156 MBIM_ENUM_HELPER(MBIM_CID_MS_NETWORK_BLACKLIST, 2) \
157 MBIM_ENUM_HELPER(MBIM_CID_MS_LTE_ATTACH_CONFIG, 3) \
158 MBIM_ENUM_HELPER(MBIM_CID_MS_LTE_ATTACH_STATUS , 4) \
159 MBIM_ENUM_HELPER(MBIM_CID_MS_SYS_CAPS , 5) \
160 MBIM_ENUM_HELPER(MBIM_CID_MS_DEVICE_CAPS_V2, 6) \
161 MBIM_ENUM_HELPER(MBIM_CID_MS_DEVICE_SLOT_MAPPING, 7) \
162 MBIM_ENUM_HELPER(MBIM_CID_MS_SLOT_INFO_STATUS, 8) \
163 MBIM_ENUM_HELPER(MBIM_CID_MS_PCO, 9) \
164 MBIM_ENUM_HELPER(MBIM_CID_MS_DEVICE_RESET, 10) \
165 MBIM_ENUM_HELPER(MBIM_CID_MS_BASE_STATIONS_INFO, 11) \
166 MBIM_ENUM_HELPER(MBIM_CID_MS_LOCATION_INFO_STATUS, 12) \
167 MBIM_ENUM_HELPER(MBIM_CID_NOT_DEFINED, 13) \
168 MBIM_ENUM_HELPER(MBIM_CID_MS_PIN_EX, 14) \
169 MBIM_ENUM_HELPER(MBIM_CID_MS_VERSION , 15)
170
171 #define MBIM_ENUM_HELPER(k, v) k = v,
172 typedef enum{
173 UUID_BASIC_CONNECT_EXT_CIDs
174 } UUID_BASIC_CONNECT_EXT_CID_E;
175 #undef MBIM_ENUM_HELPER
176 #define MBIM_ENUM_HELPER(k, v) {k, #k},
177 enumstrfunc(MS_CID2, UUID_BASIC_CONNECT_EXT_CIDs);
178 #undef MBIM_ENUM_HELPER
179
180 typedef enum {
181 MBIM_CID_SMS_CONFIGURATION = 1, // Y Y Y
182 MBIM_CID_SMS_READ = 2, // N Y Y
183 MBIM_CID_SMS_SEND = 3, // Y N N
184 MBIM_CID_SMS_DELETE = 4, // Y N N
185 MBIM_CID_SMS_MESSAGE_STORE_STATUS = 5, // N Y Y
186 } UUID_SMS_CID_E;
187
188 typedef enum {
189 MBIM_CID_DSS_CONNECT = 1, // Y N N
190 } UUID_DSS_CID_E;
191
192 #define MBIM_MSGS \
193 MBIM_ENUM_HELPER(MBIM_OPEN_MSG, 1) \
194 MBIM_ENUM_HELPER(MBIM_CLOSE_MSG, 2) \
195 MBIM_ENUM_HELPER(MBIM_COMMAND_MSG, 3) \
196 MBIM_ENUM_HELPER(MBIM_HOST_ERROR_MSG, 4) \
197 \
198 MBIM_ENUM_HELPER(MBIM_OPEN_DONE, 0x80000001) \
199 MBIM_ENUM_HELPER(MBIM_CLOSE_DONE, 0x80000002) \
200 MBIM_ENUM_HELPER(MBIM_COMMAND_DONE, 0x80000003) \
201 MBIM_ENUM_HELPER(MBIM_FUNCTION_ERROR_MSG, 0x80000004) \
202 MBIM_ENUM_HELPER(MBIM_INDICATE_STATUS_MSG, 0x80000007)
203
204 #define MBIM_ENUM_HELPER(k, v) k = v,
205 typedef enum{
206 MBIM_MSGS
207 } MBIM_MSG_Type_E;
208 #undef MBIM_ENUM_HELPER
209 #define MBIM_ENUM_HELPER(k, v) {k, #k},
210 enumstrfunc(MBIMMSGType, MBIM_MSGS);
211 #undef MBIM_ENUM_HELPER
212
213 typedef enum { /*< since=1.10 >*/
214 MBIM_CID_PROXY_CONTROL_UNKNOWN = 0,
215 MBIM_CID_PROXY_CONTROL_CONFIGURATION = 1
216 } UUID_LIBMBIM_PROXY_CID_E;
217
218 typedef enum {
219 MBIM_ERROR_TIMEOUT_FRAGMENT = 1,
220 MBIM_ERROR_FRAGMENT_OUT_OF_SEQUENCE = 2,
221 MBIM_ERROR_LENGTH_MISMATCH = 3,
222 MBIM_ERROR_DUPLICATED_TID = 4,
223 MBIM_ERROR_NOT_OPENED = 5,
224 MBIM_ERROR_UNKNOWN = 6,
225 MBIM_ERROR_CANCEL = 7,
226 MBIM_ERROR_MAX_TRANSFER = 8,
227 } MBIM_ERROR_E;
228
229 typedef enum {
230 MBIM_STATUS_SUCCESS = 0,
231 MBIM_STATUS_BUSY = 1,
232 MBIM_STATUS_FAILURE = 2,
233 MBIM_STATUS_SIM_NOT_INSERTED = 3,
234 MBIM_STATUS_BAD_SIM = 4,
235 MBIM_STATUS_PIN_REQUIRED = 5,
236 MBIM_STATUS_PIN_DISABLED = 6,
237 MBIM_STATUS_NOT_REGISTERED = 7,
238 MBIM_STATUS_PROVIDERS_NOT_FOUND = 8,
239 MBIM_STATUS_NO_DEVICE_SUPPORT = 9,
240 MBIM_STATUS_PROVIDER_NOT_VISIBLE = 10,
241 MBIM_STATUS_DATA_CLASS_NOT_AVAILABL = 11,
242 MBIM_STATUS_PACKET_SERVICE_DETACHED = 12,
243 } MBIM_STATUS_CODES_E;
244
245 typedef enum {
246 MBIMPacketServiceActionAttach = 0,
247 MBIMPacketServiceActionDetach = 1,
248 } MBIM_PACKET_SERVICE_ACTION_E;
249
250 typedef enum {
251 MBIMPacketServiceStateUnknown = 0,
252 MBIMPacketServiceStateAttaching = 1,
253 MBIMPacketServiceStateAttached = 2,
254 MBIMPacketServiceStateDetaching = 3,
255 MBIMPacketServiceStateDetached = 4,
256 } MBIM_PACKET_SERVICE_STATE_E;
257
MBIMPacketServiceStateStr(int _val)258 static const char *MBIMPacketServiceStateStr(int _val) {
259 struct { int val;char *name;} _enumstr[] = {
260 {MBIMPacketServiceStateUnknown, "Unknown"},
261 {MBIMPacketServiceStateAttaching, "Attaching"},
262 {MBIMPacketServiceStateAttached, "Attached"},
263 {MBIMPacketServiceStateDetaching, "Detaching"},
264 {MBIMPacketServiceStateDetached, "Detached"},
265 };
266 int idx;
267
268 for (idx = 0; idx < (int)(sizeof(_enumstr)/sizeof(_enumstr[0])); idx++) {
269 if (_val == _enumstr[idx].val)
270 return _enumstr[idx].name;
271 }
272
273 return "Undefined";
274 };
275
276 typedef enum {
277 MBIMDataClassNone = 0x0,
278 MBIMDataClassGPRS = 0x1,
279 MBIMDataClassEDGE = 0x2,
280 MBIMDataClassUMTS = 0x4,
281 MBIMDataClassHSDPA = 0x8,
282 MBIMDataClassHSUPA = 0x10,
283 MBIMDataClassLTE = 0x20,
284 MBIMDataClass5G_NSA = 0x40,
285 MBIMDataClass5G_SA = 0x80,
286 MBIMDataClass1XRTT = 0x10000,
287 MBIMDataClass1XEVDO = 0x20000,
288 MBIMDataClass1XEVDORevA = 0x40000,
289 MBIMDataClass1XEVDV = 0x80000,
290 MBIMDataClass3XRTT = 0x100000,
291 MBIMDataClass1XEVDORevB = 0x200000,
292 MBIMDataClassUMB = 0x400000,
293 MBIMDataClassCustom = 0x80000000,
294 } MBIM_DATA_CLASS_E;
295
MBIMDataClassStr(int _val)296 static const char *MBIMDataClassStr(int _val) {
297 struct { int val;char *name;} _enumstr[] = {
298 {MBIMDataClassNone, "None"},
299 {MBIMDataClassGPRS, "GPRS"},
300 {MBIMDataClassEDGE, "EDGE"},
301 {MBIMDataClassUMTS, "UMTS"},
302 {MBIMDataClassHSDPA, "HSDPA"},
303 {MBIMDataClassHSUPA, "HSUPA"},
304 {MBIMDataClassLTE, "LTE"},
305 {MBIMDataClass5G_NSA, "5G_NSA"},
306 {MBIMDataClass5G_SA, "5G_SA"},
307 {MBIMDataClass1XRTT, "1XRTT"},
308 {MBIMDataClass1XEVDO, "1XEVDO"},
309 {MBIMDataClass1XEVDORevA, "1XEVDORevA"},
310 {MBIMDataClass1XEVDV, "1XEVDV"},
311 {MBIMDataClass3XRTT, "3XRTT"},
312 {MBIMDataClass1XEVDORevB, "1XEVDORevB"},
313 {MBIMDataClassUMB, "UMB"},
314 {MBIMDataClassCustom, "Custom"},
315 };
316 int idx;
317
318 for (idx = 0; idx < (int)(sizeof(_enumstr)/sizeof(_enumstr[0])); idx++) {
319 if (_val == _enumstr[idx].val)
320 return _enumstr[idx].name;
321 }
322
323 return "Unknow";
324 };
325
326 typedef struct {
327 UINT32 NwError;
328 UINT32 PacketServiceState; //MBIM_PACKET_SERVICE_STATE_E
329 UINT32 HighestAvailableDataClass; //MBIM_DATA_CLASS_E
330 UINT64 UplinkSpeed;
331 UINT64 DownlinkSpeed;
332 } MBIM_PACKET_SERVICE_INFO_T;
333
334 typedef struct {
335 UINT32 NwError;
336 UINT32 PacketServiceState; //MBIM_PACKET_SERVICE_STATE_E
337 UINT32 CurrentDataClass; //MBIM_DATA_CLASS_E
338 UINT64 UplinkSpeed;
339 UINT64 DownlinkSpeed;
340 UINT32 FrequencyRange;
341 } MBIM_PACKET_SERVICE_INFO_V2_T;
342
343 typedef enum {
344 MBIMSubscriberReadyStateNotInitialized = 0,
345 MBIMSubscriberReadyStateInitialized = 1,
346 MBIMSubscriberReadyStateSimNotInserted = 2,
347 MBIMSubscriberReadyStateBadSim = 3,
348 MBIMSubscriberReadyStateFailure = 4,
349 MBIMSubscriberReadyStateNotActivated = 5,
350 MBIMSubscriberReadyStateDeviceLocked = 6,
351 }MBIM_SUBSCRIBER_READY_STATE_E;
352
MBIMSubscriberReadyStateStr(int _val)353 static const char *MBIMSubscriberReadyStateStr(int _val) {
354 struct { int val;char *name;} _enumstr[] = {
355 {MBIMSubscriberReadyStateNotInitialized, "NotInitialized"},
356 {MBIMSubscriberReadyStateInitialized, "Initialized"},
357 {MBIMSubscriberReadyStateSimNotInserted, "NotInserted"},
358 {MBIMSubscriberReadyStateBadSim, "BadSim"},
359 {MBIMSubscriberReadyStateFailure, "Failure"},
360 {MBIMSubscriberReadyStateNotActivated, "NotActivated"},
361 {MBIMSubscriberReadyStateDeviceLocked, "DeviceLocked"},
362 };
363 int idx;
364
365 for (idx = 0; idx < (int)(sizeof(_enumstr)/sizeof(_enumstr[0])); idx++) {
366 if (_val == _enumstr[idx].val)
367 return _enumstr[idx].name;
368 }
369
370 return "Undefined";
371 };
372
373 typedef struct {
374 UINT32 DeviceType; //MBIM_DEVICE_TYPE
375 UINT32 CellularClass; //MBIM_CELLULAR_CLASS
376 UINT32 VoiceClass; //MBIM_VOICE_CLASS
377 UINT32 SimClass; //MBIM_SIM_CLASS
378 UINT32 DataClass; //MBIM_DATA_CLASS
379 UINT32 SmsCaps; //MBIM_SMS_CAPS
380 UINT32 ControlCaps; //MBIM_CTRL_CAPS
381 UINT32 MaxSessions;
382 UINT32 CustomDataClassOffset;
383 UINT32 CustomDataClassSize;
384 UINT32 DeviceIdOffset;
385 UINT32 DeviceIdSize;
386 UINT32 FirmwareInfoOffset;
387 UINT32 FirmwareInfoSize;
388 UINT32 HardwareInfoOffset;
389 UINT32 HardwareInfoSize;
390 UINT8 DataBuffer[0]; //DeviceId FirmwareInfo HardwareInfo
391 } MBIM_DEVICE_CAPS_INFO_T;
392
393 typedef enum {
394 MBIMRadioOff = 0,
395 MBIMRadioOn = 1,
396 } MBIM_RADIO_SWITCH_STATE_E;
397
398 typedef struct {
399 MBIM_RADIO_SWITCH_STATE_E RadioState;
400 } MBIM_SET_RADIO_STATE_T;
401
402 typedef struct {
403 MBIM_RADIO_SWITCH_STATE_E HwRadioState;
404 MBIM_RADIO_SWITCH_STATE_E SwRadioState;
405 } MBIM_RADIO_STATE_INFO_T;
406
407 typedef enum {
408 MBIMReadyInfoFlagsNone,
409 MBIMReadyInfoFlagsProtectUniqueID,
410 }MBIM_UNIQUE_ID_FLAGS;
411
412 typedef struct {
413 UINT32 ReadyState;
414 UINT32 SubscriberIdOffset;
415 UINT32 SubscriberIdSize;
416 UINT32 SimIccIdOffset;
417 UINT32 SimIccIdSize;
418 UINT32 ReadyInfo;
419 UINT32 ElementCount;
420 UINT8 *TelephoneNumbersRefList;
421 UINT8 *DataBuffer;
422 } MBIM_SUBSCRIBER_READY_STATUS_T;
423
424 typedef enum {
425 MBIMRegisterActionAutomatic,
426 MBIMRegisterActionManual,
427 }MBIM_REGISTER_ACTION_E;
428
429 typedef enum {
430 MBIMRegisterStateUnknown = 0,
431 MBIMRegisterStateDeregistered = 1,
432 MBIMRegisterStateSearching = 2,
433 MBIMRegisterStateHome = 3,
434 MBIMRegisterStateRoaming = 4,
435 MBIMRegisterStatePartner = 5,
436 MBIMRegisterStateDenied = 6,
437 }MBIM_REGISTER_STATE_E;
438
439 typedef enum {
440 MBIMRegisterModeUnknown = 0,
441 MBIMRegisterModeAutomatic = 1,
442 MBIMRegisterModeManual = 2,
443 }MBIM_REGISTER_MODE_E;
444
MBIMRegisterStateStr(int _val)445 static const char *MBIMRegisterStateStr(int _val) {
446 struct { int val;char *name;} _enumstr[] ={
447 {MBIMRegisterStateUnknown, "Unknown"},
448 {MBIMRegisterStateDeregistered, "Deregistered"},
449 {MBIMRegisterStateSearching, "Searching"},
450 {MBIMRegisterStateHome, "Home"},
451 {MBIMRegisterStateRoaming, "Roaming"},
452 {MBIMRegisterStatePartner, "Partner"},
453 {MBIMRegisterStateDenied, "Denied"},
454 };
455 int idx;
456
457 for (idx = 0; idx < (int)(sizeof(_enumstr)/sizeof(_enumstr[0])); idx++) {
458 if (_val == _enumstr[idx].val)
459 return _enumstr[idx].name;
460 }
461
462 return "Undefined";
463 };
464
MBIMRegisterModeStr(int _val)465 static const char *MBIMRegisterModeStr(int _val) {
466 struct { int val;char *name;} _enumstr[] = {
467 {MBIMRegisterModeUnknown, "Unknown"},
468 {MBIMRegisterModeAutomatic, "Automatic"},
469 {MBIMRegisterModeManual, "Manual"},
470 };
471 int idx;
472
473 for (idx = 0; idx < (int)(sizeof(_enumstr)/sizeof(_enumstr[0])); idx++) {
474 if (_val == _enumstr[idx].val)
475 return _enumstr[idx].name;
476 }
477
478 return "Undefined";
479 };
480
481 typedef enum {
482 MBIM_REGISTRATION_NONE,
483 MBIM_REGISTRATION_MANUAL_SELECTION_NOT_AVAILABLE,
484 MBIM_REGISTRATION_PACKET_SERVICE_AUTOMATIC_ATTACH,
485 }MBIM_REGISTRATION_FLAGS_E;
486
487 typedef struct {
488 UINT32 NwError;
489 UINT32 RegisterState; //MBIM_REGISTER_STATE_E
490 UINT32 RegisterMode;
491 UINT32 AvailableDataClasses;
492 UINT32 CurrentCellularClass;
493 UINT32 ProviderIdOffset;
494 UINT32 ProviderIdSize;
495 UINT32 ProviderNameOffset;
496 UINT32 ProviderNameSize;
497 UINT32 RoamingTextOffset;
498 UINT32 RoamingTextSize;
499 UINT32 RegistrationFlag;
500 UINT8 *DataBuffer;
501 } MBIM_REGISTRATION_STATE_INFO_T;
502
503 typedef struct {
504 UINT32 NwError;
505 UINT32 RegisterState; //MBIM_REGISTER_STATE_E
506 UINT32 RegisterMode;
507 UINT32 AvailableDataClasses;
508 UINT32 CurrentCellularClass;
509 UINT32 ProviderIdOffset;
510 UINT32 ProviderIdSize;
511 UINT32 ProviderNameOffset;
512 UINT32 ProviderNameSize;
513 UINT32 RoamingTextOffset;
514 UINT32 RoamingTextSize;
515 UINT32 RegistrationFlag;
516 UINT32 PreferredDataClass;
517 UINT8 *DataBuffer;
518 } MBIM_REGISTRATION_STATE_INFO_V2_T;
519
520 typedef struct {
521 UINT32 MessageType; //Specifies the MBIM message type.
522 UINT32 MessageLength; //Specifies the total length of this MBIM message in bytes.
523 /* Specifies the MBIM message id value. This value is used to match host sent messages with function responses.
524 This value must be unique among all outstanding transactions.
525 For notifications, the TransactionId must be set to 0 by the function */
526 UINT32 TransactionId;
527 } MBIM_MESSAGE_HEADER;
528
529 typedef struct {
530 UINT32 TotalFragments; //this field indicates how many fragments there are intotal.
531 UINT32 CurrentFragment; //This field indicates which fragment this message is. Values are 0 to TotalFragments?\1
532 } MBIM_FRAGMENT_HEADER;
533
534 typedef struct {
535 MBIM_MESSAGE_HEADER MessageHeader;
536 UINT32 MaxControlTransfer;
537 } MBIM_OPEN_MSG_T;
538
539 typedef struct {
540 MBIM_MESSAGE_HEADER MessageHeader;
541 UINT32 Status;
542 } MBIM_OPEN_DONE_T;
543
544 typedef struct {
545 MBIM_MESSAGE_HEADER MessageHeader;
546 } MBIM_CLOSE_MSG_T;
547
548 typedef struct {
549 MBIM_MESSAGE_HEADER MessageHeader;
550 UINT32 Status;
551 } MBIM_CLOSE_DONE_T;
552
553 typedef struct {
554 UINT8 uuid[16];
555 } UUID_T;
556
557 typedef struct {
558 MBIM_MESSAGE_HEADER MessageHeader;
559 MBIM_FRAGMENT_HEADER FragmentHeader;
560 UUID_T DeviceServiceId; //A 16 byte UUID that identifies the device service the following CID value applies.
561 UINT32 CID; //Specifies the CID that identifies the parameter being queried for
562 UINT32 CommandType; //0 for a query operation, 1 for a Set operation
563 UINT32 InformationBufferLength; //Size of the Total InformationBuffer, may be larger than current message if fragmented.
564 UINT8 InformationBuffer[0]; //Data supplied to device specific to the CID
565 } MBIM_COMMAND_MSG_T;
566
567 typedef struct {
568 MBIM_MESSAGE_HEADER MessageHeader;
569 MBIM_FRAGMENT_HEADER FragmentHeader;
570 UUID_T DeviceServiceId; //A 16 byte UUID that identifies the device service the following CID value applies.
571 UINT32 CID; //Specifies the CID that identifies the parameter being queried for
572 UINT32 Status;
573 UINT32 InformationBufferLength; //Size of the Total InformationBuffer, may be larger than current message if fragmented.
574 UINT8 InformationBuffer[0]; //Data supplied to device specific to the CID
575 } MBIM_COMMAND_DONE_T;
576
577 typedef struct {
578 MBIM_MESSAGE_HEADER MessageHeader;
579 UINT32 ErrorStatusCode;
580 } MBIM_HOST_ERROR_MSG_T;
581
582 typedef struct {
583 MBIM_MESSAGE_HEADER MessageHeader;
584 UINT32 ErrorStatusCode;
585 } MBIM_FUNCTION_ERROR_MSG_T;
586
587 typedef struct {
588 MBIM_MESSAGE_HEADER MessageHeader;
589 MBIM_FRAGMENT_HEADER FragmentHeader;
590 UUID_T DeviceServiceId; //A 16 byte UUID that identifies the device service the following CID value applies.
591 UINT32 CID; //Specifies the CID that identifies the parameter being queried for
592 UINT32 InformationBufferLength; //Size of the Total InformationBuffer, may be larger than current message if fragmented.
593 UINT8 InformationBuffer[0]; //Data supplied to device specific to the CID
594 } MBIM_INDICATE_STATUS_MSG_T;
595
596 typedef struct {
597 UINT32 offset;
598 UINT32 size;
599 } OL_PAIR_LIST;
600
601 typedef struct {
602 UUID_T DeviceServiceId;
603 UINT32 DssPayload;
604 UINT32 MaxDssInstances;
605 UINT32 CidCount;
606 UINT32 CidList[];
607 } MBIM_DEVICE_SERVICE_ELEMENT_T;
608
609 typedef struct {
610 UINT32 DeviceServicesCount;
611 UINT32 MaxDssSessions;
612 OL_PAIR_LIST DeviceServicesRefList[];
613 } MBIM_DEVICE_SERVICES_INFO_T;
614
615 typedef enum {
616 MBIMActivationCommandDeactivate = 0,
617 MBIMActivationCommandActivate = 1,
618 } MBIM_ACTIVATION_COMMAND_E;
619
620 typedef enum {
621 MBIMCompressionNone = 0,
622 MBIMCompressionEnable = 1,
623 } MBIM_COMPRESSION_E;
624
625 typedef enum {
626 MBIMAuthProtocolNone = 0,
627 MBIMAuthProtocolPap = 1,
628 MBIMAuthProtocolChap = 2,
629 MBIMAuthProtocolMsChapV2 = 3,
630 } MBIM_AUTH_PROTOCOL_E;
631
632 #define MBIMContextIPTypes \
633 MBIM_ENUM_HELPER(MBIMContextIPTypeDefault, 0) \
634 MBIM_ENUM_HELPER(MBIMContextIPTypeIPv4, 1) \
635 MBIM_ENUM_HELPER(MBIMContextIPTypeIPv6, 2) \
636 MBIM_ENUM_HELPER(MBIMContextIPTypeIPv4v6, 3) \
637 MBIM_ENUM_HELPER(MBIMContextIPTypeIPv4AndIPv6, 4)
638
639 #define MBIM_ENUM_HELPER(k, v) k = v,
640 typedef enum {
641 MBIMContextIPTypes
642 } MBIM_CONTEXT_IP_TYPE_E;
643 #undef MBIM_ENUM_HELPER
644 #define MBIM_ENUM_HELPER(k, v) {k, #k},
645 enumstrfunc(MBIMContextIPType, MBIMContextIPTypes);
646 #undef MBIM_ENUM_HELPER
647
648 typedef enum {
649 MBIMActivationStateUnknown = 0,
650 MBIMActivationStateActivated = 1,
651 MBIMActivationStateActivating = 2,
652 MBIMActivationStateDeactivated = 3,
653 MBIMActivationStateDeactivating = 4,
654 } MBIM_ACTIVATION_STATE_E;
655
656 typedef enum {
657 MBIMVoiceCallStateNone = 0,
658 MBIMVoiceCallStateInProgress = 1,
659 MBIMVoiceCallStateHangUp = 2,
660 } MBIM_VOICECALL_STATE_E;
661
MBIMActivationStateStr(int _val)662 static const char *MBIMActivationStateStr(int _val) {
663 struct { int val;char *name;} _enumstr[] = {
664 {MBIMActivationStateUnknown, "Unknown"},
665 {MBIMActivationStateActivated, "Activated"},
666 {MBIMActivationStateActivating, "Activating"},
667 {MBIMActivationStateDeactivated, "Deactivated"},
668 {MBIMActivationStateDeactivating, "Deactivating"},
669 };
670 int idx;
671
672 for (idx = 0; idx < (int)(sizeof(_enumstr)/sizeof(_enumstr[0])); idx++) {
673 if (_val == _enumstr[idx].val)
674 return _enumstr[idx].name;
675 }
676
677 return "Undefined";
678 };
679
MBIMVoiceCallStateStr(int _val)680 static const char *MBIMVoiceCallStateStr(int _val) {
681 struct { int val;char *name;} _enumstr[] = {
682 {MBIMVoiceCallStateNone, "None"},
683 {MBIMVoiceCallStateInProgress, "InProgress"},
684 {MBIMVoiceCallStateHangUp, "HangUp"},
685 };
686 int idx;
687
688 for (idx = 0; idx < (int)(sizeof(_enumstr)/sizeof(_enumstr[0])); idx++) {
689 if (_val == _enumstr[idx].val)
690 return _enumstr[idx].name;
691 }
692
693 return "Undefined";
694 };
695
696 typedef struct {
697 UINT32 SessionId;
698 UINT32 ActivationCommand; //MBIM_ACTIVATION_COMMAND_E
699 UINT32 AccessStringOffset;
700 UINT32 AccessStringSize;
701 UINT32 UserNameOffset;
702 UINT32 UserNameSize;
703 UINT32 PasswordOffset;
704 UINT32 PasswordSize;
705 UINT32 Compression; //MBIM_COMPRESSION_E
706 UINT32 AuthProtocol; //MBIM_AUTH_PROTOCOL_E
707 UINT32 IPType; //MBIM_CONTEXT_IP_TYPE_E
708 UUID_T ContextType;
709 UINT8 DataBuffer[0]; /* apn, username, password */
710 } MBIM_SET_CONNECT_T;
711
712 typedef struct {
713 UINT32 SessionId;
714 UINT32 ActivationState; //MBIM_ACTIVATION_STATE_E
715 UINT32 VoiceCallState;
716 UINT32 IPType; //MBIM_CONTEXT_IP_TYPE_E
717 UUID_T ContextType;
718 UINT32 NwError;
719 } MBIM_CONNECT_T;
720
721 typedef struct {
722 UINT32 OnLinkPrefixLength;
723 UINT8 IPv4Address[4];
724 } MBIM_IPV4_ELEMENT_T;
725
726 typedef struct {
727 UINT32 OnLinkPrefixLength;
728 UINT8 IPv6Address[16];
729 } MBIM_IPV6_ELEMENT_T;
730
731 typedef struct {
732 UINT32 SessionId;
733 UINT32 IPv4ConfigurationAvailable; //bit0~Address, bit1~gateway, bit2~DNS, bit3~MTU
734 UINT32 IPv6ConfigurationAvailable; //bit0~Address, bit1~gateway, bit2~DNS, bit3~MTU
735 UINT32 IPv4AddressCount;
736 UINT32 IPv4AddressOffset;
737 UINT32 IPv6AddressCount;
738 UINT32 IPv6AddressOffset;
739 UINT32 IPv4GatewayOffset;
740 UINT32 IPv6GatewayOffset;
741 UINT32 IPv4DnsServerCount;
742 UINT32 IPv4DnsServerOffset;
743 UINT32 IPv6DnsServerCount;
744 UINT32 IPv6DnsServerOffset;
745 UINT32 IPv4Mtu;
746 UINT32 IPv6Mtu;
747 UINT8 DataBuffer[];
748 } MBIM_IP_CONFIGURATION_INFO_T;
749
750 typedef struct {
751 UINT32 RSRP;
752 UINT32 SNR;
753 UINT32 RSRPThreshold;
754 UINT32 SNRThreshold;
755 UINT32 SystemType;
756 } MBIM_RSRP_SNR_INFO_T;
757
758 typedef struct {
759 UINT32 Elementcount;
760 MBIM_RSRP_SNR_INFO_T RsrpSnr[0];
761 } MBIM_RSRP_SNR_T;
762
763 typedef struct {
764 UINT32 Rssi;
765 UINT32 ErrorRate;
766 UINT32 SignalStrengthInterval;
767 UINT32 RssiThreshold;
768 UINT32 ErrorRateThreshold;
769 } MBIM_SIGNAL_STATE_INFO_T;
770
771 typedef struct {
772 UINT32 Rssi;
773 UINT32 ErrorRate;
774 UINT32 SignalStrengthInterval;
775 UINT32 RssiThreshold;
776 UINT32 ErrorRateThreshold;
777 UINT32 RsrpSnrOffset;
778 UINT32 RsrpSnrSize;
779 UINT8 DataBuffer[];
780 } MBIM_SIGNAL_STATE_INFO_V2_T;
781
782 typedef struct {
783 UINT32 SignalStrengthInterval;
784 UINT32 RssiThreshold;
785 UINT32 ErrorRateThreshold;
786 } MBIM_SET_SIGNAL_STATE_T;
787
788 typedef struct {
789 UINT32 DevicePathOffset;
790 UINT32 DevicePathSize;
791 UINT32 Timeout;
792 UINT8 DataBuffer[];
793 } MBIM_LIBQMI_PROXY_CONFIG_T;
794
795 #pragma pack()
796
797 static pthread_t s_tid_reader = 0;
798 static int mbim_verbose = 0;
799 static UINT32 TransactionId = 1;
800 static unsigned mbim_default_timeout = 30000;
801 static const char *mbim_apn = NULL;
802 static const char *mbim_user = NULL;
803 static const char *mbim_passwd = NULL;
804 static int mbim_iptype = MBIMContextIPTypeDefault;
805 static int mbim_auth = MBIMAuthProtocolNone;
806 static int mbim_sessionID = 0;
807 static int mbim_fd = -1;
808 static MBIM_MESSAGE_HEADER *mbim_pRequest;
809 static MBIM_MESSAGE_HEADER *mbim_pResponse;
810
str2uuid(const char * str)811 static const UUID_T * str2uuid(const char *str) {
812 static UUID_T uuid;
813 UINT32 d[16];
814 char tmp[16*2+4+1];
815 unsigned i = 0;
816
817 while (str[i]) {
818 tmp[i] = tolower(str[i]);
819 i++;
820 }
821 tmp[i] = '\0';
822
823 sscanf(tmp, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
824 &d[0], &d[1], &d[2], &d[3], &d[4], &d[5], &d[6], &d[7],
825 &d[8], &d[9], &d[10], &d[11], &d[12], &d[13], &d[14], &d[15]);
826
827 for (i = 0; i < 16; i++) {
828 uuid.uuid[i] = d[i]&0xFF;
829 }
830
831 return &uuid;
832 }
833
wchar2char(const char * src,size_t src_size,char * dst,size_t dst_len)834 static void wchar2char(const char *src, size_t src_size, char *dst, size_t dst_len) {
835 size_t i;
836
837 for (i = 0; i < (dst_len-1) && i < (src_size/2); i++)
838 dst[i] = src[i*2];
839 dst[i] = 0;
840 }
841
char2wchar(const char * src,size_t src_len,uint8_t * dst,size_t dst_len)842 static size_t char2wchar(const char *src, size_t src_len, uint8_t *dst, size_t dst_len) {
843 size_t i;
844
845 if (src_len > (dst_len/2))
846 src_len = (dst_len/2);
847
848 for (i = 0; i < src_len; i++) {
849 *dst++ = *src++;
850 *dst++ = 0;
851 }
852
853 return i*2;
854 }
855
856 #define mbim_alloc( _size) malloc(_size)
857 #define mbim_free(_mem) do { if (_mem) { free(_mem); _mem = NULL;}} while(0)
858
859 static int mbim_open_state = 0;
860 static MBIM_SUBSCRIBER_READY_STATE_E ReadyState = MBIMSubscriberReadyStateNotInitialized;
861 static MBIM_REGISTER_STATE_E RegisterState = MBIMRegisterStateUnknown;
862 static MBIM_PACKET_SERVICE_STATE_E PacketServiceState = MBIMPacketServiceStateUnknown;
863 static MBIM_ACTIVATION_STATE_E ActivationState = MBIMActivationStateUnknown;
864 static MBIM_SUBSCRIBER_READY_STATE_E oldReadyState = MBIMSubscriberReadyStateNotInitialized;
865 static MBIM_REGISTER_STATE_E oldRegisterState = MBIMRegisterStateUnknown;
866 static MBIM_PACKET_SERVICE_STATE_E oldPacketServiceState = MBIMPacketServiceStateUnknown;
867 static MBIM_ACTIVATION_STATE_E oldActivationState = MBIMActivationStateUnknown;
868 static int mbim_update_state(void);
869
mbim2qmi_ipv4addr(uint32_t addr)870 static __inline uint32_t mbim2qmi_ipv4addr(uint32_t addr) {
871 return (addr>>24) | (addr>>8&0xff00) | (addr<<8&0xff0000) | (addr<<24);
872 }
873
mbim2qmi_ipv6addr(const unsigned char * src,unsigned char * dst)874 static __inline void mbim2qmi_ipv6addr(const unsigned char *src, unsigned char *dst) {
875 int i;
876
877 for (i = 0; i < 16 ; i++) {
878 dst[i] = src[i];
879 }
880 }
881
compose_open_command(UINT32 MaxControlTransfer)882 static MBIM_MESSAGE_HEADER *compose_open_command(UINT32 MaxControlTransfer)
883 {
884 MBIM_OPEN_MSG_T *pRequest = (MBIM_OPEN_MSG_T *)mbim_alloc(sizeof(MBIM_OPEN_MSG_T));
885
886 if(!pRequest)
887 return NULL;
888
889 pRequest->MessageHeader.MessageType = htole32(MBIM_OPEN_MSG);
890 pRequest->MessageHeader.MessageLength = htole32(sizeof(MBIM_COMMAND_MSG_T));
891 pRequest->MessageHeader.TransactionId = htole32(TransactionId++);
892 pRequest->MaxControlTransfer = htole32(MaxControlTransfer);
893
894 return &pRequest->MessageHeader;
895 }
896
compose_close_command(void)897 static MBIM_MESSAGE_HEADER *compose_close_command(void)
898 {
899 MBIM_CLOSE_MSG_T *pRequest = (MBIM_CLOSE_MSG_T *)mbim_alloc(sizeof(MBIM_CLOSE_MSG_T));
900
901 if(!pRequest)
902 return NULL;
903
904 pRequest->MessageHeader.MessageType = htole32(MBIM_CLOSE_MSG);
905 pRequest->MessageHeader.MessageLength = htole32(sizeof(MBIM_CLOSE_MSG_T));
906 pRequest->MessageHeader.TransactionId = htole32(TransactionId++);
907
908 return &pRequest->MessageHeader;
909 }
910
compose_basic_connect_command(UINT32 CID,UINT32 CommandType,void * pInformationBuffer,UINT32 InformationBufferLength)911 static MBIM_MESSAGE_HEADER *compose_basic_connect_command(UINT32 CID, UINT32 CommandType, void *pInformationBuffer, UINT32 InformationBufferLength)
912 {
913 MBIM_COMMAND_MSG_T *pRequest = (MBIM_COMMAND_MSG_T *)mbim_alloc(sizeof(MBIM_COMMAND_MSG_T) + InformationBufferLength);
914
915 if (!pRequest)
916 return NULL;
917
918 pRequest->MessageHeader.MessageType = htole32(MBIM_COMMAND_MSG);
919 pRequest->MessageHeader.MessageLength = htole32((sizeof(MBIM_COMMAND_MSG_T) + InformationBufferLength));
920 pRequest->MessageHeader.TransactionId = htole32(TransactionId++);
921
922 pRequest->FragmentHeader.TotalFragments = htole32(1);
923 pRequest->FragmentHeader.CurrentFragment= htole32(0);
924
925 memcpy(pRequest->DeviceServiceId.uuid, str2uuid(UUID_BASIC_CONNECT), 16);
926
927 pRequest->CID = htole32(CID);
928 pRequest->CommandType = htole32(CommandType);
929 if (InformationBufferLength && pInformationBuffer) {
930 pRequest->InformationBufferLength = htole32(InformationBufferLength);
931 memcpy(pRequest->InformationBuffer, pInformationBuffer, InformationBufferLength);
932 } else {
933 pRequest->InformationBufferLength = htole32(0);
934 }
935
936 return &pRequest->MessageHeader;
937 }
938
compose_basic_connect_ext_command(UINT32 CID,UINT32 CommandType,void * pInformationBuffer,UINT32 InformationBufferLength)939 static MBIM_MESSAGE_HEADER *compose_basic_connect_ext_command(UINT32 CID, UINT32 CommandType, void *pInformationBuffer, UINT32 InformationBufferLength)
940 {
941 MBIM_COMMAND_MSG_T *pRequest = (MBIM_COMMAND_MSG_T *)compose_basic_connect_command(CID, CommandType, pInformationBuffer, InformationBufferLength);
942
943 if (!pRequest)
944 return NULL;
945
946 memcpy(pRequest->DeviceServiceId.uuid, str2uuid(UUID_BASIC_CONNECT_EXT), 16);
947
948 return &pRequest->MessageHeader;
949 }
950
uuid2str(const UUID_T * pUUID)951 static const char * uuid2str(const UUID_T *pUUID) {
952 static char str[16*2+4+1];
953 const UINT8 *d = pUUID->uuid;
954
955 snprintf(str, sizeof(str), "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
956 d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7],
957 d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
958
959 return str;
960 }
961
DeviceServiceId2str(const UUID_T * pUUID)962 static const char *DeviceServiceId2str(const UUID_T *pUUID) {
963 const char *str = uuid2str(pUUID);
964
965 struct { char *val;char *name;} _enumstr[] = {
966 {UUID_BASIC_CONNECT, "UUID_BASIC_CONNECT"},
967 {UUID_BASIC_CONNECT_EXT, "UUID_BASIC_CONNECT_EXT"},
968 {UUID_SMS, "UUID_SMS"},
969 {UUID_USSD, "UUID_USSD"},
970 {UUID_PHONEBOOK, "UUID_PHONEBOOK"},
971 {UUID_STK, "UUID_STK"},
972 {UUID_AUTH, "UUID_AUTH"},
973 {UUID_DSS, "UUID_DSS"},
974 {uuid_ext_qmux, "uuid_ext_qmux"},
975 {uuid_mshsd, "uuid_mshsd"},
976 {uuid_qmbe, "uuid_qmbe"},
977 {UUID_MSFWID, "UUID_MSFWID"},
978 {uuid_atds, "uuid_atds"},
979 {uuid_qdu, "uuid_qdu"},
980 {UUID_MS_UICC_LOW_LEVEL, "UUID_MS_UICC_LOW_LEVEL"},
981 {UUID_MS_SARControl, "UUID_MS_SARControl"},
982 {UUID_VOICEEXTENSIONS, "UUID_VOICEEXTENSIONS"},
983 {UUID_LIBMBIM_PROXY, "UUID_LIBMBIM_PROXY"},
984 };
985 int idx;
986
987 for (idx = 0; idx < (int)(sizeof(_enumstr)/sizeof(_enumstr[0])); idx++) {
988 if (!strcasecmp(str, _enumstr[idx].val))
989 return _enumstr[idx].name;
990 }
991
992 return str;
993 }
994
mbim_get_segment(void * _pMsg,UINT32 offset,UINT32 len)995 static const char *mbim_get_segment(void *_pMsg, UINT32 offset, UINT32 len)
996 {
997 int idx;
998 static char buff[256] = {'\0'};
999 UINT8 *pMsg = (UINT8*)_pMsg;
1000
1001 for (idx = 0; idx < (int)(len/2); idx++)
1002 buff[idx] = pMsg[offset+idx*2];
1003 buff[idx] = '\0';
1004 return buff;
1005 }
1006
mbim_dump_header(MBIM_MESSAGE_HEADER * pMsg,const char * direction)1007 static void mbim_dump_header(MBIM_MESSAGE_HEADER *pMsg, const char *direction) {
1008 mbim_debug("%s Header:", direction);
1009 mbim_debug("%s MessageLength = %u", direction, le32toh(pMsg->MessageLength));
1010 mbim_debug("%s MessageType = %s (0x%08x)", direction, MBIMMSGTypeStr(le32toh(pMsg->MessageType)), le32toh(pMsg->MessageType));
1011 mbim_debug("%s TransactionId = %u", direction, le32toh(pMsg->TransactionId));
1012 mbim_debug("%s Contents:", direction);
1013 }
1014
mbim_dump_command_msg(MBIM_COMMAND_MSG_T * pCmdMsg,const char * direction)1015 static void mbim_dump_command_msg(MBIM_COMMAND_MSG_T *pCmdMsg, const char *direction) {
1016 mbim_debug("%s DeviceServiceId = %s (%s)", direction, DeviceServiceId2str(&pCmdMsg->DeviceServiceId), uuid2str(&pCmdMsg->DeviceServiceId));
1017 mbim_debug("%s CID = %s (%u)", direction, CID2Str(le32toh(pCmdMsg->CID)), le32toh(pCmdMsg->CID));
1018 mbim_debug("%s CommandType = %s (%u)", direction, le32toh(pCmdMsg->CommandType) ? "set" : "query", le32toh(pCmdMsg->CommandType));
1019 mbim_debug("%s InformationBufferLength = %u", direction, le32toh(pCmdMsg->InformationBufferLength));
1020 }
1021
mbim_dump_command_done(MBIM_COMMAND_DONE_T * pCmdDone,const char * direction)1022 static void mbim_dump_command_done(MBIM_COMMAND_DONE_T *pCmdDone, const char *direction) {
1023 mbim_debug("%s DeviceServiceId = %s (%s)", direction, DeviceServiceId2str(&pCmdDone->DeviceServiceId), uuid2str(&pCmdDone->DeviceServiceId));
1024 mbim_debug("%s CID = %s (%u)", direction, CID2Str(le32toh(pCmdDone->CID)), le32toh(pCmdDone->CID));
1025 mbim_debug("%s Status = %u", direction, le32toh(pCmdDone->Status));
1026 mbim_debug("%s InformationBufferLength = %u", direction, le32toh(pCmdDone->InformationBufferLength));
1027 }
1028
mbim_dump_indicate_msg(MBIM_INDICATE_STATUS_MSG_T * pIndMsg,const char * direction)1029 static void mbim_dump_indicate_msg(MBIM_INDICATE_STATUS_MSG_T *pIndMsg, const char *direction) {
1030 mbim_debug("%s DeviceServiceId = %s (%s)", direction, DeviceServiceId2str(&pIndMsg->DeviceServiceId), uuid2str(&pIndMsg->DeviceServiceId));
1031 if (!memcmp(pIndMsg->DeviceServiceId.uuid, str2uuid(UUID_BASIC_CONNECT_EXT), 16))
1032 mbim_debug("%s CID = %s (%u)", direction, MS_CID2Str(le32toh(pIndMsg->CID)), le32toh(pIndMsg->CID));
1033 else
1034 mbim_debug("%s CID = %s (%u)", direction, CID2Str(le32toh(pIndMsg->CID)), le32toh(pIndMsg->CID));
1035 mbim_debug("%s InformationBufferLength = %u", direction, le32toh(pIndMsg->InformationBufferLength));
1036 }
1037
mbim_dump_connect(MBIM_CONNECT_T * pInfo,const char * direction)1038 static void mbim_dump_connect(MBIM_CONNECT_T *pInfo, const char *direction) {
1039 mbim_debug("%s SessionId = %u", direction, le32toh(pInfo->SessionId));
1040 mbim_debug("%s ActivationState = %s (%u)", direction, MBIMActivationStateStr(le32toh(pInfo->ActivationState)), le32toh(pInfo->ActivationState));
1041 mbim_debug("%s IPType = %s", direction, MBIMContextIPTypeStr(le32toh(pInfo->IPType)));
1042 mbim_debug("%s VoiceCallState = %s", direction, MBIMVoiceCallStateStr(le32toh(pInfo->VoiceCallState)));
1043 mbim_debug("%s ContextType = %s", direction, uuid2str(&pInfo->ContextType));
1044 mbim_debug("%s NwError = %u", direction, le32toh(pInfo->NwError));
1045 }
1046
mbim_dump_signal_state(MBIM_SIGNAL_STATE_INFO_T * pInfo,const char * direction)1047 static void mbim_dump_signal_state(MBIM_SIGNAL_STATE_INFO_T *pInfo, const char *direction)
1048 {
1049 mbim_debug("%s Rssi = %u", direction, le32toh(pInfo->Rssi));
1050 mbim_debug("%s ErrorRate = %u", direction, le32toh(pInfo->ErrorRate));
1051 mbim_debug("%s SignalStrengthInterval = %u", direction, le32toh(pInfo->SignalStrengthInterval));
1052 mbim_debug("%s RssiThreshold = %u", direction, le32toh(pInfo->RssiThreshold));
1053 mbim_debug("%s ErrorRateThreshold = %u", direction, le32toh(pInfo->ErrorRateThreshold));
1054 }
1055
mbim_dump_packet_service(MBIM_PACKET_SERVICE_INFO_T * pInfo,const char * direction)1056 static void mbim_dump_packet_service(MBIM_PACKET_SERVICE_INFO_T *pInfo, const char *direction)
1057 {
1058 mbim_debug("%s NwError = %u", direction, le32toh(pInfo->NwError));
1059 mbim_debug("%s PacketServiceState = %s", direction, MBIMPacketServiceStateStr(le32toh(pInfo->PacketServiceState)));
1060 mbim_debug("%s HighestAvailableDataClass = %s", direction, MBIMDataClassStr(le32toh(pInfo->HighestAvailableDataClass)));
1061 mbim_debug("%s UplinkSpeed = %ld", direction, (long)le64toh(pInfo->UplinkSpeed));
1062 mbim_debug("%s DownlinkSpeed = %ld", direction, (long)le64toh(pInfo->DownlinkSpeed));
1063 }
1064
mbim_dump_subscriber_status(MBIM_SUBSCRIBER_READY_STATUS_T * pInfo,const char * direction)1065 static void mbim_dump_subscriber_status(MBIM_SUBSCRIBER_READY_STATUS_T *pInfo, const char *direction)
1066 {
1067 mbim_debug("%s ReadyState = %s", direction, MBIMSubscriberReadyStateStr(le32toh(pInfo->ReadyState)));
1068 mbim_debug("%s SIMICCID = %s", direction, mbim_get_segment(pInfo, le32toh(pInfo->SimIccIdOffset), le32toh(pInfo->SimIccIdSize)));
1069 mbim_debug("%s SubscriberID = %s", direction, mbim_get_segment(pInfo, le32toh(pInfo->SubscriberIdOffset), le32toh(pInfo->SubscriberIdSize)));
1070 /* maybe more than one number */
1071 uint32_t idx;
1072 for (idx = 0; idx < le32toh(pInfo->ElementCount); idx++) {
1073 UINT32 offset = ((UINT32*)((UINT8*)pInfo+offsetof(MBIM_SUBSCRIBER_READY_STATUS_T, TelephoneNumbersRefList)))[0];
1074 UINT32 length = ((UINT32*)((UINT8*)pInfo+offsetof(MBIM_SUBSCRIBER_READY_STATUS_T, TelephoneNumbersRefList)))[1];
1075 mbim_debug("%s Number = %s", direction, mbim_get_segment(pInfo, le32toh(offset), le32toh(length)));
1076 }
1077 }
1078
mbim_dump_regiester_status(MBIM_REGISTRATION_STATE_INFO_T * pInfo,const char * direction)1079 static void mbim_dump_regiester_status(MBIM_REGISTRATION_STATE_INFO_T *pInfo, const char *direction)
1080 {
1081 mbim_debug("%s NwError = %u", direction, le32toh(pInfo->NwError));
1082 mbim_debug("%s RegisterState = %s", direction, MBIMRegisterStateStr(le32toh(pInfo->RegisterState)));
1083 mbim_debug("%s RegisterMode = %s", direction, MBIMRegisterModeStr(le32toh(pInfo->RegisterMode)));
1084 }
1085
mbim_dump_ipconfig(MBIM_IP_CONFIGURATION_INFO_T * pInfo,const char * direction)1086 static void mbim_dump_ipconfig(MBIM_IP_CONFIGURATION_INFO_T *pInfo, const char *direction)
1087 {
1088 UINT8 prefix = 0, *ipv4=NULL, *ipv6=NULL, *gw=NULL, *dns1=NULL, *dns2=NULL;
1089
1090 mbim_debug("%s SessionId = %u", direction, le32toh(pInfo->SessionId));
1091 mbim_debug("%s IPv4ConfigurationAvailable = 0x%x", direction, le32toh(pInfo->IPv4ConfigurationAvailable));
1092 mbim_debug("%s IPv6ConfigurationAvailable = 0x%x", direction, le32toh(pInfo->IPv6ConfigurationAvailable));
1093 mbim_debug("%s IPv4AddressCount = 0x%x", direction, le32toh(pInfo->IPv4AddressCount));
1094 mbim_debug("%s IPv4AddressOffset = 0x%x", direction, le32toh(pInfo->IPv4AddressOffset));
1095 mbim_debug("%s IPv6AddressCount = 0x%x", direction, le32toh(pInfo->IPv6AddressCount));
1096 mbim_debug("%s IPv6AddressOffset = 0x%x", direction, le32toh(pInfo->IPv6AddressOffset));
1097
1098 /* IPv4 */
1099 if (le32toh(pInfo->IPv4ConfigurationAvailable)&0x1) {
1100 MBIM_IPV4_ELEMENT_T *pAddress = (MBIM_IPV4_ELEMENT_T *)(&pInfo->DataBuffer[le32toh(pInfo->IPv4AddressOffset)-sizeof(MBIM_IP_CONFIGURATION_INFO_T)]);
1101 prefix = le32toh(pAddress->OnLinkPrefixLength);
1102 ipv4 = pAddress->IPv4Address;
1103 mbim_debug("%s IPv4 = %u.%u.%u.%u/%u", direction, ipv4[0], ipv4[1], ipv4[2], ipv4[3], prefix);
1104 }
1105 if (le32toh(pInfo->IPv4ConfigurationAvailable)&0x2) {
1106 gw = (UINT8 *)(&pInfo->DataBuffer[le32toh(pInfo->IPv4GatewayOffset)-sizeof(MBIM_IP_CONFIGURATION_INFO_T)]);
1107 mbim_debug("%s gw = %u.%u.%u.%u", direction, gw[0], gw[1], gw[2], gw[3]);
1108 }
1109 if (le32toh(pInfo->IPv4ConfigurationAvailable)&0x3) {
1110 dns1 = (UINT8 *)(&pInfo->DataBuffer[le32toh(pInfo->IPv4DnsServerOffset) -sizeof(MBIM_IP_CONFIGURATION_INFO_T)]);
1111 mbim_debug("%s dns1 = %u.%u.%u.%u", direction, dns1[0], dns1[1], dns1[2], dns1[3]);
1112 if (le32toh(pInfo->IPv4DnsServerCount) == 2) {
1113 dns2 = dns1 + 4;
1114 mbim_debug("%s dns2 = %u.%u.%u.%u", direction, dns2[0], dns2[1], dns2[2], dns2[3]);
1115 }
1116 }
1117 if (le32toh(pInfo->IPv4Mtu)) mbim_debug("%s ipv4 mtu = %u", direction, le32toh(pInfo->IPv4Mtu));
1118
1119 /* IPv6 */
1120 if (le32toh(pInfo->IPv6ConfigurationAvailable)&0x1) {
1121 MBIM_IPV6_ELEMENT_T *pAddress = (MBIM_IPV6_ELEMENT_T *)(&pInfo->DataBuffer[le32toh(pInfo->IPv6AddressOffset)-sizeof(MBIM_IP_CONFIGURATION_INFO_T)]);
1122 prefix = le32toh(pAddress->OnLinkPrefixLength);
1123 ipv6 = pAddress->IPv6Address;
1124 mbim_debug("%s IPv6 = %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x/%d", \
1125 direction, ipv6[0], ipv6[1], ipv6[2], ipv6[3], ipv6[4], ipv6[5], ipv6[6], ipv6[7], \
1126 ipv6[8], ipv6[9], ipv6[10], ipv6[11], ipv6[12], ipv6[13], ipv6[14], ipv6[15], prefix);
1127 }
1128 if (le32toh(pInfo->IPv6ConfigurationAvailable)&0x2) {
1129 gw = (UINT8 *)(&pInfo->DataBuffer[le32toh(pInfo->IPv6GatewayOffset)-sizeof(MBIM_IP_CONFIGURATION_INFO_T)]);
1130 mbim_debug("%s gw = %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x", \
1131 direction, gw[0], gw[1], gw[2], gw[3], gw[4], gw[5], gw[6], gw[7], \
1132 gw[8], gw[9], gw[10], gw[11], gw[12], gw[13], gw[14], gw[15]);
1133 }
1134 if (le32toh(pInfo->IPv6ConfigurationAvailable)&0x3) {
1135 dns1 = (UINT8 *)(&pInfo->DataBuffer[le32toh(pInfo->IPv6DnsServerOffset)-sizeof(MBIM_IP_CONFIGURATION_INFO_T)]);
1136 mbim_debug("%s dns1 = %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x", \
1137 direction, dns1[0], dns1[1], dns1[2], dns1[3], dns1[4], dns1[5], dns1[6], dns1[7], \
1138 dns1[8], dns1[9], dns1[10], dns1[11], dns1[12], dns1[13], dns1[14], dns1[15]);
1139 if (le32toh(pInfo->IPv6DnsServerCount) == 2) {
1140 dns2 = dns1 + 16;
1141 mbim_debug("%s dns2 = %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x", \
1142 direction, dns2[0], dns2[1], dns2[2], dns2[3], dns1[4], dns1[5], dns1[6], dns1[7],
1143 dns2[8], dns2[9], dns2[10], dns2[11], dns2[12], dns2[13], dns2[14], dns2[15]);
1144 }
1145 }
1146 if (le32toh(pInfo->IPv6Mtu)) mbim_debug("%s ipv6 mtu = %u", direction, le32toh(pInfo->IPv6Mtu));
1147 }
1148
mbim_dump(MBIM_MESSAGE_HEADER * pMsg,int mbim_verbose)1149 static void mbim_dump(MBIM_MESSAGE_HEADER *pMsg, int mbim_verbose) {
1150 unsigned char *data = (unsigned char *)pMsg;
1151 const char *direction = (le32toh(pMsg->MessageType) & 0x80000000) ? "<" : ">";
1152
1153 if (!mbim_verbose)
1154 return;
1155
1156 if (mbim_verbose) {
1157 unsigned i;
1158 static char *_tmp = NULL;
1159
1160 if (!_tmp)
1161 _tmp = (char *)malloc(4096);
1162
1163 if (_tmp) {
1164 _tmp[0] = (le32toh(pMsg->MessageType) & 0x80000000) ? '<' : '>';
1165 _tmp[1] = '\0';
1166 for (i = 0; i < le32toh(pMsg->MessageLength) && i < 4096; i++)
1167 snprintf(_tmp + strlen(_tmp), 4096 - strlen(_tmp), "%02X:", data[i]);
1168 mbim_debug("%s", _tmp);
1169 }
1170 }
1171
1172 mbim_dump_header(pMsg, direction);
1173
1174 switch (le32toh(pMsg->MessageType)) {
1175 case MBIM_OPEN_MSG: {
1176 MBIM_OPEN_MSG_T *pOpenMsg = (MBIM_OPEN_MSG_T *)pMsg;
1177 mbim_debug("%s MaxControlTransfer = %u", direction, le32toh(pOpenMsg->MaxControlTransfer));
1178 }
1179 break;
1180 case MBIM_OPEN_DONE: {
1181 MBIM_OPEN_DONE_T *pOpenDone = (MBIM_OPEN_DONE_T *)pMsg;
1182 mbim_debug("%s Status = %u", direction, le32toh(pOpenDone->Status));
1183 }
1184 break;
1185 case MBIM_CLOSE_MSG: {
1186
1187 }
1188 break;
1189 case MBIM_CLOSE_DONE: {
1190 MBIM_CLOSE_DONE_T *pCloseDone = (MBIM_CLOSE_DONE_T *)pMsg;
1191 mbim_debug("%s Status = %u", direction, le32toh(pCloseDone->Status));
1192 }
1193 break;
1194 case MBIM_COMMAND_MSG: {
1195 MBIM_COMMAND_MSG_T *pCmdMsg = (MBIM_COMMAND_MSG_T *)pMsg;
1196
1197 mbim_dump_command_msg(pCmdMsg, direction);
1198 if (!memcmp(pCmdMsg->DeviceServiceId.uuid, str2uuid(UUID_BASIC_CONNECT), 16)) {
1199 switch (le32toh(pCmdMsg->CID)) {
1200 case MBIM_CID_CONNECT: {
1201 MBIM_SET_CONNECT_T *pInfo = (MBIM_SET_CONNECT_T *)pCmdMsg->InformationBuffer;
1202 mbim_debug("%s SessionId = %u", direction, le32toh(pInfo->SessionId));
1203 }
1204 break;
1205 case MBIM_CID_IP_CONFIGURATION: {
1206 MBIM_IP_CONFIGURATION_INFO_T *pInfo = (MBIM_IP_CONFIGURATION_INFO_T *)pCmdMsg->InformationBuffer;
1207 mbim_debug("%s SessionId = %u", direction, le32toh(pInfo->SessionId));
1208 }
1209 break;
1210 default:
1211 break;
1212 }
1213 }
1214 }
1215 break;
1216 case MBIM_COMMAND_DONE: {
1217 MBIM_COMMAND_DONE_T *pCmdDone = (MBIM_COMMAND_DONE_T *)pMsg;
1218
1219 mbim_dump_command_done(pCmdDone, direction);
1220 if (le32toh(pCmdDone->InformationBufferLength) == 0)
1221 return;
1222
1223 if (!memcmp(pCmdDone->DeviceServiceId.uuid, str2uuid(UUID_BASIC_CONNECT), 16)) {
1224 switch (le32toh(pCmdDone->CID)) {
1225 case MBIM_CID_CONNECT: {
1226 MBIM_CONNECT_T *pInfo = (MBIM_CONNECT_T *)pCmdDone->InformationBuffer;
1227 mbim_dump_connect(pInfo, direction);
1228 }
1229 break;
1230 case MBIM_CID_IP_CONFIGURATION: {
1231 //MBIM_IP_CONFIGURATION_INFO_T *pInfo = (MBIM_IP_CONFIGURATION_INFO_T *)pCmdDone->InformationBuffer;
1232 //mbim_dump_ipconfig(pInfo, direction);
1233 }
1234 break;
1235 case MBIM_CID_PACKET_SERVICE: {
1236 MBIM_PACKET_SERVICE_INFO_T *pInfo = (MBIM_PACKET_SERVICE_INFO_T *)pCmdDone->InformationBuffer;
1237 mbim_dump_packet_service(pInfo, direction);
1238 }
1239 break;
1240 case MBIM_CID_SUBSCRIBER_READY_STATUS: {
1241 MBIM_SUBSCRIBER_READY_STATUS_T *pInfo = (MBIM_SUBSCRIBER_READY_STATUS_T *)pCmdDone->InformationBuffer;
1242 mbim_dump_subscriber_status(pInfo, direction);
1243 }
1244 break;
1245 case MBIM_CID_REGISTER_STATE: {
1246 MBIM_REGISTRATION_STATE_INFO_T *pInfo = (MBIM_REGISTRATION_STATE_INFO_T *)pCmdDone->InformationBuffer;
1247 mbim_dump_regiester_status(pInfo, direction);
1248 }
1249 break;
1250 default:
1251 break;
1252 }
1253 }
1254 }
1255 break;
1256 case MBIM_INDICATE_STATUS_MSG: {
1257 MBIM_INDICATE_STATUS_MSG_T *pIndMsg = (MBIM_INDICATE_STATUS_MSG_T *)pMsg;
1258
1259 mbim_dump_indicate_msg(pIndMsg, direction);
1260 if (le32toh(pIndMsg->InformationBufferLength) == 0)
1261 return;
1262
1263 if (!memcmp(pIndMsg->DeviceServiceId.uuid, str2uuid(UUID_BASIC_CONNECT), 16)) {
1264 switch (le32toh(pIndMsg->CID)) {
1265 case MBIM_CID_CONNECT: {
1266 MBIM_CONNECT_T *pInfo = (MBIM_CONNECT_T *)pIndMsg->InformationBuffer;
1267 mbim_dump_connect(pInfo, direction);
1268 }
1269 break;
1270 case MBIM_CID_SIGNAL_STATE: {
1271 MBIM_SIGNAL_STATE_INFO_T *pInfo = (MBIM_SIGNAL_STATE_INFO_T *)pIndMsg->InformationBuffer;
1272 mbim_dump_signal_state(pInfo, direction);
1273 }
1274 break;
1275 case MBIM_CID_SUBSCRIBER_READY_STATUS: {
1276 MBIM_SUBSCRIBER_READY_STATUS_T *pInfo = (MBIM_SUBSCRIBER_READY_STATUS_T *)pIndMsg->InformationBuffer;
1277 mbim_dump_subscriber_status(pInfo, direction);
1278 }
1279 break;
1280 case MBIM_CID_REGISTER_STATE: {
1281 MBIM_REGISTRATION_STATE_INFO_T *pInfo = (MBIM_REGISTRATION_STATE_INFO_T *)pIndMsg->InformationBuffer;
1282 mbim_dump_regiester_status(pInfo, direction);
1283 }
1284 break;
1285 case MBIM_CID_PACKET_SERVICE: {
1286 MBIM_PACKET_SERVICE_INFO_T *pInfo = (MBIM_PACKET_SERVICE_INFO_T *)pIndMsg->InformationBuffer;
1287 mbim_dump_packet_service(pInfo, direction);
1288 }
1289 break;
1290 default:
1291 break;
1292 }
1293 }
1294 else if (!memcmp(pIndMsg->DeviceServiceId.uuid, str2uuid(UUID_BASIC_CONNECT_EXT), 16)) {
1295 }
1296 }
1297 break;
1298 case MBIM_FUNCTION_ERROR_MSG: {
1299 MBIM_FUNCTION_ERROR_MSG_T *pErrMsg = (MBIM_FUNCTION_ERROR_MSG_T*)pMsg;
1300 mbim_debug("%s ErrorStatusCode = %u", direction, le32toh(pErrMsg->ErrorStatusCode));
1301 }
1302 break;
1303 default:
1304 break;
1305 }
1306 }
1307
mbim_recv_command(MBIM_MESSAGE_HEADER * pResponse,unsigned size)1308 static void mbim_recv_command(MBIM_MESSAGE_HEADER *pResponse, unsigned size)
1309 {
1310 (void)size;
1311 pthread_mutex_lock(&cm_command_mutex);
1312
1313 if (pResponse)
1314 mbim_dump(pResponse, mbim_verbose);
1315
1316 if (pResponse == NULL) {
1317 pthread_cond_signal(&cm_command_cond);
1318 }
1319 else if (mbim_pRequest && le32toh(mbim_pRequest->TransactionId) == le32toh(pResponse->TransactionId)) {
1320 mbim_pResponse = mbim_alloc(le32toh(pResponse->MessageLength));
1321 if (mbim_pResponse)
1322 memcpy(mbim_pResponse, pResponse, le32toh(pResponse->MessageLength));
1323 pthread_cond_signal(&cm_command_cond);
1324 }
1325 else if (le32toh(pResponse->MessageType) == MBIM_INDICATE_STATUS_MSG) {
1326 MBIM_INDICATE_STATUS_MSG_T *pIndMsg = (MBIM_INDICATE_STATUS_MSG_T *)pResponse;
1327
1328 if (!memcmp(pIndMsg->DeviceServiceId.uuid, str2uuid(UUID_BASIC_CONNECT), 16))
1329 {
1330 switch (le32toh(pIndMsg->CID)) {
1331 case MBIM_CID_SUBSCRIBER_READY_STATUS: {
1332 MBIM_SUBSCRIBER_READY_STATUS_T *pInfo = (MBIM_SUBSCRIBER_READY_STATUS_T *)pIndMsg->InformationBuffer;
1333 if (oldReadyState != le32toh(pInfo->ReadyState))
1334 qmidevice_send_event_to_main(RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED);
1335 }
1336 break;
1337 case MBIM_CID_REGISTER_STATE: {
1338 MBIM_REGISTRATION_STATE_INFO_T *pInfo = (MBIM_REGISTRATION_STATE_INFO_T *)pIndMsg->InformationBuffer;
1339 if (oldRegisterState != le32toh(pInfo->RegisterState))
1340 qmidevice_send_event_to_main(RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED);
1341 }
1342 break;
1343 case MBIM_CID_PACKET_SERVICE: {
1344 MBIM_PACKET_SERVICE_INFO_T *pInfo = (MBIM_PACKET_SERVICE_INFO_T *)pIndMsg->InformationBuffer;
1345 MBIM_PACKET_SERVICE_STATE_E state = le32toh(pInfo->PacketServiceState);
1346
1347 if (oldPacketServiceState != state
1348 && (1 || MBIMPacketServiceStateAttached == state || MBIMPacketServiceStateDetached == state))
1349 qmidevice_send_event_to_main(RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED);
1350 }
1351 break;
1352 case MBIM_CID_CONNECT: {
1353 MBIM_CONNECT_T *pInfo = (MBIM_CONNECT_T *)pIndMsg->InformationBuffer;
1354 if (pInfo->SessionId == (uint32_t)mbim_sessionID) {
1355 MBIM_ACTIVATION_STATE_E state = le32toh(pInfo->ActivationState);
1356
1357 if (oldActivationState != state
1358 && (1 || MBIMActivationStateActivated == state || MBIMActivationStateDeactivated == state))
1359 qmidevice_send_event_to_main(RIL_UNSOL_DATA_CALL_LIST_CHANGED);
1360 }
1361 }
1362 break;
1363 default:
1364 break;
1365 }
1366 }
1367 }
1368
1369 pthread_mutex_unlock(&cm_command_mutex);
1370 }
1371
mbim_send_command(MBIM_MESSAGE_HEADER * pRequest,MBIM_COMMAND_DONE_T ** ppCmdDone,unsigned msecs)1372 static int mbim_send_command(MBIM_MESSAGE_HEADER *pRequest, MBIM_COMMAND_DONE_T **ppCmdDone, unsigned msecs) {
1373 int ret;
1374
1375 if (ppCmdDone)
1376 *ppCmdDone = NULL;
1377
1378 if (mbim_fd <= 0)
1379 return -ENODEV;
1380
1381 if (s_tid_reader == 0)
1382 return -EINVAL;
1383
1384 if (!pRequest)
1385 return -ENOMEM;
1386
1387 pthread_mutex_lock(&cm_command_mutex);
1388
1389 if (pRequest) {
1390 if (pRequest->TransactionId == (0xFFFFFF + 1)) { //mbim-proxy need 0xFF000000 to indicat client
1391 TransactionId = 1;
1392 pRequest->TransactionId = htole32(TransactionId++);
1393 }
1394 mbim_dump(pRequest, mbim_verbose);
1395 }
1396
1397 mbim_pRequest = pRequest;
1398 mbim_pResponse = NULL;
1399
1400 ret = write(mbim_fd, pRequest, le32toh(pRequest->MessageLength));
1401
1402 if (ret > 0 && (uint32_t)ret == le32toh(pRequest->MessageLength)) {
1403 ret = pthread_cond_timeout_np(&cm_command_cond, &cm_command_mutex, msecs);
1404 if (!ret) {
1405 if (mbim_pResponse && ppCmdDone) {
1406 *ppCmdDone = (MBIM_COMMAND_DONE_T *)mbim_pResponse;
1407 }
1408 }
1409 } else {
1410 mbim_debug("%s pthread_cond_timeout_np=%d", __func__, ret);
1411 }
1412
1413 mbim_pRequest = mbim_pResponse = NULL;
1414
1415 pthread_mutex_unlock(&cm_command_mutex);
1416
1417 return ret;
1418 }
1419
mbim_proxy_read(int fd,MBIM_MESSAGE_HEADER * pResponse,size_t size)1420 static ssize_t mbim_proxy_read (int fd, MBIM_MESSAGE_HEADER *pResponse, size_t size) {
1421 ssize_t nreads;
1422
1423 nreads = read(fd, pResponse, sizeof(MBIM_MESSAGE_HEADER));
1424 if (nreads == sizeof(MBIM_MESSAGE_HEADER) && le32toh(pResponse->MessageLength) <= size) {
1425 nreads += read(fd, pResponse+1, le32toh(pResponse->MessageLength) - sizeof(MBIM_MESSAGE_HEADER));
1426 }
1427
1428 return nreads;
1429 }
1430
mbim_read_thread(void * param)1431 static void * mbim_read_thread(void *param) {
1432 PROFILE_T *profile = (PROFILE_T *)param;
1433 const char *cdc_wdm = (const char *)profile->qmichannel;
1434 int wait_for_request_quit = 0;
1435
1436 mbim_verbose = debug_qmi;
1437 s_tid_reader = pthread_self();
1438
1439 if (profile->qmap_mode > 1 && profile->qmapnet_adapter[0]) {
1440 if (!profile->proxy[0])
1441 sprintf(profile->proxy, "%s", QUECTEL_MBIM_PROXY);
1442 mbim_sessionID = profile->pdp;
1443 }
1444
1445 if (profile->proxy[0]) {
1446 mbim_fd = cm_open_proxy(profile->proxy);
1447 }
1448 else {
1449 mbim_fd = cm_open_dev(cdc_wdm);
1450 }
1451
1452 if (mbim_fd <= 0) {
1453 mbim_debug("fail to open (%s), errno: %d (%s)", cdc_wdm, errno, strerror(errno));
1454 goto __quit;
1455 }
1456
1457 dbg_time("cdc_wdm_fd = %d", mbim_fd);
1458
1459 qmidevice_send_event_to_main(RIL_INDICATE_DEVICE_CONNECTED);
1460
1461 while (mbim_fd > 0) {
1462 struct pollfd pollfds[] = {{mbim_fd, POLLIN, 0}, {qmidevice_control_fd[1], POLLIN, 0}};
1463 int ne, ret, nevents = 2;
1464
1465 ret = poll(pollfds, nevents, wait_for_request_quit ? 1000 : -1);
1466
1467 if (ret == 0 && wait_for_request_quit) {
1468 break;
1469 }
1470
1471 if (ret < 0) {
1472 mbim_debug("%s poll=%d, errno: %d (%s)", __func__, ret, errno, strerror(errno));
1473 break;
1474 }
1475
1476 for (ne = 0; ne < nevents; ne++) {
1477 int fd = pollfds[ne].fd;
1478 short revents = pollfds[ne].revents;
1479
1480 if (revents & (POLLERR | POLLHUP | POLLNVAL)) {
1481 mbim_debug("%s poll err/hup/inval", __func__);
1482 mbim_debug("epoll fd = %d, events = 0x%04x", fd, revents);
1483 if (revents & (POLLERR | POLLHUP | POLLNVAL))
1484 goto __quit;
1485 }
1486
1487 if ((revents & POLLIN) == 0)
1488 continue;
1489
1490 if (mbim_fd == fd) {
1491 ssize_t nreads;
1492 MBIM_MESSAGE_HEADER *pResponse = (MBIM_MESSAGE_HEADER *) cm_recv_buf;
1493
1494 if (profile->proxy[0])
1495 nreads = mbim_proxy_read(fd, pResponse, sizeof(cm_recv_buf));
1496 else
1497 nreads = read(fd, pResponse, sizeof(cm_recv_buf));
1498
1499 if (nreads <= 0) {
1500 mbim_debug("%s read=%d errno: %d (%s)", __func__, (int)nreads, errno, strerror(errno));
1501 break;
1502 }
1503
1504 mbim_recv_command(pResponse, nreads);
1505 }
1506 else if (fd == qmidevice_control_fd[1]) {
1507 int triger_event;
1508 if (read(fd, &triger_event, sizeof(triger_event)) == sizeof(triger_event)) {
1509 //mbim_debug("triger_event = 0x%x", triger_event);
1510 switch (triger_event) {
1511 case RIL_REQUEST_QUIT:
1512 goto __quit;
1513 break;
1514 case SIG_EVENT_STOP:
1515 wait_for_request_quit = 1;
1516 break;
1517 default:
1518 break;
1519 }
1520 }
1521 }
1522 }
1523 }
1524
1525 __quit:
1526 if (mbim_fd != -1) { close(mbim_fd); mbim_fd = -1; }
1527 mbim_recv_command(NULL, 0);
1528 qmidevice_send_event_to_main(RIL_INDICATE_DEVICE_DISCONNECTED);
1529 mbim_debug("%s exit", __func__);
1530 s_tid_reader = 0;
1531
1532 return NULL;
1533 }
1534
mbim_status_code(MBIM_MESSAGE_HEADER * pMsgHdr)1535 static int mbim_status_code(MBIM_MESSAGE_HEADER *pMsgHdr) {
1536 int status = 0;
1537
1538 if (!pMsgHdr)
1539 return 0;
1540
1541 switch (le32toh(pMsgHdr->MessageType)) {
1542 case MBIM_OPEN_DONE: {
1543 MBIM_OPEN_DONE_T *pOpenDone = (MBIM_OPEN_DONE_T *)pMsgHdr;
1544 status = le32toh(pOpenDone->Status);
1545 }
1546 break;
1547 case MBIM_CLOSE_DONE: {
1548 MBIM_CLOSE_DONE_T *pCloseDone = (MBIM_CLOSE_DONE_T *)pMsgHdr;
1549 status = le32toh(pCloseDone->Status);
1550 }
1551 break;
1552 case MBIM_COMMAND_DONE: {
1553 MBIM_COMMAND_DONE_T *pCmdDone = (MBIM_COMMAND_DONE_T *)pMsgHdr;
1554 status = le32toh(pCmdDone->Status);
1555 }
1556 break;
1557 case MBIM_FUNCTION_ERROR_MSG: {
1558 MBIM_FUNCTION_ERROR_MSG_T *pErrMsg = (MBIM_FUNCTION_ERROR_MSG_T *)pMsgHdr;
1559 status = le32toh(pErrMsg->ErrorStatusCode);
1560 if (status == MBIM_ERROR_NOT_OPENED)
1561 mbim_open_state = 0; //EM06ELAR03A05M4G when suspend/resume, may get this error
1562 }
1563 break;
1564 default:
1565 break;
1566 }
1567
1568 return status;
1569 }
1570
1571 #define mbim_check_err(err, pRequest, pCmdDone) do { \
1572 int _status = mbim_status_code(pCmdDone ? &pCmdDone->MessageHeader : NULL); \
1573 if (err || _status || !pCmdDone) { \
1574 if (pCmdDone) { mbim_dump(&pCmdDone->MessageHeader, (mbim_verbose == 0)); } \
1575 mbim_free(pRequest); mbim_free(pCmdDone); \
1576 mbim_debug("%s:%d err=%d, Status=%d", __func__, __LINE__, err, _status); \
1577 if (err) return err; if (_status) return _status; return 8888; \
1578 } \
1579 } while(0)
1580
1581 /*
1582 * MBIM device can be open repeatly without error
1583 * So, we can call the function, no matter it have been opened or not
1584 */
mbim_open_device(uint32_t MaxControlTransfer)1585 static int mbim_open_device(uint32_t MaxControlTransfer) {
1586 MBIM_MESSAGE_HEADER *pRequest = NULL;
1587 MBIM_OPEN_DONE_T *pOpenDone = NULL;
1588 int err = 0;
1589
1590 mbim_debug("%s()", __func__);
1591 pRequest = compose_open_command(MaxControlTransfer);
1592 err = mbim_send_command(pRequest, (MBIM_COMMAND_DONE_T **)&pOpenDone, 2*1000);
1593 mbim_check_err(err, pRequest, pOpenDone);
1594
1595 err = le32toh(pOpenDone->Status);
1596 mbim_free(pRequest); mbim_free(pOpenDone);
1597
1598 return err;
1599 }
1600
mbim_close_device(void)1601 static int mbim_close_device(void) {
1602 MBIM_MESSAGE_HEADER *pRequest = NULL;
1603 MBIM_CLOSE_DONE_T *pCloseDone = NULL;
1604 int err = 0;
1605
1606 mbim_debug("%s()", __func__);
1607 pRequest = compose_close_command();
1608 err = mbim_send_command(pRequest, (MBIM_COMMAND_DONE_T **)&pCloseDone, mbim_default_timeout);
1609 mbim_check_err(err, pRequest, pCloseDone);
1610
1611 err = le32toh(pCloseDone->Status);
1612 mbim_free(pRequest); mbim_free(pCloseDone);
1613
1614 return err;
1615 }
1616
mbim_query_connect(int sessionID)1617 static int mbim_query_connect(int sessionID) {
1618 MBIM_MESSAGE_HEADER *pRequest = NULL;
1619 MBIM_COMMAND_DONE_T *pCmdDone = NULL;
1620 MBIM_SET_CONNECT_T set_connect;
1621 int err;
1622
1623 if (ActivationState != MBIMActivationStateActivated || mbim_verbose)
1624 mbim_debug("%s(sessionID=%d)", __func__, sessionID); //avoid two many log
1625 set_connect.SessionId = htole32(sessionID);
1626 pRequest = compose_basic_connect_command(MBIM_CID_CONNECT, MBIM_CID_CMD_TYPE_QUERY, &set_connect, sizeof(set_connect));
1627 err = mbim_send_command(pRequest, &pCmdDone, mbim_default_timeout);
1628 mbim_check_err(err, pRequest, pCmdDone);
1629
1630 if (le32toh(pCmdDone->InformationBufferLength))
1631 {
1632 MBIM_CONNECT_T *pInfo = (MBIM_CONNECT_T *)pCmdDone->InformationBuffer;
1633 ActivationState = le32toh(pInfo->ActivationState);
1634 mbim_update_state();
1635 }
1636 mbim_free(pRequest); mbim_free(pCmdDone);
1637 return err;
1638 }
1639
mbim_ms_version_query(void)1640 static int mbim_ms_version_query(void) {
1641 MBIM_MESSAGE_HEADER *pRequest = NULL;
1642 MBIM_COMMAND_DONE_T *pCmdDone = NULL;
1643 int err;
1644
1645 struct _bc_ext_version {
1646 UINT8 ver_minor;
1647 UINT8 ver_major;
1648 UINT8 ext_ver_minor;
1649 UINT8 ext_ver_major;
1650 } __attribute__ ((packed)) bc_ext_version;
1651
1652 bc_ext_version.ver_major = 1;
1653 bc_ext_version.ver_minor = 0;
1654 bc_ext_version.ext_ver_major = 2;
1655 bc_ext_version.ext_ver_minor = 0;
1656
1657 pRequest = compose_basic_connect_ext_command(MBIM_CID_MS_VERSION, MBIM_CID_CMD_TYPE_QUERY, &bc_ext_version, sizeof(bc_ext_version));
1658 err = mbim_send_command(pRequest, &pCmdDone, mbim_default_timeout);
1659 mbim_check_err(err, pRequest, pCmdDone);
1660
1661 if (le32toh(pCmdDone->InformationBufferLength)) {
1662 struct _bc_ext_version *pInfo = (struct _bc_ext_version *)pCmdDone->InformationBuffer;
1663 //mbim_debug("%s ext_rel_ver major=%d, minor=%d", __func__, pInfo->ext_ver_major, pInfo->ext_ver_minor);
1664 mbim_ms_version = pInfo->ext_ver_major;
1665 }
1666
1667 mbim_free(pRequest); mbim_free(pCmdDone);
1668 return err;
1669 }
1670
mbim_device_services_query(void)1671 static int mbim_device_services_query(void) {
1672 MBIM_MESSAGE_HEADER *pRequest = NULL;
1673 MBIM_COMMAND_DONE_T *pCmdDone = NULL;
1674 int err;
1675 int mbim_v2_support = 0;
1676
1677 mbim_debug("%s()", __func__);
1678 pRequest = compose_basic_connect_command(MBIM_CID_DEVICE_SERVICES, MBIM_CID_CMD_TYPE_QUERY, NULL, 0);
1679 err = mbim_send_command(pRequest, &pCmdDone, mbim_default_timeout);
1680 mbim_check_err(err, pRequest, pCmdDone);
1681
1682 if (pCmdDone->InformationBufferLength) {
1683 MBIM_DEVICE_SERVICES_INFO_T *pInfo = (MBIM_DEVICE_SERVICES_INFO_T *)pCmdDone->InformationBuffer;
1684 UINT32 i;
1685
1686 for (i = 0; i < le32toh(pInfo->DeviceServicesCount) ; i++) {
1687 //UINT32 size = pInfo->DeviceServicesRefList[i].size;
1688 UINT32 offset = le32toh(pInfo->DeviceServicesRefList[i].offset);
1689 MBIM_DEVICE_SERVICE_ELEMENT_T *pSrvEle = (MBIM_DEVICE_SERVICE_ELEMENT_T *)((void *)pInfo + offset);
1690
1691 if (!strcasecmp(UUID_BASIC_CONNECT_EXT, uuid2str(&pSrvEle->DeviceServiceId))) {
1692 UINT32 cid = 0;
1693
1694 for (cid = 0; cid < le32toh(pSrvEle->CidCount); cid++) {
1695 if (MBIM_CID_MS_VERSION == le32toh(pSrvEle->CidList[cid])) {
1696 mbim_v2_support = 1;
1697 }
1698 }
1699 }
1700 }
1701 }
1702 mbim_free(pRequest); mbim_free(pCmdDone);
1703
1704 if (mbim_v2_support) {
1705 mbim_ms_version_query();
1706 }
1707
1708 return err;
1709 }
1710
mbim_device_caps_query(PROFILE_T * profile)1711 static int mbim_device_caps_query(PROFILE_T *profile) {
1712 MBIM_MESSAGE_HEADER *pRequest = NULL;
1713 MBIM_COMMAND_DONE_T *pCmdDone = NULL;
1714 int err;
1715
1716 mbim_debug("%s()", __func__);
1717 pRequest = compose_basic_connect_command(MBIM_CID_DEVICE_CAPS, MBIM_CID_CMD_TYPE_QUERY, NULL, 0);
1718 err = mbim_send_command(pRequest, &pCmdDone, mbim_default_timeout);
1719 mbim_check_err(err, pRequest, pCmdDone);
1720
1721 if (le32toh(pCmdDone->InformationBufferLength)) {
1722 MBIM_DEVICE_CAPS_INFO_T *pInfo = (MBIM_DEVICE_CAPS_INFO_T *)pCmdDone->InformationBuffer;
1723 char tmp[32];
1724
1725 if (le32toh(pInfo->DeviceIdOffset) && le32toh(pInfo->DeviceIdSize)) {
1726 wchar2char((const char *)pInfo + le32toh(pInfo->DeviceIdOffset), le32toh(pInfo->DeviceIdSize), tmp, sizeof(tmp));
1727 mbim_debug("DeviceId: %s", tmp);
1728 }
1729 if (le32toh(pInfo->FirmwareInfoOffset) && le32toh(pInfo->FirmwareInfoSize)) {
1730 wchar2char((const char *)pInfo + le32toh(pInfo->FirmwareInfoOffset), le32toh(pInfo->FirmwareInfoSize), tmp, sizeof(tmp));
1731 strncpy(profile->BaseBandVersion, tmp, sizeof(profile->BaseBandVersion));
1732 mbim_debug("FirmwareInfo: %s", tmp);
1733 }
1734 if (le32toh(pInfo->HardwareInfoOffset) && le32toh(pInfo->HardwareInfoSize)) {
1735 wchar2char((const char *)pInfo + le32toh(pInfo->HardwareInfoOffset), le32toh(pInfo->HardwareInfoSize), tmp, sizeof(tmp));
1736 mbim_debug("HardwareInfo: %s", tmp);
1737 }
1738 }
1739 mbim_free(pRequest); mbim_free(pCmdDone);
1740 return err;
1741 }
1742
1743 #if 0
1744 static int mbim_radio_state_query(void) {
1745 MBIM_MESSAGE_HEADER *pRequest = NULL;
1746 MBIM_COMMAND_DONE_T *pCmdDone = NULL;
1747 int err;
1748
1749 mbim_debug("%s()", __func__);
1750 pRequest = compose_basic_connect_command(MBIM_CID_RADIO_STATE, MBIM_CID_CMD_TYPE_QUERY, NULL, 0);
1751 err = mbim_send_command(pRequest, &pCmdDone, mbim_default_timeout);
1752 mbim_check_err(err, pRequest, pCmdDone);
1753
1754 if (pCmdDone->InformationBufferLength) {
1755 MBIM_RADIO_STATE_INFO_T *pInfo = (MBIM_RADIO_STATE_INFO_T *)pCmdDone->InformationBuffer;
1756 mbim_debug("HwRadioState: %d, SwRadioState: %d", pInfo->HwRadioState, pInfo->SwRadioState);
1757 }
1758 mbim_free(pRequest); mbim_free(pCmdDone);
1759 return err;
1760 }
1761 #endif
1762
mbim_set_radio_state(MBIM_RADIO_SWITCH_STATE_E RadioState)1763 static int mbim_set_radio_state(MBIM_RADIO_SWITCH_STATE_E RadioState) {
1764 MBIM_MESSAGE_HEADER *pRequest = NULL;
1765 MBIM_COMMAND_DONE_T *pCmdDone = NULL;
1766 UINT32 value = htole32(RadioState);
1767 int err;
1768
1769 mbim_debug("%s( %d )", __func__, RadioState);
1770 pRequest = compose_basic_connect_command(MBIM_CID_RADIO_STATE, MBIM_CID_CMD_TYPE_SET, &value, sizeof(value));
1771 err = mbim_send_command(pRequest, &pCmdDone, mbim_default_timeout);
1772 mbim_check_err(err, pRequest, pCmdDone);
1773
1774 if (le32toh(pCmdDone->InformationBufferLength)) {
1775 MBIM_RADIO_STATE_INFO_T *pInfo = (MBIM_RADIO_STATE_INFO_T *)pCmdDone->InformationBuffer;
1776 mbim_debug("HwRadioState: %d, SwRadioState: %d", le32toh(pInfo->HwRadioState), le32toh(pInfo->SwRadioState));
1777 }
1778 mbim_free(pRequest); mbim_free(pCmdDone);
1779 return err;
1780 }
1781
mbim_subscriber_status_query(void)1782 static int mbim_subscriber_status_query(void) {
1783 MBIM_MESSAGE_HEADER *pRequest = NULL;
1784 MBIM_COMMAND_DONE_T *pCmdDone = NULL;
1785 int err;
1786
1787 mbim_debug("%s()", __func__);
1788 pRequest = compose_basic_connect_command(MBIM_CID_SUBSCRIBER_READY_STATUS, MBIM_CID_CMD_TYPE_QUERY, NULL, 0);
1789 err = mbim_send_command(pRequest, &pCmdDone, mbim_default_timeout);
1790 mbim_check_err(err, pRequest, pCmdDone);
1791
1792 if (le32toh(pCmdDone->InformationBufferLength)) {
1793 MBIM_SUBSCRIBER_READY_STATUS_T *pInfo = (MBIM_SUBSCRIBER_READY_STATUS_T *)pCmdDone->InformationBuffer;
1794 char tmp[32];
1795
1796 wchar2char((const char *)pInfo + le32toh(pInfo->SubscriberIdOffset), le32toh(pInfo->SubscriberIdSize), tmp, sizeof(tmp));
1797 mbim_debug("SubscriberId: %s", tmp);
1798 wchar2char((const char *)pInfo + le32toh(pInfo->SimIccIdOffset), le32toh(pInfo->SimIccIdSize), tmp, sizeof(tmp));
1799 mbim_debug("SimIccId: %s", tmp);
1800 ReadyState = le32toh(pInfo->ReadyState);
1801 mbim_update_state();
1802 }
1803 mbim_free(pRequest); mbim_free(pCmdDone);
1804 return err;
1805 }
1806
mbim_register_state_query(void)1807 static int mbim_register_state_query(void) {
1808 MBIM_MESSAGE_HEADER *pRequest = NULL;
1809 MBIM_COMMAND_DONE_T *pCmdDone = NULL;
1810 int err;
1811
1812 mbim_debug("%s()", __func__);
1813 pRequest = compose_basic_connect_command(MBIM_CID_REGISTER_STATE, MBIM_CID_CMD_TYPE_QUERY, NULL, 0);
1814 err = mbim_send_command(pRequest, &pCmdDone, mbim_default_timeout);
1815 mbim_check_err(err, pRequest, pCmdDone);
1816
1817 if (le32toh(pCmdDone->InformationBufferLength)) {
1818 MBIM_REGISTRATION_STATE_INFO_T *pInfo = (MBIM_REGISTRATION_STATE_INFO_T *)pCmdDone->InformationBuffer;;
1819 RegisterState = le32toh(pInfo->RegisterState);
1820 mbim_update_state();
1821 }
1822 mbim_free(pRequest); mbim_free(pCmdDone);
1823 return err;
1824 }
1825
mbim_packet_service_query(void)1826 static int mbim_packet_service_query(void) {
1827 MBIM_MESSAGE_HEADER *pRequest = NULL;
1828 MBIM_COMMAND_DONE_T *pCmdDone = NULL;
1829 int err;
1830
1831 mbim_debug("%s()", __func__);
1832 pRequest = compose_basic_connect_command(MBIM_CID_PACKET_SERVICE, MBIM_CID_CMD_TYPE_QUERY, NULL, 0);
1833 err = mbim_send_command(pRequest, &pCmdDone, mbim_default_timeout);
1834 mbim_check_err(err, pRequest, pCmdDone);
1835
1836 if (le32toh(pCmdDone->InformationBufferLength)) {
1837 MBIM_PACKET_SERVICE_INFO_T *pInfo = (MBIM_PACKET_SERVICE_INFO_T *)pCmdDone->InformationBuffer;
1838 PacketServiceState = le32toh(pInfo->PacketServiceState);
1839 mbim_update_state();
1840
1841 if (le32toh(pCmdDone->InformationBufferLength) == sizeof(MBIM_PACKET_SERVICE_INFO_V2_T)) {
1842 MBIM_PACKET_SERVICE_INFO_V2_T *pInfo = (MBIM_PACKET_SERVICE_INFO_V2_T *)pCmdDone->InformationBuffer;
1843 mbim_debug("CurrentDataClass = %s", MBIMDataClassStr(le32toh(pInfo->CurrentDataClass)));
1844 }
1845 }
1846 mbim_free(pRequest); mbim_free(pCmdDone);
1847 return err;
1848 }
1849
mbim_packet_service_set(MBIM_PACKET_SERVICE_ACTION_E action)1850 static int mbim_packet_service_set(MBIM_PACKET_SERVICE_ACTION_E action) {
1851 MBIM_MESSAGE_HEADER *pRequest = NULL;
1852 MBIM_COMMAND_DONE_T *pCmdDone = NULL;
1853 UINT32 value = htole32(action);
1854 int err;
1855
1856 mbim_debug("%s()", __func__);
1857 pRequest = compose_basic_connect_command(MBIM_CID_PACKET_SERVICE, MBIM_CID_CMD_TYPE_SET, &value, sizeof(value));
1858 err = mbim_send_command(pRequest, &pCmdDone, mbim_default_timeout);
1859 mbim_check_err(err, pRequest, pCmdDone);
1860
1861 if (le32toh(pCmdDone->InformationBufferLength)) {
1862 MBIM_PACKET_SERVICE_INFO_T *pInfo = (MBIM_PACKET_SERVICE_INFO_T *)pCmdDone->InformationBuffer;
1863 PacketServiceState = le32toh(pInfo->PacketServiceState);
1864 mbim_update_state();
1865 }
1866 mbim_free(pRequest); mbim_free(pCmdDone);
1867 return err;
1868 }
1869
1870 #define _align_32(len) {len += (len % 4) ? (4 - (len % 4)) : 0;}
mbim_populate_connect_data(MBIM_SET_CONNECT_T ** connect_req_ptr)1871 static int mbim_populate_connect_data(MBIM_SET_CONNECT_T **connect_req_ptr) {
1872 int offset;
1873 int buflen = 0;
1874
1875 if (mbim_apn && strlen(mbim_apn) > 0) buflen += 2*strlen(mbim_apn) ;
1876 _align_32(buflen);
1877 if (mbim_user && strlen(mbim_user) > 0) buflen += 2*strlen(mbim_user);
1878 _align_32(buflen);
1879 if (mbim_passwd && strlen(mbim_passwd) > 0) buflen += 2*strlen(mbim_passwd);
1880 _align_32(buflen);
1881
1882 *connect_req_ptr = (MBIM_SET_CONNECT_T*)malloc(sizeof(MBIM_SET_CONNECT_T) + buflen);
1883 if (! *connect_req_ptr) {
1884 mbim_debug("not enough memory\n");
1885 return -1;
1886 }
1887 memset(*connect_req_ptr, 0, sizeof(MBIM_SET_CONNECT_T) + buflen);
1888
1889 offset = 0;
1890 if (mbim_apn && strlen(mbim_apn) > 0) {
1891 (*connect_req_ptr)->AccessStringSize = htole32(2*strlen(mbim_apn));
1892 (*connect_req_ptr)->AccessStringOffset = htole32(offset + sizeof(MBIM_SET_CONNECT_T));
1893 offset = char2wchar(mbim_apn, strlen(mbim_apn), &(*connect_req_ptr)->DataBuffer[offset], buflen - offset);
1894 _align_32(offset);
1895 }
1896
1897 if (mbim_user && strlen(mbim_user) > 0) {
1898 (*connect_req_ptr)->UserNameSize = htole32(2*strlen(mbim_user));
1899 (*connect_req_ptr)->UserNameOffset = htole32(offset + sizeof(MBIM_SET_CONNECT_T));
1900 offset = char2wchar(mbim_user, strlen(mbim_user), &(*connect_req_ptr)->DataBuffer[offset], buflen - offset);
1901 _align_32(offset);
1902 }
1903
1904 if (mbim_passwd && strlen(mbim_passwd) > 0) {
1905 (*connect_req_ptr)->PasswordSize = htole32(2*strlen(mbim_passwd));
1906 (*connect_req_ptr)->PasswordOffset = htole32(offset + sizeof(MBIM_SET_CONNECT_T));
1907 offset = char2wchar(mbim_passwd, strlen(mbim_passwd), &(*connect_req_ptr)->DataBuffer[offset], buflen - offset);
1908 }
1909
1910 return buflen;
1911 }
1912
mbim_set_connect(int onoff,int sessionID)1913 static int mbim_set_connect(int onoff, int sessionID) {
1914 MBIM_MESSAGE_HEADER *pRequest = NULL;
1915 MBIM_COMMAND_DONE_T *pCmdDone = NULL;
1916 MBIM_SET_CONNECT_T *set_connect = NULL;
1917 int err;
1918
1919 mbim_debug("%s(onoff=%d, sessionID=%d)", __func__, onoff, sessionID);
1920 /* alloc memory then populate APN USERNAME PASSWORD */
1921 int buflen = mbim_populate_connect_data(&set_connect);
1922 if (buflen < 0) {
1923 return ENOMEM;
1924 }
1925
1926 set_connect->SessionId = htole32(sessionID);
1927 if (onoff == 0)
1928 set_connect->ActivationCommand = htole32(MBIMActivationCommandDeactivate);
1929 else
1930 set_connect->ActivationCommand = htole32(MBIMActivationCommandActivate);
1931
1932 set_connect->Compression = htole32(MBIMCompressionNone);
1933 set_connect->AuthProtocol = htole32(mbim_auth);
1934 set_connect->IPType = htole32(mbim_iptype);
1935 memcpy(set_connect->ContextType.uuid, str2uuid(UUID_MBIMContextTypeInternet), 16);
1936
1937 pRequest = compose_basic_connect_command(MBIM_CID_CONNECT, MBIM_CID_CMD_TYPE_SET, set_connect, sizeof(MBIM_SET_CONNECT_T) + buflen);
1938 mbim_free(set_connect);
1939 err = mbim_send_command(pRequest, &pCmdDone, mbim_default_timeout*10);
1940 mbim_check_err(err, pRequest, pCmdDone);
1941
1942 if (le32toh(pCmdDone->InformationBufferLength)) {
1943 MBIM_CONNECT_T *pInfo = (MBIM_CONNECT_T *)pCmdDone->InformationBuffer;
1944 ActivationState = le32toh(pInfo->ActivationState);
1945 mbim_update_state();
1946 }
1947
1948 mbim_free(pRequest); mbim_free(pCmdDone);
1949 return err;
1950 }
1951
mbim_ip_config(PROFILE_T * profile,int sessionID)1952 static int mbim_ip_config(PROFILE_T *profile, int sessionID) {
1953 MBIM_MESSAGE_HEADER *pRequest = NULL;
1954 MBIM_COMMAND_DONE_T *pCmdDone = NULL;
1955 MBIM_IP_CONFIGURATION_INFO_T ip_info;
1956 int err;
1957
1958 if (profile->ipv4.Address == 0 || mbim_verbose)
1959 mbim_debug("%s(sessionID=%d)", __func__, sessionID);
1960 ip_info.SessionId = htole32(sessionID);
1961 pRequest = compose_basic_connect_command(MBIM_CID_IP_CONFIGURATION, MBIM_CID_CMD_TYPE_QUERY, &ip_info, sizeof(ip_info));
1962 err = mbim_send_command(pRequest, &pCmdDone, mbim_default_timeout);
1963 mbim_check_err(err, pRequest, pCmdDone);
1964
1965 if (le32toh(pCmdDone->InformationBufferLength)) {
1966 UINT8 prefix, *ipv4=NULL, *ipv6=NULL, *gw=NULL, *dns1=NULL, *dns2=NULL;
1967 UINT32 mtu = 1500;
1968 MBIM_IP_CONFIGURATION_INFO_T *pInfo = (MBIM_IP_CONFIGURATION_INFO_T *)pCmdDone->InformationBuffer;
1969
1970 /* IPv4 network configration */
1971 if (le32toh(pInfo->IPv4ConfigurationAvailable)&0x1) {
1972 MBIM_IPV4_ELEMENT_T *pAddress = (MBIM_IPV4_ELEMENT_T *)(&pInfo->DataBuffer[le32toh(pInfo->IPv4AddressOffset)-sizeof(MBIM_IP_CONFIGURATION_INFO_T)]);
1973 prefix = le32toh(pAddress->OnLinkPrefixLength);
1974 ipv4 = pAddress->IPv4Address;
1975
1976 if (le32toh(pInfo->IPv4ConfigurationAvailable)&0x2)
1977 gw = (UINT8 *)(&pInfo->DataBuffer[le32toh(pInfo->IPv4GatewayOffset)-sizeof(MBIM_IP_CONFIGURATION_INFO_T)]);
1978
1979 if (le32toh(pInfo->IPv4ConfigurationAvailable)&0x4) {
1980 dns1 = (UINT8 *)(&pInfo->DataBuffer[le32toh(pInfo->IPv4DnsServerOffset)-sizeof(MBIM_IP_CONFIGURATION_INFO_T)]);
1981 if (le32toh(pInfo->IPv4DnsServerCount) == 2)
1982 dns2 = dns1 + 4;
1983 }
1984
1985 if (le32toh(pInfo->IPv4ConfigurationAvailable)&0x8)
1986 mtu = le32toh(pInfo->IPv4Mtu);
1987
1988 if (profile->ipv4.Address != mbim2qmi_ipv4addr(*(uint32_t *)ipv4) || mbim_verbose) {
1989 mbim_dump_ipconfig(pInfo, "<");
1990 profile->ipv4.Address = mbim2qmi_ipv4addr(*(uint32_t *)ipv4);
1991 }
1992 profile->ipv4.Gateway = mbim2qmi_ipv4addr(*(uint32_t *)gw);
1993 profile->ipv4.SubnetMask = mbim2qmi_ipv4addr(0xFFFFFFFF>>(32-prefix)<<(32-prefix));
1994 profile->ipv4.DnsPrimary = mbim2qmi_ipv4addr(*(uint32_t *)dns1);
1995 profile->ipv4.DnsSecondary = mbim2qmi_ipv4addr(*(uint32_t *)dns2);
1996 profile->ipv4.Mtu = mbim2qmi_ipv4addr(mtu);
1997 }
1998
1999 /* IPv6 network configration */
2000 if (le32toh(pInfo->IPv6ConfigurationAvailable)&0x1) {
2001 MBIM_IPV6_ELEMENT_T *pAddress = (MBIM_IPV6_ELEMENT_T *)(&pInfo->DataBuffer[le32toh(pInfo->IPv6AddressOffset)-sizeof(MBIM_IP_CONFIGURATION_INFO_T)]);
2002 prefix = le32toh(pAddress->OnLinkPrefixLength);
2003 ipv6 = pAddress->IPv6Address;
2004
2005 if (le32toh(pInfo->IPv6ConfigurationAvailable)&0x2)
2006 gw = (UINT8 *)(&pInfo->DataBuffer[le32toh(pInfo->IPv6GatewayOffset)-sizeof(MBIM_IP_CONFIGURATION_INFO_T)]);
2007
2008 if (le32toh(pInfo->IPv6ConfigurationAvailable)&0x4) {
2009 dns1 = (UINT8 *)(&pInfo->DataBuffer[le32toh(pInfo->IPv6DnsServerOffset)-sizeof(MBIM_IP_CONFIGURATION_INFO_T)]);
2010 if (le32toh(pInfo->IPv6DnsServerCount) == 2)
2011 dns2 = dns1 + 16;
2012 }
2013
2014 if (le32toh(pInfo->IPv6ConfigurationAvailable)&0x8)
2015 mtu = le32toh(pInfo->IPv6Mtu);
2016
2017 mbim2qmi_ipv6addr(ipv6, profile->ipv6.Address);
2018 mbim2qmi_ipv6addr(gw, profile->ipv6.Gateway);
2019 mbim2qmi_ipv6addr(dns1, profile->ipv6.DnsPrimary);
2020 mbim2qmi_ipv6addr(dns2, profile->ipv6.DnsSecondary);
2021 profile->ipv6.PrefixLengthIPAddr = prefix;
2022 profile->ipv6.PrefixLengthGateway = prefix;
2023 profile->ipv6.Mtu = mbim2qmi_ipv4addr(mtu);
2024 }
2025 }
2026 return err;
2027 }
2028
mbim_proxy_configure(const char * dev)2029 int mbim_proxy_configure(const char *dev) {
2030 MBIM_MESSAGE_HEADER *pRequest = NULL;
2031 MBIM_COMMAND_DONE_T *pCmdDone = NULL;
2032 MBIM_LIBQMI_PROXY_CONFIG_T *cfg;
2033 int err;
2034
2035 pRequest = compose_basic_connect_command(
2036 MBIM_CID_PROXY_CONTROL_CONFIGURATION,
2037 MBIM_CID_CMD_TYPE_SET,
2038 NULL,
2039 sizeof(*cfg) + strlen(dev)*2);
2040 if (pRequest) {
2041 memcpy(((MBIM_COMMAND_MSG_T *)pRequest)->DeviceServiceId.uuid, str2uuid(UUID_LIBMBIM_PROXY), 16);
2042 cfg = (MBIM_LIBQMI_PROXY_CONFIG_T *)((MBIM_COMMAND_MSG_T *)pRequest)->InformationBuffer;
2043
2044 cfg->DevicePathOffset = sizeof(*cfg);
2045 cfg->DevicePathSize = char2wchar(dev, strlen(dev), cfg->DataBuffer, strlen(dev)*2);
2046 cfg->Timeout = 15;
2047 }
2048
2049 err = mbim_send_command(pRequest, &pCmdDone, mbim_default_timeout);
2050 mbim_check_err(err, pRequest, pCmdDone);
2051
2052 mbim_free(pRequest); mbim_free(pCmdDone);
2053 return err;
2054 }
2055
mbim_update_state(void)2056 static int mbim_update_state(void) {
2057 int chages = 0;
2058
2059 if (oldReadyState != ReadyState) {
2060 mbim_debug("SubscriberReadyState %s -> %s ", MBIMSubscriberReadyStateStr(oldReadyState), MBIMSubscriberReadyStateStr(ReadyState));
2061 oldReadyState = ReadyState; chages++;
2062 }
2063 if (oldRegisterState != RegisterState) {
2064 mbim_debug("RegisterState %s -> %s ", MBIMRegisterStateStr(oldRegisterState), MBIMRegisterStateStr(RegisterState));
2065 oldRegisterState = RegisterState; chages++;
2066 }
2067 if (oldPacketServiceState != PacketServiceState) {
2068 mbim_debug("PacketServiceState %s -> %s ", MBIMPacketServiceStateStr(oldPacketServiceState), MBIMPacketServiceStateStr(PacketServiceState));
2069 oldPacketServiceState = PacketServiceState; chages++;
2070 }
2071 if (oldActivationState != ActivationState) {
2072 mbim_debug("ActivationState %s -> %s ", MBIMActivationStateStr(oldActivationState), MBIMActivationStateStr(ActivationState));
2073 oldActivationState = ActivationState; chages++;
2074 }
2075
2076 return chages;
2077 }
2078
mbim_init(PROFILE_T * profile)2079 static int mbim_init(PROFILE_T *profile) {
2080 int retval;
2081 int t = 0;
2082
2083 if (profile->proxy[0] && !strcmp(profile->proxy, LIBMBIM_PROXY)) {
2084 retval = mbim_proxy_configure(profile->qmichannel);
2085 if (retval) goto exit;
2086 }
2087
2088 while (t++ < 10) {
2089 retval = mbim_open_device(4096);
2090 if (retval != ETIMEDOUT)
2091 break;
2092 }
2093 if (retval) goto exit;
2094 retval = mbim_device_caps_query(profile);
2095 if (retval) goto exit;
2096 mbim_update_state();
2097 retval = mbim_device_services_query();
2098 if (retval) goto exit;
2099 mbim_update_state();
2100 retval = mbim_set_radio_state(MBIMRadioOn);
2101 if (retval) goto exit;
2102 mbim_update_state();
2103
2104 return 0;
2105
2106 exit:
2107 return retval;
2108 }
2109
mbim_deinit(void)2110 static int mbim_deinit(void) {
2111 mbim_close_device();
2112
2113 return 0;
2114 }
2115
2116 const struct qmi_device_ops mbim_dev_ops = {
2117 .init = mbim_init,
2118 .deinit = mbim_deinit,
2119 .read = mbim_read_thread,
2120 };
2121
requestBaseBandVersion(PROFILE_T * profile)2122 static int requestBaseBandVersion(PROFILE_T *profile) {
2123 (void)profile;
2124 return 0;
2125 }
2126
requestGetSIMStatus(SIM_Status * pSIMStatus)2127 static int requestGetSIMStatus(SIM_Status *pSIMStatus)
2128 {
2129 int retval;
2130
2131 *pSIMStatus = SIM_ABSENT;
2132 retval = mbim_subscriber_status_query();
2133 if (retval)
2134 goto exit;
2135 mbim_update_state();
2136
2137 switch(ReadyState) {
2138 case MBIMSubscriberReadyStateNotInitialized: *pSIMStatus = SIM_NOT_READY; break;
2139 case MBIMSubscriberReadyStateInitialized: *pSIMStatus = SIM_READY; break;
2140 case MBIMSubscriberReadyStateSimNotInserted: *pSIMStatus = SIM_ABSENT; break;
2141 case MBIMSubscriberReadyStateBadSim: *pSIMStatus = SIM_BAD; break;
2142 case MBIMSubscriberReadyStateFailure: *pSIMStatus = SIM_ABSENT; break;
2143 case MBIMSubscriberReadyStateNotActivated: *pSIMStatus = SIM_ABSENT; break;
2144 case MBIMSubscriberReadyStateDeviceLocked: *pSIMStatus = SIM_PIN; break;
2145 default: *pSIMStatus = SIM_ABSENT; break;
2146 }
2147
2148 exit:
2149 return retval;
2150 }
2151
requestRegistrationState(UCHAR * pPSAttachedState)2152 static int requestRegistrationState(UCHAR *pPSAttachedState) {
2153 int retval;
2154
2155 *pPSAttachedState = 0;
2156 retval = mbim_register_state_query();
2157 if (retval)
2158 goto exit;
2159 mbim_update_state();
2160
2161 switch (RegisterState) {
2162 case MBIMRegisterStateUnknown: *pPSAttachedState = 0; break;
2163 case MBIMRegisterStateDeregistered: *pPSAttachedState = 0; break;
2164 case MBIMRegisterStateSearching: *pPSAttachedState = 0; break;
2165 case MBIMRegisterStateHome: *pPSAttachedState = 1; break;
2166 case MBIMRegisterStateRoaming: *pPSAttachedState = 1; break;
2167 case MBIMRegisterStatePartner: *pPSAttachedState = 0; break;
2168 case MBIMRegisterStateDenied: *pPSAttachedState = 0; break;
2169 default: *pPSAttachedState = 0; break;
2170 }
2171
2172 if (*pPSAttachedState == 0)
2173 goto exit;
2174
2175 retval = mbim_packet_service_query();
2176 if (retval)
2177 goto exit;
2178
2179 switch (PacketServiceState) {
2180 case MBIMPacketServiceStateUnknown: *pPSAttachedState = 0; break;
2181 case MBIMPacketServiceStateAttaching: *pPSAttachedState = 0; break;
2182 case MBIMPacketServiceStateAttached: *pPSAttachedState = 1; break;
2183 case MBIMPacketServiceStateDetaching: *pPSAttachedState = 0; break;
2184 case MBIMPacketServiceStateDetached: *pPSAttachedState = 0; break;
2185 default: *pPSAttachedState = 0; break;
2186 }
2187
2188 if (*pPSAttachedState == 0)
2189 mbim_packet_service_set(MBIMPacketServiceActionAttach);
2190
2191 exit:
2192 return retval;
2193 }
2194
requestSetupDataCall(PROFILE_T * profile,int curIpFamily)2195 static int requestSetupDataCall(PROFILE_T *profile, int curIpFamily) {
2196 int retval;
2197
2198 (void)curIpFamily;
2199
2200 if (profile->apn)
2201 mbim_apn = profile->apn;
2202 if (profile->user)
2203 mbim_user = profile->user;
2204 if (profile->password)
2205 mbim_passwd = profile->password;
2206 if (profile->auth)
2207 mbim_auth = profile->auth;
2208 if (profile->enable_ipv4)
2209 mbim_iptype = MBIMContextIPTypeIPv4;
2210 if (profile->enable_ipv6)
2211 mbim_iptype = MBIMContextIPTypeIPv6;
2212 if (profile->enable_ipv4 && profile->enable_ipv6)
2213 mbim_iptype = MBIMContextIPTypeIPv4AndIPv6;
2214
2215 retval = mbim_set_connect(1, mbim_sessionID);
2216 if (retval)
2217 goto exit;
2218
2219 exit:
2220 return retval;
2221 }
2222
requestQueryDataCall(UCHAR * pConnectionStatus,int curIpFamily)2223 static int requestQueryDataCall(UCHAR *pConnectionStatus, int curIpFamily) {
2224 int retval;
2225
2226 (void)curIpFamily;
2227
2228 *pConnectionStatus = QWDS_PKT_DATA_DISCONNECTED;
2229
2230 retval = mbim_query_connect(mbim_sessionID);
2231 if (retval)
2232 goto exit;
2233
2234 switch(ActivationState) {
2235 case MBIMActivationStateUnknown: *pConnectionStatus = QWDS_PKT_DATA_UNKNOW; break;
2236 case MBIMActivationStateActivated: *pConnectionStatus = QWDS_PKT_DATA_CONNECTED; break;
2237 case MBIMActivationStateActivating: *pConnectionStatus = QWDS_PKT_DATA_DISCONNECTED; break;
2238 case MBIMActivationStateDeactivated: *pConnectionStatus = QWDS_PKT_DATA_DISCONNECTED; break;
2239 case MBIMActivationStateDeactivating: *pConnectionStatus = QWDS_PKT_DATA_DISCONNECTED; break;
2240 default: *pConnectionStatus = QWDS_PKT_DATA_DISCONNECTED; break;
2241 }
2242
2243 exit:
2244 return retval;
2245 }
2246
requestDeactivateDefaultPDP(PROFILE_T * profile,int curIpFamily)2247 static int requestDeactivateDefaultPDP(PROFILE_T *profile, int curIpFamily) {
2248 int retval;
2249
2250 (void)profile;
2251 (void)curIpFamily;
2252
2253 retval = mbim_set_connect(0, mbim_sessionID);
2254 if (retval)
2255 goto exit;
2256
2257 exit:
2258 return retval;
2259 }
2260
requestGetIPAddress(PROFILE_T * profile,int curIpFamily)2261 static int requestGetIPAddress(PROFILE_T *profile, int curIpFamily) {
2262 int retval;
2263
2264 (void)curIpFamily;
2265 retval = mbim_ip_config(profile, mbim_sessionID);
2266 if (retval)
2267 goto exit;
2268
2269 exit:
2270 return retval;
2271 }
2272
2273 const struct request_ops mbim_request_ops = {
2274 .requestBaseBandVersion = requestBaseBandVersion,
2275 .requestGetSIMStatus = requestGetSIMStatus,
2276 .requestRegistrationState = requestRegistrationState,
2277 .requestSetupDataCall = requestSetupDataCall,
2278 .requestQueryDataCall = requestQueryDataCall,
2279 .requestDeactivateDefaultPDP = requestDeactivateDefaultPDP,
2280 .requestGetIPAddress = requestGetIPAddress,
2281 };
2282
2283