5 * Copyright (C) 2007-2010 Intel Corporation. All rights reserved.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * This program 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
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
32 #define CONNMAN_API_SUBJECT_TO_CHANGE
33 #include <connman/plugin.h>
34 #include <connman/device.h>
35 #include <connman/inet.h>
36 #include <connman/log.h>
39 #include <WiMaxAPIEx.h>
44 * Connman plugin interface
46 * This part deals with the connman internals
49 /* WiMAX network driver probe/remove, nops */
50 static int iwmx_cm_network_probe(struct connman_network *nw)
55 static void iwmx_cm_network_remove(struct connman_network *nw)
60 * Called by connman when it wants us to tell the device to connect to
61 * the network @network_el; the device is @network_el->parent.
63 * We do a synchronous call to start the connection; the logic
64 * attached to the status change callback will update the connman
65 * internals once the change happens.
67 static int iwmx_cm_network_connect(struct connman_network *nw)
70 struct wmxsdk *wmxsdk;
71 const char *station_name = connman_network_get_identifier(nw);
73 wmxsdk = connman_device_get_data(connman_network_get_device(nw));
74 result = iwmx_sdk_connect(wmxsdk, nw);
75 DBG("(nw %p [%s] wmxsdk %p) = %d\n", nw, station_name, wmxsdk, result);
80 * Called by connman to have the device @nw->parent
81 * disconnected from @nw.
83 * We do a synchronous call to start the disconnection; the logic
84 * attached to the status change callback will update the connman
85 * internals once the change happens.
87 static int iwmx_cm_network_disconnect(struct connman_network *nw)
90 struct wmxsdk *wmxsdk;
91 const char *station_name = connman_network_get_identifier(nw);
93 wmxsdk = connman_device_get_data(connman_network_get_device(nw));
94 result = iwmx_sdk_disconnect(wmxsdk);
95 DBG("(nw %p [%s] wmxsdk %p) = %d\n", nw, station_name, wmxsdk, result);
100 * "Driver" for the networks detected by a device.
102 static struct connman_network_driver iwmx_cm_network_driver = {
104 .type = CONNMAN_NETWORK_TYPE_WIMAX,
105 .probe = iwmx_cm_network_probe,
106 .remove = iwmx_cm_network_remove,
107 .connect = iwmx_cm_network_connect,
108 .disconnect = iwmx_cm_network_disconnect,
112 * A (maybe) new network is available, create/update its data
114 * If the network is new, we create and register a new element; if it
115 * is not, we reuse the one in the list.
118 * wmxsdk->network_mutex has to be locked
120 struct connman_network *__iwmx_cm_network_available(
121 struct wmxsdk *wmxsdk, const char *station_name,
122 const char *station_type,
123 const void *sdk_nspname, size_t sdk_nspname_size,
126 struct connman_network *nw = NULL;
127 struct connman_device *dev = wmxsdk->dev;
128 char group[3 * strlen(station_name) + 1];
131 nw = connman_device_get_network(dev, station_name);
133 DBG("new network %s", station_name);
134 nw = connman_network_create(station_name,
135 CONNMAN_NETWORK_TYPE_WIMAX);
136 connman_network_set_index(nw, connman_device_get_index(dev));
137 connman_network_set_protocol(nw, CONNMAN_NETWORK_PROTOCOL_IP);
138 connman_network_set_name(nw, station_name);
139 connman_network_set_blob(nw, "WiMAX.NSP.name",
140 sdk_nspname, sdk_nspname_size);
141 /* FIXME: add roaming info? */
142 /* Set the group name -- this has to be a unique
143 * [a-zA-Z0-9_] string common to all the networks that
144 * are actually the same provider. In WiMAX each
145 * network from the CAPI is a single provider, so we
146 * just set this as the network name, encoded in
148 for (cnt = 0; station_name[cnt] != 0; cnt++)
149 sprintf(group + 3 * cnt, "%02x", station_name[cnt]);
150 group[3 * cnt + 1] = 0;
151 connman_network_set_group(nw, station_name);
152 if (connman_device_add_network(dev, nw) < 0) {
153 connman_network_unref(nw);
157 DBG("updating network %s nw %p\n", station_name, nw);
158 connman_network_set_available(nw, TRUE);
159 connman_network_set_strength(nw, strength);
160 connman_network_set_string(nw, "WiMAX Network Type", station_type);
166 * A new network is available [locking version]
168 * See __iwmx_cm_network_available() for docs
170 struct connman_network *iwmx_cm_network_available(
171 struct wmxsdk *wmxsdk, const char *station_name,
172 const char *station_type,
173 const void *sdk_nspname, size_t sdk_nspname_size,
176 struct connman_network *nw;
178 g_static_mutex_lock(&wmxsdk->network_mutex);
179 nw = __iwmx_cm_network_available(wmxsdk, station_name, station_type,
180 sdk_nspname, sdk_nspname_size,
182 g_static_mutex_unlock(&wmxsdk->network_mutex);
187 * The device has been enabled, make sure connman knows
189 static void iwmx_cm_dev_enabled(struct wmxsdk *wmxsdk)
191 struct connman_device *dev = wmxsdk->dev;
192 connman_inet_ifup(connman_device_get_index(dev));
193 connman_device_set_powered(dev, TRUE);
197 * The device has been disabled, make sure connman is aware of it.
199 static void iwmx_cm_dev_disabled(struct wmxsdk *wmxsdk)
201 struct connman_device *dev = wmxsdk->dev;
202 connman_inet_ifdown(connman_device_get_index(dev));
203 connman_device_set_powered(dev, FALSE);
207 * The device has been (externally to connman) connnected to a
208 * network, make sure connman knows.
210 * When the device is connected to a network, this function is called
211 * to change connman's internal state to reflect the fact.
213 * If the change came from an external entity, that means that our
214 * connect code wasn't called. Our connect code sets
215 * @wmxsdk->connecting_nw to the network we were connecting
216 * to. If it is unset, it means an external entity forced the device
217 * to connect. In that case, we need to find out which network it was
218 * connected to, and create/lookup a @nw for it.
220 * Once the nw is set, then we are done.
222 static void iwmx_cm_dev_connected(struct wmxsdk *wmxsdk)
224 struct connman_network *nw;
226 g_mutex_lock(wmxsdk->connect_mutex);
227 nw = wmxsdk->connecting_nw;
229 nw = __iwmx_sdk_get_connected_network(wmxsdk);
231 connman_error("wmxsdk: can't find connected network\n");
235 wmxsdk->nw = connman_network_ref(nw);
236 wmxsdk->connecting_nw = NULL;
237 connman_network_set_method(network, CONNMAN_IPCONFIG_METHOD_DHCP);
238 connman_network_set_connected(nw, TRUE);
239 DBG("connected to network %s\n",
240 connman_network_get_identifier(nw));
242 g_mutex_unlock(wmxsdk->connect_mutex);
246 * The device has been (externally to connman) disconnnected, make
249 * We need to reverse the steps done in iwmx_cm_dev_connected().
250 * If the event was caused by an external entity and we had no record
251 * of being connected to a network...well, bad luck. We'll just
252 * pretend it happened ok.
254 static void __iwmx_cm_dev_disconnected(struct wmxsdk *wmxsdk)
256 struct connman_network *nw = wmxsdk->nw;
259 DBG("disconnected from network %s\n",
260 connman_network_get_identifier(nw));
261 connman_network_set_connected(nw, FALSE);
262 connman_network_unref(nw);
265 DBG("disconnected from unknown network\n");
269 * The device has been disconnnected, make sure connman knows
271 * See __iwmx_cm_dev_disconnect() for more information.
273 static void iwmx_cm_dev_disconnected(struct wmxsdk *wmxsdk)
275 g_mutex_lock(wmxsdk->connect_mutex);
276 __iwmx_cm_dev_disconnected(wmxsdk);
277 g_mutex_unlock(wmxsdk->connect_mutex);
281 * Handle a change in state
283 * This is were most of the action happens. When the device changes
284 * state, this will catch it (through the state change callback or an
285 * explicit call) and call iwmx_cm_dev_*ed() to indicate to connman what
288 * Finally, cache the new device status.
290 void __iwmx_cm_state_change(struct wmxsdk *wmxsdk,
291 WIMAX_API_DEVICE_STATUS __new_status)
293 WIMAX_API_DEVICE_STATUS __old_status = wmxsdk->status;
294 WIMAX_API_DEVICE_STATUS old_status;
295 WIMAX_API_DEVICE_STATUS new_status;
298 * Simplify state transition computations.
300 * For practical effects, some states are the same
303 #if HAVE_IWMXSDK_STATUS_IDLE
304 /* Conection_Idle is the same as Data_Connected */
305 if (__old_status == WIMAX_API_DEVICE_STATUS_Connection_Idle)
306 old_status = WIMAX_API_DEVICE_STATUS_Data_Connected;
308 old_status = __old_status;
309 if (__new_status == WIMAX_API_DEVICE_STATUS_Connection_Idle)
310 new_status = WIMAX_API_DEVICE_STATUS_Data_Connected;
312 new_status = __new_status;
313 #endif /* #if HAVE_IWMXSDK_STATUS_IDLE */
314 /* Radio off: all are just RF_OFF_SW (the highest) */
315 switch (__old_status) {
316 case WIMAX_API_DEVICE_STATUS_RF_OFF_HW_SW:
317 case WIMAX_API_DEVICE_STATUS_RF_OFF_HW:
318 case WIMAX_API_DEVICE_STATUS_RF_OFF_SW:
319 old_status = WIMAX_API_DEVICE_STATUS_RF_OFF_SW;
322 old_status = __old_status;
326 switch (__new_status) {
327 case WIMAX_API_DEVICE_STATUS_RF_OFF_HW_SW:
328 case WIMAX_API_DEVICE_STATUS_RF_OFF_HW:
329 case WIMAX_API_DEVICE_STATUS_RF_OFF_SW:
330 new_status = WIMAX_API_DEVICE_STATUS_RF_OFF_SW;
333 new_status = __new_status;
337 /* If no real state change, do nothing */
338 if (old_status == new_status) {
339 DBG("no state changed\n");
342 DBG("state change from %d (%d: %s) to %d (%d: %s)\n",
343 old_status, __old_status,
344 iwmx_sdk_dev_status_to_str(__old_status),
345 new_status, __new_status,
346 iwmx_sdk_dev_status_to_str(__new_status));
348 /* Cleanup old state */
349 switch (old_status) {
350 case WIMAX_API_DEVICE_STATUS_UnInitialized:
351 /* This means the plugin is starting but the device is
352 * in some state already, so we need to update our
353 * internal knowledge of it. */
354 if (new_status > WIMAX_API_DEVICE_STATUS_RF_OFF_SW)
355 iwmx_cm_dev_enabled(wmxsdk);
357 case WIMAX_API_DEVICE_STATUS_RF_OFF_SW:
358 /* This means the radio is being turned on, so enable
359 * the device ( unless going to uninitialized). */
360 if (new_status != WIMAX_API_DEVICE_STATUS_RF_OFF_SW)
361 iwmx_cm_dev_enabled(wmxsdk);
363 case WIMAX_API_DEVICE_STATUS_Ready:
365 case WIMAX_API_DEVICE_STATUS_Scanning:
367 case WIMAX_API_DEVICE_STATUS_Connecting:
369 case WIMAX_API_DEVICE_STATUS_Data_Connected:
370 iwmx_cm_dev_disconnected(wmxsdk);
373 connman_error("wmxsdk: unknown old status %d\n", old_status);
377 /* Implement new state */
378 switch (new_status) {
379 case WIMAX_API_DEVICE_STATUS_UnInitialized:
381 case WIMAX_API_DEVICE_STATUS_RF_OFF_SW:
382 /* This means the radio is being turned off, so
383 * disable the device unless coming from uninitialized. */
384 if (old_status != WIMAX_API_DEVICE_STATUS_UnInitialized)
385 iwmx_cm_dev_disabled(wmxsdk);
387 case WIMAX_API_DEVICE_STATUS_Ready:
389 case WIMAX_API_DEVICE_STATUS_Scanning:
391 case WIMAX_API_DEVICE_STATUS_Connecting:
393 case WIMAX_API_DEVICE_STATUS_Data_Connected:
394 iwmx_cm_dev_connected(wmxsdk);
397 connman_error("wmxsdk: unknown new status %d\n", old_status);
400 wmxsdk->status = __new_status;
404 * Implement a device state transition [locking version]
406 * See __iwmx_cm_state_change()
408 void iwmx_cm_state_change(struct wmxsdk *wmxsdk,
409 WIMAX_API_DEVICE_STATUS __new_status)
411 g_mutex_lock(wmxsdk->status_mutex);
412 __iwmx_cm_state_change(wmxsdk, __new_status);
413 g_mutex_unlock(wmxsdk->status_mutex);
417 * Read the cached device status
419 WIMAX_API_DEVICE_STATUS iwmx_cm_status_get(struct wmxsdk *wmxsdk)
421 WIMAX_API_DEVICE_STATUS status;
423 g_mutex_lock(wmxsdk->status_mutex);
424 status = wmxsdk->status;
425 g_mutex_unlock(wmxsdk->status_mutex);
430 * Called by connman when a device is enabled by the user
432 * We need to turn the radio on; the state change function will poke
435 static int iwmx_cm_enable(struct connman_device *dev)
438 struct wmxsdk *wmxsdk = connman_device_get_data(dev);
440 connman_inet_ifup(connman_device_get_index(dev));
441 result = iwmx_sdk_rf_state_set(wmxsdk, WIMAX_API_RF_ON);
446 * Called by connman when a device is disabled by the user
448 * Simple: just make sure the radio is off; the state change function
449 * will poke the internals.
451 static int iwmx_cm_disable(struct connman_device *dev)
454 struct wmxsdk *wmxsdk = connman_device_get_data(dev);
456 result = iwmx_sdk_rf_state_set(wmxsdk, WIMAX_API_RF_OFF);
457 connman_inet_ifdown(connman_device_get_index(dev));
462 * Probe deferred call from when the mainloop is idle
464 * probe() schedules this to be called from the mainloop when idle to
465 * do a device status evaluation. Needed because of an internal race
466 * condition in connman. FIXME: deploy into _probe() when fixed.
468 static gboolean __iwmx_cm_probe_dpc(gpointer _wmxsdk)
471 struct wmxsdk *wmxsdk = _wmxsdk;
472 result = iwmx_sdk_get_device_status(wmxsdk);
474 connman_error("wmxsdk: can't get status: %d\n", result);
476 iwmx_cm_state_change(wmxsdk, result);
481 * Called by connman when a new device pops in
483 * We allocate our private structure, register with the WiMAX API,
484 * open their device, subscribe to all the callbacks.
486 * At the end, we launch a deferred call (to work around current
487 * connman issues that need to be fixed in the future) and update the
488 * device's status. This allows us to pick up the current status and
489 * adapt connman's idea of the device to it.
491 static int iwmx_cm_probe(struct connman_device *dev)
494 struct wmxsdk *wmxsdk = NULL;
496 wmxsdk = connman_device_get_data(dev);
498 /* not called from a discovery done by the WiMAX
499 * Network Service, ignore */
502 result = iwmx_sdk_setup(wmxsdk);
506 /* There is a race condition in the connman core that doesn't
507 * allow us to call this directly and things to work properly
508 * FIXME FIXME FIXME: merge _dpc call in here when connman is fixed */
509 g_idle_add(__iwmx_cm_probe_dpc, wmxsdk);
512 iwmx_sdk_remove(wmxsdk);
518 * Called when a device is removed from connman
520 * Cleanup all that is done in _probe. Remove callbacks, unregister
521 * from the WiMAX API.
523 static void iwmx_cm_remove(struct connman_device *dev)
525 struct wmxsdk *wmxsdk = connman_device_get_data(dev);
526 iwmx_sdk_remove(wmxsdk);
530 * Called by connman to ask the device to scan for networks
532 * We have set in the WiMAX API the scan result callbacks, so we just
533 * start a simple scan (not a wide one).
535 * First we obtain the current list of networks and pass it to the
536 * callback processor. Then we start an scan cycle.
538 static int iwmx_cm_scan(struct connman_device *dev)
540 struct wmxsdk *wmxsdk = connman_device_get_data(dev);
541 return iwmx_sdk_scan(wmxsdk);
545 * Driver for a WiMAX API based device.
547 static struct connman_device_driver iwmx_cm_device_driver = {
549 .type = CONNMAN_DEVICE_TYPE_WIMAX,
550 .probe = iwmx_cm_probe,
551 .remove = iwmx_cm_remove,
552 .enable = iwmx_cm_enable,
553 .disable = iwmx_cm_disable,
554 .scan = iwmx_cm_scan,
557 static int iwmx_cm_init(void)
561 result = connman_device_driver_register(&iwmx_cm_device_driver);
563 goto error_driver_register;
564 result = connman_network_driver_register(&iwmx_cm_network_driver);
566 goto error_network_driver_register;
567 result = iwmx_sdk_api_init();
569 goto error_iwmx_sdk_init;
573 connman_network_driver_unregister(&iwmx_cm_network_driver);
574 error_network_driver_register:
575 connman_device_driver_unregister(&iwmx_cm_device_driver);
576 error_driver_register:
580 static void iwmx_cm_exit(void)
583 connman_network_driver_unregister(&iwmx_cm_network_driver);
584 connman_device_driver_unregister(&iwmx_cm_device_driver);
587 CONNMAN_PLUGIN_DEFINE(iwmx, "Intel WiMAX SDK / Common API plugin",
588 CONNMAN_VERSION, CONNMAN_PLUGIN_PRIORITY_LOW,
589 iwmx_cm_init, iwmx_cm_exit);