• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/uqmi/uqmid/modem_fsm.c

  1 
  2 #include <assert.h>
  3 
  4 #include "osmocom/fsm.h"
  5 #include "osmocom/utils.h"
  6 
  7 #include "qmi-enums-dms.h"
  8 #include "qmi-errors.h"
  9 #include "sim_fsm.h"
 10 #include "talloc.h"
 11 
 12 #include "qmi-struct.h"
 13 #include "qmi-enums.h"
 14 #include "qmi-message.h"
 15 #include "qmi-enums-uim.h"
 16 
 17 #include "uqmid.h"
 18 #include "logging.h"
 19 #include "utils.h"
 20 
 21 #include "modem.h"
 22 #include "modem_fsm.h"
 23 #include "modem_tx.h"
 24 #include "services.h"
 25 #include "wwan.h"
 26 
 27 #define S(x) (1 << (x))
 28 
 29 /* FIXME: if a service "vanished", abort/re-sync with backoff */
 30 /* Timeouts periods in seconds */
 31 #define T_GET_VERSION_S 5
 32 #define T_SYNC_S 3
 33 /* default timeout */
 34 #define T_DEFAULT_S 5
 35 
 36 /* Timeout number */
 37 
 38 enum {
 39         N_RESEND = 1,
 40         N_FAILURE,
 41         N_DESTROY,
 42 };
 43 
 44 static const struct value_string modem_event_names[] = {
 45         { MODEM_EV_REQ_START,                   "REQ_START" },
 46         { MODEM_EV_REQ_DESTROY,                 "REQ_DESTROY" },
 47         { MODEM_EV_REQ_CONFIGURED,              "REQ_CONFIGURED"},
 48         { MODEM_EV_RX_SYNC,                     "RX_SYNC" },
 49         { MODEM_EV_RX_VERSION,                  "RX_VERSION" },
 50         { MODEM_EV_RX_MODEL,                    "RX_MODEL" },
 51         { MODEM_EV_RX_MANUFACTURER,             "RX_MANUFACTURER" },
 52         { MODEM_EV_RX_REVISION,                 "RX_REVISION" },
 53 
 54         { MODEM_EV_RX_POWEROFF,                 "RX_POWEROFF" },
 55         { MODEM_EV_RX_POWERON,                  "RX_POWERON" },
 56         { MODEM_EV_RX_POWERSET,                 "RX_POWERSET" },
 57 
 58         { MODEM_EV_REQ_SIM_TERM,                "RX_SIM_TERM" },
 59         { MODEM_EV_REQ_SIM_FAILURE,             "RX_SIM_FAILURE" },
 60         { MODEM_EV_REQ_SIM_READY,               "RX_SIM_READY" },
 61 
 62         { MODEM_EV_RX_GET_PROFILE_LIST,         "RX_GET_PROFILE_LIST" },
 63         { MODEM_EV_RX_MODIFIED_PROFILE,         "RX_MODIFIED_PROFILE" },
 64         { MODEM_EV_RX_CONFIGURED,               "RX_CONFIGURED" },
 65 
 66         { MODEM_EV_RX_SEARCHING,                "RX_SEARCHING" },
 67         { MODEM_EV_RX_UNREGISTERED,             "RX_UNREGISTERED" },
 68         { MODEM_EV_RX_REGISTERED,               "RX_REGISTERED" },
 69 
 70         { MODEM_EV_RX_SUBSCRIBED,               "RX_SUBSCRIBED" },
 71         { MODEM_EV_RX_SUBSCRIBE_FAILED,         "RX_SUBSCRIBE_FAILED" },
 72 
 73         { MODEM_EV_RX_DISABLE_AUTOCONNECT_SUCCESS, "RX_DISABLE_AUTOCONNECT_SUCCESS"},
 74 
 75         { MODEM_EV_RX_FAILED,                   "RX_FAILED" },
 76         { MODEM_EV_RX_SUCCEED,                  "RX_SUCCEED" },
 77         { 0, NULL }
 78 };
 79 
 80 #define NAS_SERVICE_POLL_TIMEOUT_S 5
 81 
 82 void modem_fsm_start(struct modem *modem)
 83 {
 84         osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_REQ_START, NULL);
 85 }
 86 
 87 static void modem_st_unconfigured(struct osmo_fsm_inst *fi, uint32_t event, void *data)
 88 {
 89         switch (event) {
 90         case MODEM_EV_REQ_START:
 91                 osmo_fsm_inst_state_chg(fi, MODEM_ST_RESYNC, T_SYNC_S, N_FAILURE);
 92                 break;
 93         }
 94 }
 95 
 96 static void ctl_sync_request_cb(struct qmi_service *service, struct qmi_request *req, struct qmi_msg *msg)
 97 {
 98         struct modem *modem = req->cb_data;
 99         int ret = 0;
100 
101         /* transaction aborted or timedout */
102         if (!msg) {
103                 osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_FAILED, NULL);
104                 return;
105         }
106 
107         ret = qmi_parse_ctl_sync_response(msg);
108         if (ret != QMI_PROTOCOL_ERROR_NONE) {
109                 modem_log(modem, LOGL_ERROR, "Sync Request returned error %d", ret);
110                 osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_FAILED, NULL);
111                 return;
112         }
113 
114         osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_SYNC, NULL);
115 }
116 
117 static void modem_st_resync_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
118 {
119         struct modem *modem = fi->priv;
120         struct qmi_service *ctl = uqmi_service_find(modem->qmi, QMI_SERVICE_CTL);
121 
122         uqmi_service_send_simple(ctl, qmi_set_ctl_sync_request, ctl_sync_request_cb, modem);
123 }
124 
125 static void modem_st_resync(struct osmo_fsm_inst *fi, uint32_t event, void *data)
126 {
127         osmo_fsm_inst_state_chg(fi, MODEM_ST_GET_VERSION, T_GET_VERSION_S, 0);
128 }
129 
130 static void uqmid_modem_version_cb(struct qmi_service *ctl_service, struct qmi_request *req, struct qmi_msg *msg)
131 {
132         struct modem *modem = req->cb_data;
133         struct qmi_service *service;
134         uint8_t service_id;
135         uint16_t major, minor;
136 
137         struct qmi_ctl_get_version_info_response res = {};
138         qmi_parse_ctl_get_version_info_response(msg, &res);
139 
140         for (int i = 0; i < res.data.service_list_n; i++) {
141                 service_id = res.data.service_list[i].service;
142                 major = res.data.service_list[i].major_version;
143                 minor = res.data.service_list[i].minor_version;
144 
145                 service = uqmi_service_find_or_init(modem->qmi, service_id);
146                 if (!service)
147                         continue;
148 
149                 service->major = major;
150                 service->minor = minor;
151         }
152 
153         /* FIXME: create a list of required services and validate them */
154 
155         osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_VERSION, NULL);
156 }
157 
158 static void modem_st_get_version_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
159 {
160         struct modem *modem = fi->priv;
161         struct qmi_request *req = talloc_zero(modem->qmi->ctrl, struct qmi_request);
162         struct qmi_msg *msg = talloc_zero_size(req, 1024);
163 
164         int ret = qmi_set_ctl_get_version_info_request(msg);
165         if (ret) {
166                 LOG_ERROR("Failed to encode get version info");
167                 return;
168         }
169 
170         req->msg = msg;
171         req->cb = uqmid_modem_version_cb;
172         req->cb_data = modem;
173         uqmi_service_send_msg(modem->qmi->ctrl, req);
174 }
175 
176 static void modem_st_get_version(struct osmo_fsm_inst *fi, uint32_t event, void *data)
177 {
178         struct modem *modem = fi->priv;
179 
180         switch (event) {
181         case MODEM_EV_RX_VERSION:
182                 osmo_fsm_inst_dispatch(modem->sim.fi, SIM_EV_REQ_START, NULL);
183                 osmo_fsm_inst_state_chg(fi, MODEM_ST_GET_MODEL, 0, 0);
184                 break;
185         }
186 }
187 
188 static void get_manuf_cb(struct qmi_service *service, struct qmi_request *req, struct qmi_msg *msg)
189 {
190         struct modem *modem = req->cb_data;
191         int ret = 0;
192 
193         struct qmi_dms_get_manufacturer_response res = {};
194         ret = qmi_parse_dms_get_manufacturer_response(msg, &res);
195 
196         if (ret) {
197                 /* FIXME: No manufacturer. Ignoring */
198                 modem_log(modem, LOGL_ERROR, "Failed to get a manufacturer.");
199                 osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_MANUFACTURER, NULL);
200                 return;
201         }
202 
203         if (!res.data.manufacturer) {
204                 /* FIXME: No manufacturer */
205                 modem_log(modem, LOGL_ERROR, "Got empty manufacturer.");
206                 osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_MANUFACTURER, NULL);
207                 return;
208         }
209 
210         if (modem->manuf)
211                 talloc_free(modem->manuf);
212 
213         modem->manuf = talloc_strdup(modem, res.data.manufacturer);
214         osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_MANUFACTURER, NULL);
215 }
216 
217 static void get_model_cb(struct qmi_service *service, struct qmi_request *req, struct qmi_msg *msg)
218 {
219         struct modem *modem = req->cb_data;
220         int ret = 0;
221 
222         struct qmi_dms_get_model_response res = {};
223         ret = qmi_parse_dms_get_model_response(msg, &res);
224 
225         if (ret) {
226                 /* FIXME: No model. Ignoring */
227                 modem_log(modem, LOGL_ERROR, "Failed to get a model.");
228                 osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_MODEL, NULL);
229                 return;
230         }
231 
232         if (!res.data.model) {
233                 /* FIXME: No model */
234                 modem_log(modem, LOGL_ERROR, "Got empty model.");
235                 osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_MODEL, NULL);
236                 return;
237         }
238 
239         if (modem->model)
240                 talloc_free(modem->model);
241 
242         modem->model = talloc_strdup(modem, res.data.model);
243         osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_MODEL, NULL);
244 }
245 
246 static void get_revision_cb(struct qmi_service *service, struct qmi_request *req, struct qmi_msg *msg)
247 {
248         struct modem *modem = req->cb_data;
249         int ret = 0;
250 
251         struct qmi_dms_get_revision_response res = {};
252         ret = qmi_parse_dms_get_revision_response(msg, &res);
253 
254         if (ret) {
255                 /* FIXME: No revision. Ignoring */
256                 modem_log(modem, LOGL_ERROR, "Failed to get a revision.");
257                 osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_REVISION, NULL);
258                 return;
259         }
260 
261         if (!res.data.revision) {
262                 /* FIXME: No revision */
263                 modem_log(modem, LOGL_ERROR, "Got empty revision.");
264                 osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_REVISION, NULL);
265                 return;
266         }
267 
268         if (modem->rev)
269                 talloc_free(modem->rev);
270 
271         modem->rev = talloc_strdup(modem, res.data.revision);
272         osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_REVISION, NULL);
273 }
274 
275 static void get_ids_cb(struct qmi_service *service, struct qmi_request *req, struct qmi_msg *msg)
276 {
277         struct modem *modem = req->cb_data;
278         int ret = 0;
279 
280         struct qmi_dms_get_ids_response res = {};
281         ret = qmi_parse_dms_get_ids_response(msg, &res);
282 
283         if (ret) {
284                 /* FIXME: No revision. Ignoring */
285                 modem_log(modem, LOGL_ERROR, "Failed to get a IMEI.");
286                 osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_IMEI, NULL);
287                 return;
288         }
289 
290         TALLOC_FREE(modem->meid);
291         TALLOC_FREE(modem->imei);
292         TALLOC_FREE(modem->imeisv);
293 
294         if (res.data.meid)
295                 modem->meid = talloc_strdup(modem, res.data.meid);
296 
297         if (res.data.imei)
298                 modem->imei = talloc_strdup(modem, res.data.imei);
299 
300         if (res.data.imei_software_version)
301                 modem->imeisv = talloc_strdup(modem, res.data.imei_software_version);
302 
303         osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_IMEI, NULL);
304 }
305 
306 static void modem_st_get_model_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
307 {
308         struct modem *modem = fi->priv;
309         struct qmi_service *service = uqmi_service_find(modem->qmi, QMI_SERVICE_DMS);
310 
311         if (!service) {
312                 modem_log(modem, LOGL_ERROR, "DMS service unavailable");
313                 /* FIXME: fail to perm failure */
314         }
315 
316         uqmi_service_send_simple(service, qmi_set_dms_get_model_request, get_model_cb, modem);
317 }
318 
319 static void modem_st_get_model(struct osmo_fsm_inst *fi, uint32_t event, void *data)
320 {
321         struct modem *modem = fi->priv;
322         struct qmi_service *service = uqmi_service_find(modem->qmi, QMI_SERVICE_DMS);
323 
324         if (!service) {
325                 modem_log(modem, LOGL_ERROR, "DMS service unavailable");
326                 /* FIXME: fail to perm failure */
327         }
328 
329         /* FIXME: enable timeout and check if enough information has been gathered */
330 
331         switch (event) {
332         case MODEM_EV_RX_MODEL:
333                 uqmi_service_send_simple(service, qmi_set_dms_get_manufacturer_request, get_manuf_cb, modem);
334                 break;
335         case MODEM_EV_RX_MANUFACTURER:
336                 uqmi_service_send_simple(service, qmi_set_dms_get_revision_request, get_revision_cb, modem);
337                 break;
338         case MODEM_EV_RX_REVISION:
339                 uqmi_service_send_simple(service, qmi_set_dms_get_ids_request, get_ids_cb, modem);
340                 break;
341         case MODEM_EV_RX_IMEI:
342                 osmo_fsm_inst_state_chg(fi, MODEM_ST_POWEROFF, 3, 0);
343                 break;
344         }
345 }
346 
347 static void dms_get_operating_mode_cb(struct qmi_service *service, struct qmi_request *req, struct qmi_msg *msg)
348 {
349         struct modem *modem = req->cb_data;
350         int ret = 0;
351         struct qmi_dms_get_operating_mode_response res = {};
352 
353         if (req->ret) {
354                 modem_log(modem, LOGL_INFO, "Failed to get operating mode. Status %d/%s.", req->ret,
355                           qmi_get_error_str(req->ret));
356                 osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_FAILED, NULL);
357                 return;
358         }
359 
360         ret = qmi_parse_dms_get_operating_mode_response(msg, &res);
361         if (ret) {
362                 modem_log(modem, LOGL_INFO, "Failed to get operating mode. Failed to parse message");
363                 osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_FAILED, NULL);
364                 return;
365         }
366 
367         if (!res.set.mode) {
368                 modem_log(modem, LOGL_INFO, "Failed to get operating mode. Failed to parse message");
369                 osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_FAILED, NULL);
370         }
371 
372         modem_log(modem, LOGL_INFO, "Current in operating mode %d", res.data.mode);
373         switch (res.data.mode) {
374         case QMI_DMS_OPERATING_MODE_ONLINE:
375                 osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_POWERON, (void *)(long)res.data.mode);
376                 break;
377         case QMI_DMS_OPERATING_MODE_LOW_POWER:
378                 osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_POWEROFF, (void *)(long)res.data.mode);
379                 break;
380         default:
381                 modem_log(modem, LOGL_ERROR, "Unhandled power mode! (%d) Trying to power off", res.data.mode);
382                 osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_POWERON, (void *)(long)res.data.mode);
383         }
384 }
385 
386 static void dms_set_operating_mode_cb(struct qmi_service *service, struct qmi_request *req, struct qmi_msg *msg)
387 {
388         struct modem *modem = req->cb_data;
389         if (req->ret) {
390                 modem_log(modem, LOGL_INFO, "Failed to set operating mode. Status %d/%s.", req->ret,
391                           qmi_get_error_str(req->ret));
392                 osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_FAILED, NULL);
393                 return;
394         }
395 
396         /* TODO: we should request the state again to validate the modem is following our request. */
397         osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_POWERSET, 0);
398 }
399 
400 static void modem_st_poweroff_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
401 {
402         struct modem *modem = fi->priv;
403         struct qmi_service *dms = uqmi_service_find(modem->qmi, QMI_SERVICE_DMS);
404 
405         /* FIXME: abort when DMS doesn't exist */
406         if (dms)
407                 uqmi_service_send_simple(dms, qmi_set_dms_get_operating_mode_request, dms_get_operating_mode_cb, modem);
408 }
409 static void modem_st_poweroff(struct osmo_fsm_inst *fi, uint32_t event, void *data)
410 {
411         struct modem *modem = fi->priv;
412         struct qmi_service *dms = uqmi_service_find(modem->qmi, QMI_SERVICE_DMS);
413 
414         switch (event) {
415         case MODEM_EV_RX_POWERON:
416                 tx_dms_set_operating_mode(modem, dms, QMI_DMS_OPERATING_MODE_LOW_POWER, dms_set_operating_mode_cb);
417                 break;
418         case MODEM_EV_RX_POWERSET:
419                 uqmi_service_send_simple(dms, qmi_set_dms_get_operating_mode_request, dms_get_operating_mode_cb, modem);
420                 break;
421         case MODEM_EV_RX_POWEROFF:
422                 if (modem->config.configured && !modem->state.error)
423                         osmo_fsm_inst_state_chg(fi, MODEM_ST_WAIT_UIM, 0, 0);
424                 else /* stop timer and wait for the user to continue */
425                         osmo_timer_del(&fi->timer);
426                 break;
427         case MODEM_EV_REQ_CONFIGURED: /* when the modem reach this state, but isn't yet configured, wait for the config */
428                 osmo_fsm_inst_state_chg(fi, MODEM_ST_WAIT_UIM, 0, 0);
429                 break;
430         }
431 }
432 
433 static void modem_st_wait_uim_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
434 {
435         struct modem *modem = fi->priv;
436 
437         if (modem->sim.fi->state == SIM_ST_READY)
438                 osmo_fsm_inst_state_chg(fi, MODEM_ST_CONFIGURE_MODEM, 0, 0);
439 }
440 
441 static void modem_st_wait_uim(struct osmo_fsm_inst *fi, uint32_t event, void *data)
442 {
443         switch (event) {
444         case MODEM_EV_REQ_SIM_READY:
445                 osmo_fsm_inst_state_chg(fi, MODEM_ST_CONFIGURE_MODEM, 0, 0);
446                 break;
447         default:
448                 break;
449         }
450 }
451 
452 static void wds_modify_profile_cb(struct qmi_service *service, struct qmi_request *req, struct qmi_msg *msg)
453 {
454         struct modem *modem = req->cb_data;
455         struct qmi_wds_modify_profile_response res = {};
456         long err = 1;
457         int ret;
458         if (req->ret) {
459                 modem_log(modem, LOGL_INFO, "Failed to modify profile list. Status %d/%s.", req->ret,
460                           qmi_get_error_str(req->ret));
461                 /* FIXME: add extended profile error */
462                 osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_MODIFIED_PROFILE, (void *)err);
463                 return;
464         }
465 
466         ret = qmi_parse_wds_modify_profile_response(msg, &res);
467         if (ret) {
468                 modem_log(modem, LOGL_INFO, "Failed to modify profile list. Failed to parse message");
469                 osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_MODIFIED_PROFILE, (void *)err);
470                 return;
471         }
472 
473         err = 0;
474         osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_MODIFIED_PROFILE, (void *)err);
475 }
476 
477 static void wds_get_profile_list_cb(struct qmi_service *service, struct qmi_request *req, struct qmi_msg *msg)
478 {
479         struct modem *modem = req->cb_data;
480         struct qmi_wds_get_profile_list_response res = {};
481         long err = 1;
482         int ret;
483         if (req->ret) {
484                 modem_log(modem, LOGL_INFO, "Failed to get profile list. Status %d/%s.", req->ret,
485                           qmi_get_error_str(req->ret));
486                 osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_FAILED, NULL);
487                 return;
488         }
489 
490         ret = qmi_parse_wds_get_profile_list_response(msg, &res);
491         if (ret) {
492                 modem_log(modem, LOGL_INFO, "Failed to get operating mode. Failed to parse message");
493                 osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_FAILED, NULL);
494                 return;
495         }
496 
497         for (int i = 0; i < res.data.profile_list_n; i++) {
498                 uint8_t type = res.data.profile_list[i].profile_type;
499                 uint8_t idx = res.data.profile_list[i].profile_index;
500                 /* const char *name = res.data.profile_list[i].profile_name; */
501                 if (type != QMI_WDS_PROFILE_TYPE_3GPP)
502                         continue;
503 
504                 err = 0;
505                 /* we're taking the first one and ignoring the rest for now */
506                 modem_log(modem, LOGL_INFO, "Found profile id %d", idx);
507                 modem->qmi->wds.profile_id = idx;
508                 modem->qmi->wds.valid = 1;
509         }
510 
511         osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_GET_PROFILE_LIST, (void *)err);
512 }
513 
514 static void modem_st_configure_modem_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
515 {
516         struct modem *modem = fi->priv;
517         struct qmi_service *wds = uqmi_service_find(modem->qmi, QMI_SERVICE_WDS);
518 
519         switch (modem->config.pdp_type) {
520         case QMI_WDS_PDP_TYPE_IPV4:
521                 modem->qmi->wds.ip_family = QMI_WDS_IP_FAMILY_IPV4;
522                 break;
523         /* FIXME: add support for IPV4/IPV6 dual stack */
524         case QMI_WDS_PDP_TYPE_IPV4_OR_IPV6:
525         case QMI_WDS_PDP_TYPE_IPV6:
526                 modem->qmi->wds.ip_family = QMI_WDS_IP_FAMILY_IPV6;
527                 break;
528         default:
529                 modem->qmi->wds.ip_family = QMI_WDS_IP_FAMILY_UNSPECIFIED;
530                 break;
531         }
532 
533         tx_wds_get_profile_list(modem, wds, wds_get_profile_list_cb);
534 }
535 
536 static void modem_st_configure_modem(struct osmo_fsm_inst *fi, uint32_t event, void *data)
537 {
538         struct modem *modem = fi->priv;
539         struct qmi_service *wds = uqmi_service_find(modem->qmi, QMI_SERVICE_WDS);
540 
541         /* get Profile list, if no Profile,
542          * create one ()
543          * modify profile () */
544 
545         switch (event) {
546         case MODEM_EV_RX_GET_PROFILE_LIST:
547                 /* err */
548                 if (data) {
549                         /* failed to get profile list/generate a new profile */
550                 } else {
551                         tx_wds_modify_profile(modem, wds, wds_modify_profile_cb, modem->qmi->wds.profile_id,
552                                               modem->config.apn, modem->config.pdp_type, modem->config.username,
553                                               modem->config.password);
554                 }
555                 break;
556         case MODEM_EV_RX_MODIFIED_PROFILE:
557                 /* configure the physical kernel interface */
558                 osmo_fsm_inst_state_chg(fi, MODEM_ST_CONFIGURE_KERNEL, T_DEFAULT_S, 0);
559                 break;
560         }
561         /* TODO: check if this is the default profile! */
562 }
563 
564 static void wda_set_data_format_cb(struct qmi_service *service, struct qmi_request *req, struct qmi_msg *msg)
565 {
566         struct modem *modem = req->cb_data;
567         int ret = 0;
568         struct qmi_wda_set_data_format_response res = {};
569 
570         if (req->ret) {
571                 modem_log(modem, LOGL_ERROR, "Failed to set data format. Status %d/%s.", req->ret,
572                           qmi_get_error_str(req->ret));
573                 osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_FAILED, NULL);
574                 return;
575         }
576 
577         ret = qmi_parse_wda_set_data_format_response(msg, &res);
578         if (ret) {
579                 modem_log(modem, LOGL_ERROR, "Failed to set data format. Failed to parse message");
580                 osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_FAILED, NULL);
581                 return;
582         }
583 
584         if (!res.set.link_layer_protocol) {
585                 modem_log(modem, LOGL_ERROR, "Failed to set data format. Link layer protocol TLV missing");
586                 osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_FAILED, NULL);
587                 return;
588         }
589 
590         /* currently uqmid only supports raw-ip */
591         if (res.data.link_layer_protocol != QMI_WDA_LINK_LAYER_PROTOCOL_RAW_IP) {
592                 modem_log(modem, LOGL_ERROR, "Failed to set data format. Link layer protocol TLV missing");
593                 osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_FAILED, NULL);
594                 return;
595         }
596 
597         osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_SUCCEED, (void *)(long)msg->svc.message);
598 }
599 
600 /* Configure the kernel network interface */
601 static void modem_st_configure_kernel_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
602 {
603         struct modem *modem = fi->priv;
604         struct qmi_service *wda = uqmi_service_find(modem->qmi, QMI_SERVICE_WDA);
605 
606         if (modem->wwan.skip_configuration) {
607                 tx_wda_set_data_format(modem, wda, wda_set_data_format_cb);
608                 return;
609         }
610 
611         /* when using raw-ip later with QMAP support, ensure the mtu is at the maximum of the USB transfer */
612         int ret = wwan_refresh_device(modem);
613         if (ret) {
614                 modem_log(modem, LOGL_ERROR, "Failed to get wwan device. err %d", ret);
615                 return;
616         }
617 
618         ret = wwan_ifupdown(modem->wwan.dev, 0);
619         if (ret) {
620                 modem_log(modem, LOGL_ERROR, "Failed to bring down wwan device. err %d", ret);
621                 return;
622         }
623 
624         modem->wwan.config.pass_through = false;
625         modem->wwan.config.raw_ip = false;
626         ret = wwan_set_configuration(modem->wwan.sysfs, &modem->wwan.config);
627         if (ret) {
628                 modem_log(modem, LOGL_ERROR, "Failed to set qmi configuration. err %d", ret);
629                 return;
630         }
631 
632         ret = wwan_set_mtu(modem->wwan.dev, 1500);
633         if (ret) {
634                 modem_log(modem, LOGL_ERROR, "Failed to set mtu. err %d", ret);
635                 return;
636         }
637 
638         modem->wwan.config.pass_through = false;
639         modem->wwan.config.raw_ip = true;
640         ret = wwan_set_configuration(modem->wwan.sysfs, &modem->wwan.config);
641         if (ret) {
642                 modem_log(modem, LOGL_ERROR, "Failed to set qmi configuration (final). err %d", ret);
643                 return;
644         }
645 
646         ret = wwan_ifupdown(modem->wwan.dev, 1);
647         if (ret) {
648                 modem_log(modem, LOGL_ERROR, "Failed to bring up wwan device. err %d", ret);
649                 return;
650         }
651 
652         tx_wda_set_data_format(modem, wda, wda_set_data_format_cb);
653 }
654 
655 
656 static void modem_st_configure_kernel(struct osmo_fsm_inst *fi, uint32_t event, void *data)
657 {
658         long msg = (long) data;
659 
660         switch (event) {
661         case MODEM_EV_RX_SUCCEED:
662                 /* Wrong message handler */
663                 /* TODO: generate and use WDA Message defines */
664                 if (msg != 0x0020)
665                         break;
666 
667                 osmo_fsm_inst_state_chg(fi, MODEM_ST_POWERON, 0, 0);
668                 break;
669         }
670 }
671 
672 static void modem_st_poweron_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
673 {
674         struct modem *modem = fi->priv;
675         struct qmi_service *dms = uqmi_service_find(modem->qmi, QMI_SERVICE_DMS);
676 
677         /* FIXME: abort when DMS doesn't exist */
678         if (dms)
679                 uqmi_service_send_simple(dms, qmi_set_dms_get_operating_mode_request, dms_get_operating_mode_cb, modem);
680 }
681 static void modem_st_poweron(struct osmo_fsm_inst *fi, uint32_t event, void *data)
682 {
683         struct modem *modem = fi->priv;
684         struct qmi_service *dms = uqmi_service_find(modem->qmi, QMI_SERVICE_DMS);
685 
686         switch (event) {
687         case MODEM_EV_RX_POWEROFF:
688                 tx_dms_set_operating_mode(modem, dms, QMI_DMS_OPERATING_MODE_ONLINE, dms_set_operating_mode_cb);
689                 break;
690         case MODEM_EV_RX_POWERSET:
691         case MODEM_EV_RX_POWERON:
692                 osmo_fsm_inst_state_chg(fi, MODEM_ST_NETSEARCH, NAS_SERVICE_POLL_TIMEOUT_S, 0);
693                 break;
694         }
695 }
696 
697 static void subscribe_result_cb(struct qmi_service *service, struct qmi_request *req, struct qmi_msg *msg)
698 {
699         struct modem *modem = req->cb_data;
700         if (req->ret) {
701                 modem_log(modem, LOGL_INFO, "Service %d: Subscribe check failed with %d/%s", service->service, req->ret,
702                           qmi_get_error_str(req->ret));
703                 osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_SUBSCRIBE_FAILED,
704                                        (void *)(long)le32_to_cpu(msg->svc.message));
705                 return;
706         }
707 
708         osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_SUBSCRIBED, (void *)(long)le32_to_cpu(msg->svc.message));
709 }
710 
711 static void get_serving_system_cb(struct qmi_service *service, struct qmi_request *req, struct qmi_msg *msg)
712 {
713         struct modem *modem = req->cb_data;
714         struct qmi_nas_get_serving_system_response res = {};
715 
716         if (req->ret) {
717                 modem_log(modem, LOGL_INFO, "Failed to get system info. Status %d/%s", req->ret,
718                           qmi_get_error_str(req->ret));
719                 osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_FAILED, (void *)(long)1);
720                 return;
721         }
722 
723         int ret = qmi_parse_nas_get_serving_system_response(msg, &res);
724         if (ret) {
725                 modem_log(modem, LOGL_ERROR, "Failed to decode serving system response");
726                 osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_FAILED, (void *)(long)1);
727                 return;
728         }
729 
730         if (!res.set.serving_system) {
731                 modem_log(modem, LOGL_ERROR, "No serving system in get serving system");
732                 osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_FAILED, (void *)(long)1);
733                 return;
734         }
735 
736         modem_log(modem, LOGL_INFO, "Network registration state %d", res.data.serving_system.registration_state);
737 
738         switch (res.data.serving_system.registration_state) {
739         case QMI_NAS_REGISTRATION_STATE_REGISTERED:
740                 osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_REGISTERED, NULL);
741                 return;
742         case QMI_NAS_REGISTRATION_STATE_NOT_REGISTERED:
743         case QMI_NAS_REGISTRATION_STATE_UNKNOWN:
744         case QMI_NAS_REGISTRATION_STATE_REGISTRATION_DENIED:
745                 osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_UNREGISTERED, NULL);
746                 return;
747         case QMI_NAS_REGISTRATION_STATE_NOT_REGISTERED_SEARCHING:
748                 osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_SEARCHING, NULL);
749                 return;
750         }
751 }
752 
753 static void nas_force_search_cb(struct qmi_service *service, struct qmi_request *req, struct qmi_msg *msg)
754 {
755         struct modem *modem = req->cb_data;
756         if (req->ret) {
757                 modem_log(modem, LOGL_INFO, "Failed to force a network search. Status %d/%s", req->ret,
758                           qmi_get_error_str(req->ret));
759                 /* FIXME: charge timer */
760                 osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_FAILED, NULL);
761                 return;
762         }
763 }
764 
765 static void modem_st_netsearch_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
766 {
767         struct modem *modem = fi->priv;
768         struct qmi_service *nas = uqmi_service_find(modem->qmi, QMI_SERVICE_NAS);
769         tx_nas_subscribe_nas_events(modem, nas, 1, subscribe_result_cb);
770 }
771 
772 static void modem_st_netsearch(struct osmo_fsm_inst *fi, uint32_t event, void *data)
773 {
774         /* TODO: register to internal indications */
775         struct modem *modem = fi->priv;
776         struct qmi_service *nas = uqmi_service_find(modem->qmi, QMI_SERVICE_NAS);
777 
778         switch (event) {
779         case MODEM_EV_RX_REGISTERED:
780                 osmo_fsm_inst_state_chg(fi, MODEM_ST_REGISTERED, 0, 0);
781                 break;
782         case MODEM_EV_RX_FAILED:
783                 osmo_timer_schedule(&fi->timer, 5, 0);
784                 break;
785         case MODEM_EV_RX_SUBSCRIBED:
786         case MODEM_EV_RX_SUBSCRIBE_FAILED:
787                 uqmi_service_send_simple(nas, qmi_set_nas_get_serving_system_request, get_serving_system_cb, modem);
788                 break;
789         case MODEM_EV_RX_UNREGISTERED:
790                 modem_log(modem, LOGL_INFO, "Start network search.");
791                 uqmi_service_send_simple(nas, qmi_set_nas_force_network_search_request, nas_force_search_cb, modem);
792                 break;
793         }
794 }
795 
796 static void modem_st_registered_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
797 {
798         osmo_fsm_inst_state_chg(fi, MODEM_ST_START_IFACE, 5, 0);
799 }
800 static void modem_st_registered(struct osmo_fsm_inst *fi, uint32_t event, void *data)
801 {
802 }
803 
804 static void wds_start_network_cb(struct qmi_service *service, struct qmi_request *req, struct qmi_msg *msg)
805 {
806         struct modem *modem = req->cb_data;
807         struct qmi_wds_start_network_response res = {};
808         long err = 1;
809         int ret;
810 
811         ret = qmi_parse_wds_start_network_response(msg, &res);
812         if (ret) {
813                 modem_log(modem, LOGL_INFO, "Failed to get operating mode. Failed to parse message");
814                 osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_FAILED, NULL);
815                 return;
816         }
817 
818         /* to get error causes */
819         err = ret = req->ret;
820         if (ret && ret == QMI_PROTOCOL_ERROR_NO_EFFECT) {
821                 modem_log(modem, LOGL_INFO, "Start network return NO_EFFECT. Trying to continue");
822         } else if (ret) {
823                 modem_log(modem, LOGL_INFO, "Failed start network. QMI Status %d/%s.", req->ret,
824                           qmi_get_error_str(req->ret));
825                 if (res.set.call_end_reason)
826                         modem_log(modem, LOGL_INFO, "Call End Reason %x", res.data.call_end_reason);
827 
828                 if (res.set.verbose_call_end_reason) {
829                         modem_log(modem, LOGL_INFO, "Verbose End Reason type %x/reason %x",
830                                   res.data.verbose_call_end_reason.type, res.data.verbose_call_end_reason.reason);
831                 }
832 
833                 osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_FAILED, (void *)(long)req->ret);
834                 return;
835         }
836 
837         if (res.set.packet_data_handle) {
838                 modem->qmi->wds.packet_handle = res.data.packet_data_handle;
839                 osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_SUCCEED, (void *)err);
840         } else {
841                 modem_log(modem, LOGL_INFO, "No packet data handle. Suspicious...");
842                 osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_FAILED, (void *)err);
843         }
844 }
845 
846 static void
847 wds_stop_network_cb(struct qmi_service *service, struct qmi_request *req, struct qmi_msg *msg)
848 {
849         struct modem *modem = req->cb_data;
850         int ret;
851 
852         ret = qmi_parse_wds_stop_network_response(msg);
853         if (ret) {
854                 modem_log(modem, LOGL_INFO, "Failed to stop network.");
855                 osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_FAILED, NULL);
856                 return;
857         }
858 
859         osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_DISABLE_AUTOCONNECT_SUCCESS, NULL);
860 }
861 
862 static void modem_st_start_iface_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
863 {
864         struct modem *modem = fi->priv;
865         struct qmi_service *wds = uqmi_service_find(modem->qmi, QMI_SERVICE_WDS);
866 
867         fi->N = 0;
868         tx_wds_start_network(modem, wds, wds_start_network_cb, modem->qmi->wds.profile_id, modem->qmi->wds.ip_family);
869 }
870 static void modem_st_start_iface(struct osmo_fsm_inst *fi, uint32_t event, void *data)
871 {
872         struct modem *modem = fi->priv;
873         long reason;
874         bool disable_autoconnect = true;
875         struct qmi_service *wds = uqmi_service_find(modem->qmi, QMI_SERVICE_WDS);
876         /* FIXME: ensure essential services "can't" disappear or abort the FSM nicely */
877         assert(wds);
878 
879         switch (event) {
880         case MODEM_EV_RX_DISABLE_AUTOCONNECT_SUCCESS:
881                 tx_wds_start_network(modem, wds, wds_start_network_cb, modem->qmi->wds.profile_id, modem->qmi->wds.ip_family);
882                 break;
883         case MODEM_EV_RX_FAILED:
884                 reason = (long) data;
885                 switch (reason) {
886                 case QMI_PROTOCOL_ERROR_CALL_FAILED:
887                         fi->T = N_RESEND;
888                         break;
889                 case QMI_PROTOCOL_ERROR_NO_EFFECT:
890                         /* No effect means it already started a connection,
891                          * but we didn't got packet_data_handle out of it.
892                          */
893                         fi->N++;
894                         tx_wds_stop_network(modem, wds, wds_stop_network_cb, 0xffffffff, &disable_autoconnect);
895                         break;
896                 default:
897                         uqmid_modem_set_error(modem, "Start Iface/Network failed!");
898                         osmo_fsm_inst_state_chg(fi, MODEM_ST_POWEROFF, 0, 0);
899                         break;
900                 }
901                 break;
902         case MODEM_EV_RX_SUCCEED:
903                 osmo_fsm_inst_state_chg(fi, MODEM_ST_LIVE, 0, 0);
904                 break;
905         }
906 }
907 
908 static void ipv4_to_sockaddr(const uint32_t wds_ip, struct sockaddr_in *addr)
909 {
910         memset(addr, 0, sizeof(*addr));
911         addr->sin_family = AF_INET;
912         addr->sin_addr.s_addr = htonl(wds_ip);
913 }
914 
915 static void ipv6_to_sockaddr(const uint16_t *wds_ip6, struct sockaddr_in6 *addr)
916 {
917         memset(addr, 0, sizeof(*addr));
918         addr->sin6_family = AF_INET6;
919         memcpy(&addr->sin6_addr, wds_ip6, sizeof(struct in6_addr));
920 }
921 
922 static void wds_get_current_settings_cb(struct qmi_service *service, struct qmi_request *req, struct qmi_msg *msg)
923 {
924         struct modem *modem = req->cb_data;
925         struct qmi_wds_get_current_settings_response res = {};
926         int ret;
927 
928         ret = qmi_parse_wds_get_current_settings_response(msg, &res);
929         if (ret) {
930                 modem_log(modem, LOGL_INFO, "Failed to get current settings. Failed to parse message");
931                 osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_FAILED, NULL);
932                 return;
933         }
934 
935         if (!res.set.ip_family) {
936                 modem_log(modem, LOGL_ERROR, "Modem didn't include ip family");
937                 osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_FAILED, (void *)1);
938         }
939 
940         memset(&modem->brearer.dns1, 0, sizeof(modem->brearer.dns1));
941         memset(&modem->brearer.dns2, 0, sizeof(modem->brearer.dns2));
942 
943         switch (res.data.ip_family) {
944         case QMI_WDS_IP_FAMILY_IPV4:
945                 memset(&modem->brearer.v4_addr, 0, sizeof(modem->brearer.v4_addr));
946                 memset(&modem->brearer.v4_netmask, 0, sizeof(modem->brearer.v4_netmask));
947                 memset(&modem->brearer.v4_gateway, 0, sizeof(modem->brearer.v4_gateway));
948 
949                 if (!res.set.ipv4_address) {
950                         modem_log(modem, LOGL_ERROR, "Modem didn't include IPv4 Address.");
951                         osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_FAILED, (void *)2);
952                 }
953                 ipv4_to_sockaddr(res.data.ipv4_address, &modem->brearer.v4_addr);
954 
955                 /* Still unsure why there is a this subnet mask. maybe natt'ed by the modem? */
956                 if (res.set.ipv4_gateway_subnet_mask) {
957                         ipv4_to_sockaddr(res.data.ipv4_gateway_subnet_mask,
958                                          (struct sockaddr_in *)&modem->brearer.v4_netmask);
959                 }
960 
961                 if (res.set.ipv4_gateway_address) {
962                         ipv4_to_sockaddr(res.data.ipv4_gateway_address,
963                                          (struct sockaddr_in *)&modem->brearer.v4_gateway);
964                 }
965 
966                 if (res.set.primary_ipv4_dns_address) {
967                         ipv4_to_sockaddr(res.data.primary_ipv4_dns_address, (struct sockaddr_in *)&modem->brearer.dns1);
968                 }
969 
970                 if (res.set.secondary_ipv4_dns_address) {
971                         ipv4_to_sockaddr(res.data.secondary_ipv4_dns_address,
972                                          (struct sockaddr_in *)&modem->brearer.dns2);
973                 }
974                 break;
975         case QMI_WDS_IP_FAMILY_IPV6:
976                 if (!res.set.ipv6_address) {
977                         modem_log(modem, LOGL_ERROR, "Modem didn't include IPv6 Address.");
978                         osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_FAILED, (void *)3);
979                 }
980 
981                 if (res.set.ipv6_primary_dns_address) {
982                         ipv6_to_sockaddr(res.data.ipv6_primary_dns_address,
983                                          (struct sockaddr_in6 *)&modem->brearer.dns1);
984                 }
985 
986                 if (res.set.ipv6_secondary_dns_address) {
987                         ipv6_to_sockaddr(res.data.ipv6_secondary_dns_address,
988                                          (struct sockaddr_in6 *)&modem->brearer.dns2);
989                 }
990 
991                 break;
992         default:
993                 modem_log(modem, LOGL_ERROR, "Modem reported an unknown ip_family %d.", res.data.ip_family);
994                 osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_FAILED, (void *)4);
995                 break;
996         }
997 
998         osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_RX_SUCCEED, NULL);
999 }
1000 
1001 static void modem_st_live_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
1002 {
1003         struct modem *modem = fi->priv;
1004         struct qmi_service *wds = uqmi_service_find(modem->qmi, QMI_SERVICE_WDS);
1005 
1006         tx_wds_get_current_settings(modem, wds, wds_get_current_settings_cb);
1007         /* TODO: register to indications */
1008 }
1009 
1010 static void modem_st_live(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1011 {
1012         switch (event) {
1013         case MODEM_EV_RX_FAILED:
1014                 break;
1015         case MODEM_EV_RX_SUCCEED:
1016                 break;
1017         }
1018 }
1019 
1020 static void modem_st_failed(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1021 {
1022 }
1023 
1024 static void modem_st_destroy_onenter(struct osmo_fsm_inst *fi, uint32_t old_state)
1025 {
1026         struct modem *modem = fi->priv;
1027 
1028         /* FIXME: try to close the network, poweroff the modem ? */
1029         qmi_device_close(modem->qmi, 5000);
1030 }
1031 static void modem_st_destroy(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1032 {
1033 }
1034 
1035 static int modem_fsm_timer_cb(struct osmo_fsm_inst *fi)
1036 {
1037         struct modem *modem = fi->priv;
1038         struct qmi_service *service;
1039 
1040         switch (fi->state) {
1041         case MODEM_ST_NETSEARCH:
1042                 service = uqmi_service_find(modem->qmi, QMI_SERVICE_NAS);
1043                 if (!service) {
1044                         modem_log(modem, LOGL_ERROR, "NAS service doesn't exist");
1045                         return 1;
1046                 }
1047                 uqmi_service_send_simple(service, qmi_set_nas_get_serving_system_request, get_serving_system_cb, modem);
1048                 osmo_timer_schedule(&fi->timer, NAS_SERVICE_POLL_TIMEOUT_S, 0);
1049                 break;
1050         case MODEM_ST_START_IFACE:
1051                 switch (fi->T) {
1052                 case N_RESEND:
1053                         /* resend the packet */
1054                         service = uqmi_service_find(modem->qmi, QMI_SERVICE_WDS);
1055                         if (!service) {
1056                                 modem_log(modem, LOGL_ERROR, "WDS service doesn't exist");
1057                                 return 1;
1058                         }
1059                         tx_wds_start_network(modem, service, wds_start_network_cb, modem->qmi->wds.profile_id,
1060                                              modem->qmi->wds.ip_family);
1061                         osmo_timer_schedule(&fi->timer, 5, 0);
1062                         break;
1063                 default:
1064                         /* we timedout ! No answer? */
1065                         modem_log(modem, LOGL_ERROR, "WDS: Couldn't start the interface!");
1066                         /* TODO: enter failure state */
1067                         break;
1068                 }
1069                 break;
1070         default:
1071                 switch (fi->T) {
1072                 case N_FAILURE:
1073                         modem_log(modem, LOGL_ERROR, "State timedout. Entering failure state");
1074                         osmo_fsm_inst_state_chg(fi, MODEM_ST_FAILED, 0, 0);
1075                         break;
1076                 }
1077 
1078                 break;
1079         }
1080 
1081         return 0;
1082 }
1083 
1084 static void modem_fsm_allstate_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
1085 {
1086         switch (event) {
1087         case MODEM_EV_REQ_DESTROY:
1088                 osmo_fsm_inst_state_chg(fi, MODEM_ST_DESTROY, 0, 0);
1089                 break;
1090         }
1091 }
1092 
1093 static const struct osmo_fsm_state modem_states[] = {
1094         [MODEM_ST_IDLE] = {
1095                 .in_event_mask = S(MODEM_EV_REQ_START),
1096                 .out_state_mask = S(MODEM_ST_RESYNC) | S(MODEM_ST_DESTROY),
1097                 .name = "UNCONFIGURED",
1098                 .action = modem_st_unconfigured,
1099         },
1100         [MODEM_ST_RESYNC] = {
1101                 .in_event_mask = S(MODEM_EV_RX_SYNC),
1102                 .out_state_mask = S(MODEM_ST_GET_VERSION)
1103                                   | S(MODEM_ST_FAILED)
1104                                   | S(MODEM_ST_DESTROY),
1105                 .name = "RESYNC",
1106                 .action = modem_st_resync,
1107                 .onenter = modem_st_resync_onenter,
1108         },
1109         [MODEM_ST_GET_VERSION] = {
1110                 .in_event_mask = S(MODEM_EV_RX_VERSION),
1111                 .out_state_mask = S(MODEM_ST_GET_MODEL) | S(MODEM_ST_DESTROY),
1112                 .name = "GET_VERSION",
1113                 .action = modem_st_get_version,
1114                 .onenter = modem_st_get_version_onenter,
1115         },
1116         [MODEM_ST_GET_MODEL] = {
1117                 .in_event_mask = S(MODEM_EV_RX_MODEL) |
1118                                  S(MODEM_EV_RX_MANUFACTURER) |
1119                                  S(MODEM_EV_RX_REVISION) |
1120                                  S(MODEM_EV_RX_IMEI),
1121                 .out_state_mask = S(MODEM_ST_POWEROFF) | S(MODEM_ST_DESTROY),
1122                 .name = "GET_MODEL",
1123                 .action = modem_st_get_model,
1124                 .onenter = modem_st_get_model_onenter,
1125         },
1126         [MODEM_ST_POWEROFF] = {
1127                 .in_event_mask = S(MODEM_EV_RX_POWEROFF)
1128                                  | S(MODEM_EV_RX_POWERON)
1129                                  | S(MODEM_EV_RX_POWERSET)
1130                                  | S(MODEM_EV_REQ_CONFIGURED),
1131                 .out_state_mask = S(MODEM_ST_CONFIGURE_MODEM)
1132                                   | S(MODEM_ST_DESTROY)
1133                                   | S(MODEM_ST_WAIT_UIM),
1134                 .name = "POWEROFF",
1135                 .action = modem_st_poweroff,
1136                 .onenter = modem_st_poweroff_onenter,
1137         },
1138         [MODEM_ST_WAIT_UIM] = {
1139                 .in_event_mask = S(MODEM_EV_REQ_SIM_READY),
1140                 .out_state_mask = S(MODEM_ST_CONFIGURE_MODEM) | S(MODEM_ST_DESTROY),
1141                 .name = "WAIT_UIM",
1142                 .action = modem_st_wait_uim,
1143                 .onenter = modem_st_wait_uim_onenter,
1144         },
1145         [MODEM_ST_CONFIGURE_MODEM] = {
1146                 .in_event_mask = S(MODEM_EV_RX_CONFIGURED)
1147                                  | S(MODEM_EV_RX_GET_PROFILE_LIST)
1148                                  | S(MODEM_EV_RX_MODIFIED_PROFILE),
1149                 .out_state_mask = S(MODEM_ST_CONFIGURE_KERNEL) | S(MODEM_ST_DESTROY),
1150                 .name = "CONFIGURE_MODEM",
1151                 .action = modem_st_configure_modem,
1152                 .onenter = modem_st_configure_modem_onenter,
1153         },
1154         [MODEM_ST_CONFIGURE_KERNEL] = {
1155                 .in_event_mask = S(MODEM_EV_RX_SUCCEED),
1156                 .out_state_mask = S(MODEM_ST_POWERON) | S(MODEM_ST_DESTROY),
1157                 .name = "CONFIGURE_KERNEL",
1158                 .action = modem_st_configure_kernel,
1159                 .onenter = modem_st_configure_kernel_onenter,
1160         },
1161         [MODEM_ST_POWERON] = {
1162                 .in_event_mask = S(MODEM_EV_RX_POWEROFF)
1163                                  | S(MODEM_EV_RX_POWERON)
1164                                  | S(MODEM_EV_RX_POWERSET),
1165                 .out_state_mask = S(MODEM_ST_NETSEARCH) | S(MODEM_ST_DESTROY),
1166                 .name = "POWERON",
1167                 .action = modem_st_poweron,
1168                 .onenter = modem_st_poweron_onenter,
1169         },
1170         [MODEM_ST_NETSEARCH] = {
1171                 .in_event_mask = S(MODEM_EV_RX_REGISTERED)
1172                                  | S(MODEM_EV_RX_UNREGISTERED)
1173                                  | S(MODEM_EV_RX_SEARCHING)
1174                                  | S(MODEM_EV_RX_FAILED)
1175                                  | S(MODEM_EV_RX_SUBSCRIBED)
1176                                  | S(MODEM_EV_RX_SUBSCRIBE_FAILED),
1177                 .out_state_mask = S(MODEM_ST_REGISTERED) | S(MODEM_ST_DESTROY),
1178                 .name = "NETSEARCH",
1179                 .action = modem_st_netsearch,
1180                 .onenter = modem_st_netsearch_onenter,
1181         },
1182         [MODEM_ST_REGISTERED] = {
1183                 .in_event_mask = 0,
1184                 .out_state_mask = S(MODEM_ST_START_IFACE) | S(MODEM_ST_DESTROY),
1185                 .name = "REGISTERED",
1186                 .action = modem_st_registered,
1187                 .onenter = modem_st_registered_onenter,
1188         },
1189         [MODEM_ST_START_IFACE] = {
1190                 .in_event_mask = S(MODEM_EV_RX_SUCCEED)
1191                                  | S(MODEM_EV_RX_FAILED)
1192                                  | S(MODEM_EV_RX_DISABLE_AUTOCONNECT_SUCCESS),
1193                 .out_state_mask = S(MODEM_ST_LIVE) | S(MODEM_ST_DESTROY) | S(MODEM_ST_POWEROFF),
1194                 .name = "START_IFACE",
1195                 .action = modem_st_start_iface,
1196                 .onenter = modem_st_start_iface_onenter,
1197         },
1198         [MODEM_ST_LIVE] = {
1199                 .in_event_mask = S(MODEM_EV_RX_SUCCEED) | S(MODEM_EV_RX_FAILED),
1200                 .out_state_mask = S(MODEM_ST_DESTROY),
1201                 .name = "LIVE",
1202                 .action = modem_st_live,
1203                 .onenter = modem_st_live_onenter,
1204         },
1205         [MODEM_ST_FAILED] = {
1206                 .in_event_mask = 0,
1207                 .out_state_mask = S(MODEM_ST_DESTROY),
1208                 .name = "FAILED",
1209                 .action = modem_st_failed,
1210                 // .onenter = modem_st_live_onenter,s
1211         },
1212         [MODEM_ST_DESTROY] = {
1213                 .in_event_mask = 0,
1214                 .out_state_mask = 0,
1215                 .name = "DESTROY",
1216                 .action = modem_st_destroy,
1217                 .onenter = modem_st_destroy_onenter,
1218         },
1219 };
1220 
1221 static struct osmo_fsm modem_fsm = {
1222         .name = "MODEM",
1223         .states = modem_states,
1224         .num_states = ARRAY_SIZE(modem_states),
1225         .allstate_event_mask = S(MODEM_EV_REQ_DESTROY),
1226         .allstate_action = modem_fsm_allstate_action,
1227         //    .cleanup = modem_fsm_cleanup,
1228         .timer_cb = modem_fsm_timer_cb,
1229         .event_names = modem_event_names,
1230         .pre_term = NULL,
1231 };
1232 
1233 struct osmo_fsm_inst *modem_fsm_alloc(struct modem *modem)
1234 {
1235         return osmo_fsm_inst_alloc(&modem_fsm, modem, modem, LOGL_DEBUG, modem->name);
1236 }
1237 
1238 static __attribute__((constructor)) void on_dso_load_ctx(void)
1239 {
1240         OSMO_ASSERT(osmo_fsm_register(&modem_fsm) == 0);
1241 }
1242 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt