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

Sources/uqmi/uqmid/modem.c

  1 /*
  2  * uqmi -- tiny QMI support implementation
  3  *
  4  * Copyright (C) 2023 Alexander Couzens <lynxis@fe80.eu>
  5  *
  6  * This library is free software; you can redistribute it and/or
  7  * modify it under the terms of the GNU Lesser General Public
  8  * License as published by the Free Software Foundation; either
  9  * version 2 of the License, or (at your option) any later version.
 10  *
 11  * This library is distributed in the hope that it will be useful,
 12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 14  * Lesser General Public License for more details.
 15  *
 16  * You should have received a copy of the GNU Lesser General Public
 17  * License along with this library; if not, write to the
 18  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 19  * Boston, MA 02110-1301 USA.
 20  */
 21 
 22 /* Used by uqmid to contain the modem state */
 23 
 24 #include <fcntl.h>
 25 #include <unistd.h>
 26 #include <stdlib.h>
 27 #include <stdio.h>
 28 #include <string.h>
 29 #include <talloc.h>
 30 
 31 #include "qmi-message.h"
 32 
 33 #include "qmi-enums-dms.h"
 34 #include "qmi-enums-wds.h"
 35 #include "qmi-enums.h"
 36 #include "sim_fsm.h"
 37 #include "uqmid.h"
 38 #include "qmi-errors.h"
 39 #include "qmi-errors.c"
 40 
 41 #include "mbim.h"
 42 #include "services.h"
 43 
 44 #include "modem.h"
 45 #include "modem_fsm.h"
 46 #include "modem_tx.h"
 47 #include "osmocom/fsm.h"
 48 #include "ubus.h"
 49 #include "logging.h"
 50 #include "utils.h"
 51 
 52 LIST_HEAD(uqmid_modems);
 53 
 54 struct modem *
 55 uqmid_modem_find_by_device(const char *device)
 56 {
 57         struct modem *modem;
 58 
 59         list_for_each_entry(modem, &uqmid_modems, list) {
 60                 if (!strcmp(device, modem->device))
 61                         return modem;
 62         }
 63 
 64         return NULL;
 65 }
 66 
 67 struct modem *
 68 uqmid_modem_find_by_name(const char *name)
 69 {
 70         struct modem *modem;
 71         list_for_each_entry(modem, &uqmid_modems, list) {
 72                 if (!strcmp(name, modem->name))
 73                         return modem;
 74         }
 75 
 76         return NULL;
 77 }
 78 
 79 static void
 80 modem_error_cb(struct qmi_dev *dev, void *data)
 81 {
 82         struct modem *modem = data;
 83 
 84         osmo_fsm_inst_term(modem->fi, OSMO_FSM_TERM_ERROR, modem);
 85         uqmid_ubus_modem_destroy(modem);
 86         qmi_device_close(modem->qmi, 0);
 87 
 88         list_del(&modem->list);
 89         talloc_free(modem);
 90 }
 91 
 92 /**
 93  *
 94  * @param name an unique name also used by ubus
 95  * @param device path to the device. /dev/cdc-wdm0
 96  * @param qmi_over_mbim true if qmi needs to be tunneled over mbim
 97  * @return 0 on success
 98  */
 99 int
100 uqmid_modem_add(const char *name, const char *device, bool qmi_over_mbim)
101 {
102         struct modem *modem = uqmid_modem_find_by_name(name);
103         int ret;
104         if (modem)
105                 return -EALREADY;
106 
107         modem = talloc_zero(NULL, struct modem);
108         modem->name = talloc_strdup(modem, name);
109         modem->device = talloc_strdup(modem, device);
110         modem->qmi = qmi_device_open(modem, device);
111         if (!modem->qmi)
112                 goto err;
113 
114         ret = uqmid_ubus_modem_add(modem);
115         if (ret)
116                 goto err;
117 
118         modem->qmi->error_cb = modem_error_cb;
119         modem->qmi->error_cb_data = modem;
120         modem->sim.use_uim = true;
121 
122         modem->fi = modem_fsm_alloc(modem);
123         modem->sim.fi = sim_fsm_alloc(modem);
124         list_add(&modem->list, &uqmid_modems);
125         modem_fsm_start(modem);
126 
127         return 0;
128 
129 err:
130         if (modem->qmi)
131                 qmi_device_close(modem->qmi, 0);
132 
133         talloc_free(modem);
134         return -1;
135 }
136 
137 
138 static void
139 modem_remove_cb(struct qmi_dev *dev, void *data)
140 {
141         struct modem *modem = data;
142 
143         osmo_fsm_inst_term(modem->fi, OSMO_FSM_TERM_REGULAR, modem);
144         uqmid_ubus_modem_destroy(modem);
145 
146         list_del(&modem->list);
147         talloc_free(modem);
148 }
149 
150 int
151 uqmid_modem_remove(struct modem *modem)
152 {
153         if (!modem)
154                 return -EINVAL;
155 
156         if (!modem->fi)
157                 return 0;
158 
159         if (modem->fi->state == MODEM_ST_DESTROY)
160                 return 0;
161 
162         if (modem->fi->proc.terminating)
163                 return 0;
164 
165         /* TODO: move the assignment of closing_cb */
166         modem->qmi->closing_cb = modem_remove_cb;
167         modem->qmi->closing_cb_data = modem;
168         osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_REQ_DESTROY, modem);
169 
170         return 0;
171 }
172 
173 int
174 uqmid_modem_configured(struct modem *modem)
175 {
176         osmo_fsm_inst_dispatch(modem->fi, MODEM_EV_REQ_CONFIGURED, NULL);
177         return 0;
178 }
179 
180 static void
181 wds_get_packet_status_cb(struct qmi_service *service, struct qmi_request *req, struct qmi_msg *msg)
182 {
183         struct modem *modem = req->cb_data;
184         int ret = 0;
185         struct qmi_wds_get_packet_service_status_response res = {};
186 
187         if (req->ret) {
188                 modem_log(modem, LOGL_INFO, "Failed to get operating mode. Status %d/%s.", req->ret, qmi_get_error_str(req->ret));
189                 /* FIXME: send ubus failed */
190                 return;
191         }
192 
193         ret = qmi_parse_wds_get_packet_service_status_response(msg, &res);
194         if (ret) {
195                 modem_log(modem, LOGL_INFO, "Failed to get packet service status. Failed to parse message");
196                 /* FIXME: send ubus failed */
197                 return;
198         }
199 
200         if (!res.set.connection_status) {
201                 modem_log(modem, LOGL_INFO, "Failed to get packet service status. No connection status");
202         }
203 
204         modem_log(modem, LOGL_INFO, "Conn Status is %d", res.data.connection_status);
205 
206         /* Fix send back */
207         return;
208 }
209 
210 struct modem_opmode_data {
211         struct modem *modem;
212         void *cb_data;
213         uqmid_modem_get_opmode_cb cb;
214 };
215 
216 static void
217 modem_get_opmode_cb(struct qmi_service *service, struct qmi_request *req, struct qmi_msg *msg)
218 {
219         struct modem_opmode_data *data= req->cb_data;
220         struct modem *modem = data->modem;
221         int ret = 0;
222         struct qmi_dms_get_operating_mode_response res = {};
223 
224         if (!data) {
225                 return;
226         }
227 
228         if (req->ret) {
229                 modem_log(modem, LOGL_INFO, "Failed to get operating mode. Status %d/%s.", req->ret, qmi_get_error_str(req->ret));
230                 goto out;
231         }
232 
233         ret = qmi_parse_dms_get_operating_mode_response(msg, &res);
234         if (ret) {
235                 modem_log(modem, LOGL_INFO, "Failed to get operating mode. Failed to parse message");
236                 goto out;
237         }
238 
239         if (!res.set.mode) {
240                 modem_log(modem, LOGL_INFO, "Failed to get operating mode. Failed to parse message");
241         }
242 
243         modem_log(modem, LOGL_INFO, "Opmode is %d", res.data.mode);
244         data->cb(data->cb_data, 0, res.data.mode);
245 out:
246         free(data);
247         return;
248 }
249 
250 int
251 uqmid_modem_get_opmode(struct modem *modem, uqmid_modem_get_opmode_cb cb, void *cb_data)
252 {
253         struct qmi_service *dms = uqmi_service_find(modem->qmi, QMI_SERVICE_DMS);
254         if (!dms) {
255                 cb(cb_data, -ENOENT, 0);
256                 modem_log(modem, LOGL_ERROR, "Ubus call requested, but dms not available.");
257                 return -1;
258         }
259 
260         struct modem_opmode_data *data = calloc(1, sizeof(*data));
261         if (!data) {
262                 cb(cb_data, -ENOMEM, 0);
263                 return -1;
264         }
265 
266         data->cb = cb;
267         data->cb_data = cb_data;
268         data->modem = modem;
269 
270         uqmi_service_send_simple(dms, qmi_set_dms_get_operating_mode_request, modem_get_opmode_cb, data);
271         return 0;
272 }
273 
274 int uqmid_modem_networkstatus(struct modem *modem)
275 {
276         struct qmi_service *wds = uqmi_service_find(modem->qmi, QMI_SERVICE_WDS);
277         if (!wds) {
278                 modem_log(modem, LOGL_ERROR, "Ubus call requested, but wds not available.");
279                 return -1;
280         }
281 
282         uqmi_service_send_simple(wds, qmi_set_wds_get_packet_service_status_request, wds_get_packet_status_cb, modem);
283         return 0;
284 }
285 
286 void uqmid_modem_set_error(struct modem *modem, const char *error)
287 {
288         if (modem->state.error) {
289                 talloc_free(modem->state.error);
290         }
291 
292         if (error) {
293                 modem_log(modem, LOGL_ERROR, "failed with %s", error);
294                 modem->state.error = talloc_strdup(modem, error);
295         } else {
296                 modem->state.error = NULL;
297         }
298 }
299 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt