Remove obsolete file.
[connman] / plugins / iwmxsdk.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2009  Intel Corporation. All rights reserved.
6  *
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.
10  *
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.
15  *
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
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdio.h>
27 #include <errno.h>
28 #include <string.h>
29 #include <net/if.h>
30
31 #include <glib.h>
32
33 #define CONNMAN_API_SUBJECT_TO_CHANGE
34 #include <connman/device.h>
35 #include <connman/inet.h>
36 #include <connman/log.h>
37
38 #include <WiMaxAPI.h>
39 #include <WiMaxAPIEx.h>
40
41 #include "iwmx.h"
42
43 /* Yes, this is dirty; see above on IWMX_SDK_DEV_MAX*/
44 static struct wmxsdk g_iwmx_sdk_devs[IWMX_SDK_DEV_MAX];
45
46 static struct wmxsdk *deviceid_to_wmxsdk(struct WIMAX_API_DEVICE_ID *device_id)
47 {
48         return container_of(device_id, struct wmxsdk, device_id);
49 }
50
51 static struct WIMAX_API_DEVICE_ID g_api;
52
53
54 /*
55  * FIXME: pulled it it out of some hole
56  *
57  * the cinr to percentage computation comes from the L3/L4 doc
58  *
59  * But some other places (L4 code) have a more complex, seemingly
60  * logarithmical computation.
61  *
62  * Oh well...
63  *
64  */
65 static int cinr_to_percentage(int cinr)
66 {
67         int strength;
68         if (cinr <= -5)
69                 strength = 0;
70         else if (cinr >= 25)
71                 strength = 100;
72         else    /* Calc percentage on the value from -5 to 25 */
73                 strength = ((100UL * (cinr - -5)) / (25 - -5));
74         return strength;
75 }
76
77 /*
78  * Convert a WiMAX API status to an string.
79  */
80 const char *iwmx_sdk_dev_status_to_str(WIMAX_API_DEVICE_STATUS status)
81 {
82         switch (status) {
83         case WIMAX_API_DEVICE_STATUS_UnInitialized:
84                 return "Uninitialized";
85                 break;
86         case WIMAX_API_DEVICE_STATUS_RF_OFF_HW_SW:
87                 return "Device RF Off(both H/W and S/W)";
88                 break;
89         case WIMAX_API_DEVICE_STATUS_RF_OFF_HW:
90                 return "Device RF Off(via H/W switch)";
91         case WIMAX_API_DEVICE_STATUS_RF_OFF_SW:
92                 return "Device RF Off(via S/W switch)";
93         case WIMAX_API_DEVICE_STATUS_Ready:
94                 return "Device is ready";
95         case WIMAX_API_DEVICE_STATUS_Scanning:
96                 return "Device is scanning";
97         case WIMAX_API_DEVICE_STATUS_Connecting:
98                 return "Connection in progress";
99         case WIMAX_API_DEVICE_STATUS_Data_Connected:
100                 return "Layer 2 connected";
101         case WIMAX_API_DEVICE_STATUS_Connection_Idle:
102                 return "Idle connection";
103         default:
104                 return "unknown state";
105         }
106 }
107
108 /*
109  * Get the device's status from the device
110  *
111  * Does NOT cache the result
112  * Does NOT trigger a state change in connman
113  *
114  * Returns < 0 errno code on error, status code if ok.
115  */
116 WIMAX_API_DEVICE_STATUS iwmx_sdk_get_device_status(struct wmxsdk *wmxsdk)
117 {
118         WIMAX_API_RET r;
119         char errstr[512];
120         UINT32 errstr_size = sizeof(errstr);
121
122         WIMAX_API_DEVICE_STATUS dev_status;
123         WIMAX_API_CONNECTION_PROGRESS_INFO pi;
124
125         r = GetDeviceStatus(&wmxsdk->device_id, &dev_status, &pi);
126         if (r != WIMAX_API_RET_SUCCESS) {
127                 GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size);
128                 connman_error("wmxsdk: Cannot read device state: %d (%s)\n",
129                         r, errstr);
130                 dev_status = -EIO;
131         }
132         return dev_status;
133 }
134
135 /*
136  * Get the device's status from the device but return a string describing it
137  *
138  * Same conditions as iwmx_sdk_get_device_status().
139  */
140 static const char *iwmx_sdk_get_device_status_str(struct wmxsdk *wmxsdk)
141 {
142         const char *result;
143         WIMAX_API_DEVICE_STATUS dev_status;
144
145         dev_status = iwmx_sdk_get_device_status(wmxsdk);
146         if ((int) dev_status < 0)
147                 result = "cannot read device state";
148         else
149                 result = iwmx_sdk_dev_status_to_str(dev_status);
150         return result;
151 }
152
153 /*
154  * Translate a WiMAX network type to a readable name.
155  */
156 static const char *iwmx_sdk_network_type_name(enum _WIMAX_API_NETWORK_TYPE network_type)
157 {
158         static char *network_type_name[] = {
159                 [WIMAX_API_HOME] = "",
160                 [WIMAX_API_PARTNER] = " (partner network)",
161                 [WIMAX_API_ROAMING_PARTNER] = " (roaming partner network)",
162                 [WIMAX_API_UNKNOWN] = " (unknown network)",
163         };
164         if (network_type > WIMAX_API_UNKNOWN)
165                 return "(BUG! UNKNOWN NETWORK_TYPE MODE)";
166         else
167                 return network_type_name[network_type];
168 }
169
170 /*
171  * If the device is connected but we don't know about the network,
172  * create the knowledge of it.
173  *
174  * Asks the WiMAX API to report which NSP we are connected to and we
175  * create/update a network_el in the device's network list. Then
176  * return it.
177  *
178  * Returns NULL on error.
179  *
180  * NOTE: wmxsdk->network_mutex has to be taken
181  */
182 struct connman_network *__iwmx_sdk_get_connected_network(struct wmxsdk *wmxsdk)
183 {
184         struct connman_network *nw;
185
186         struct WIMAX_API_CONNECTED_NSP_INFO nsp_info;
187         WIMAX_API_RET r;
188         char errstr[512];
189         UINT32 errstr_size = sizeof(errstr);
190
191         /* The device is getting connected due to an external (to
192          * connman) event; find which is the nw we are getting
193          * connected to. if we don't have it, add it */
194         r = GetConnectedNSP(&wmxsdk->device_id, &nsp_info);
195         if (r != WIMAX_API_RET_SUCCESS) {
196                 GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size);
197                 connman_error(
198                         "wmxsdk: Cannot get connected NSP info: %d (%s)\n",
199                         r, errstr);
200                 strcpy((char *) nsp_info.NSPName, "unknown");
201                 nw = iwmx_cm_network_available(
202                         wmxsdk, "unknown",
203                         iwmx_sdk_network_type_name(WIMAX_API_UNKNOWN),
204                         nsp_info.NSPName, strlen((char *) nsp_info.NSPName) + 1,
205                         cinr_to_percentage(nsp_info.CINR - 10));
206         } else {
207                 nw = iwmx_cm_network_available(
208                         wmxsdk, (char *) nsp_info.NSPName,
209                         iwmx_sdk_network_type_name(nsp_info.networkType),
210                         nsp_info.NSPName, strlen((char *) nsp_info.NSPName) + 1,
211                         cinr_to_percentage(nsp_info.CINR - 10));
212         }
213         return nw;
214 }
215
216 /*
217  * Callback for a RF State command
218  *
219  * Called by the WiMAX API when a command sent to change the RF state
220  * is completed. This is just a confirmation of what happened with the
221  * command.
222  *
223  * We don't do anything, as when the device changes state, the state
224  * change callback is called and that will fiddle with the connman
225  * internals.
226  */
227 static void __iwmx_sdk_rf_state_cb(struct WIMAX_API_DEVICE_ID *device_id,
228                                                 WIMAX_API_RF_STATE rf_state)
229 {
230         DBG("rf_state changed to %d\n", rf_state);
231 }
232
233 /*
234  * Turn the radio on or off
235  *
236  * First it checks that we are in the right state before doing
237  * anything; there might be no need to do anything.
238  *
239  * Issue a command to the WiMAX API, wait for a callback confirming it
240  * is done. Sometimes the callback is missed -- in that case, do force
241  * a state change evaluation.
242  *
243  * Frustration note:
244  *
245  *      Geezoos efing Xist, they make difficult even the most simple
246  *      of the operations
247  *
248  *      This thing is definitely a pain. If the radio is ON already
249  *      and you switch it on again...well, there is no way to tell
250  *      because you don't get a callback saying it basically
251  *      suceeded. But on the other hand, if the thing was in a
252  *      different state and action needs to be taken, you have to wait
253  *      for a callback to confirm it's done. However, there is also an
254  *      state change callback, which is almost the same, so now you
255  *      have to handle things in two "unrelated" threads of execution.
256  *
257  *      How the shpx are you expected to tell the difference? Check
258  *      status first? On timeout? Nice gap (eighteen wheeler size) for
259  *      race conditions.
260  */
261 int iwmx_sdk_rf_state_set(struct wmxsdk *wmxsdk, WIMAX_API_RF_STATE rf_state)
262 {
263         int result;
264
265         WIMAX_API_RET r;
266         char errstr[512];
267         UINT32 errstr_size = sizeof(errstr);
268         WIMAX_API_DEVICE_STATUS dev_status;
269
270         g_assert(rf_state == WIMAX_API_RF_ON || rf_state == WIMAX_API_RF_OFF);
271
272         /* Guess what the current radio state is; if it is ON
273          * already, don't redo it. */
274         dev_status = iwmx_sdk_get_device_status(wmxsdk);
275         if ((int) dev_status < 0) {
276                 result = dev_status;
277                 goto error_get_status;
278         }
279         switch (dev_status) {
280         case WIMAX_API_DEVICE_STATUS_UnInitialized:
281                 result = -EINVAL;
282                 goto error_cant_do;
283         case WIMAX_API_DEVICE_STATUS_RF_OFF_HW_SW:
284         case WIMAX_API_DEVICE_STATUS_RF_OFF_HW:
285                 connman_error(
286                         "wmxsdk: cannot turn on radio: hw switch is off\n");
287                 result = -EPERM;
288                 goto error_cant_do;
289                 break;
290         case WIMAX_API_DEVICE_STATUS_RF_OFF_SW:
291                 if (rf_state == WIMAX_API_RF_OFF) {
292                         result = 0;
293                         DBG("radio is already off\n");
294                         goto out_done;
295                 }
296                 break;
297         case WIMAX_API_DEVICE_STATUS_Ready:
298         case WIMAX_API_DEVICE_STATUS_Scanning:
299         case WIMAX_API_DEVICE_STATUS_Connecting:
300         case WIMAX_API_DEVICE_STATUS_Data_Connected:
301         case WIMAX_API_DEVICE_STATUS_Connection_Idle:
302                 if (rf_state == WIMAX_API_RF_ON) {
303                         result = 0;
304                         DBG("radio is already on\n");
305                         goto out_done;
306                 }
307                 break;
308         default:
309                 g_assert(1);
310         }
311         /* Ok, flip the radio */
312         r = CmdControlPowerManagement(&wmxsdk->device_id, rf_state);
313         if (r != WIMAX_API_RET_SUCCESS) {
314                 GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size);
315                 connman_error("wmxsdk: Cannot flip radio to %d: %d (%s) "
316                               "[device is in state %s]\n",
317                               rf_state, r, errstr,
318                               iwmx_sdk_get_device_status_str(wmxsdk));
319                 result = -EIO;
320         } else
321                 result = -EINPROGRESS;
322 out_done:
323 error_cant_do:
324 error_get_status:
325         return result;
326 }
327
328 /*
329  * Callback for a Connect command
330  *
331  * Called by the WiMAX API when a command sent to connect is
332  * completed. This is just a confirmation of what happened with the
333  * command.
334  *
335  * WE DON'T DO MUCH HERE -- the real meat happens when a state change
336  * callback is sent, where we detect we move to connected state (or
337  * from disconnecting to something else); the state change callback is
338  * called and that will fiddle with the connman internals.
339  */
340 static void __iwmx_sdk_connect_cb(struct WIMAX_API_DEVICE_ID *device_id,
341                                         WIMAX_API_NETWORK_CONNECTION_RESP resp)
342 {
343         WIMAX_API_DEVICE_STATUS status;
344         struct wmxsdk *wmxsdk = deviceid_to_wmxsdk(device_id);
345
346         status = iwmx_cm_status_get(wmxsdk);
347         if (resp == WIMAX_API_CONNECTION_SUCCESS) {
348                 if (status != WIMAX_API_DEVICE_STATUS_Data_Connected
349                     && status != WIMAX_API_DEVICE_STATUS_Connection_Idle)
350                         connman_error("wmxsdk: error: connect worked, but state"
351                                       " didn't change (now it is %d [%s])\n",
352                                       status,
353                                       iwmx_sdk_dev_status_to_str(status));
354         } else
355                 connman_error("wmxsdk: failed to connect (status %d: %s)\n",
356                               status, iwmx_sdk_dev_status_to_str(status));
357 }
358
359 /*
360  * Connect to a network
361  *
362  * This function starts the connection process to a given network;
363  * when the device changes status, the status change callback will
364  * tell connman if the network is finally connected or not.
365  *
366  * One of the reasons it is done like that is to allow external tools
367  * to control the device and the plugin just passing the status so
368  * connman displays the right info.
369  */
370 int iwmx_sdk_connect(struct wmxsdk *wmxsdk, struct connman_network *nw)
371 {
372         int result;
373
374         WIMAX_API_RET r;
375         char errstr[512];
376         UINT32 errstr_size = sizeof(errstr);
377         WIMAX_API_DEVICE_STATUS dev_status;
378         const char *station_name = connman_network_get_identifier(nw);
379         const void *sdk_nspname;
380         unsigned int sdk_nspname_size;
381
382         g_mutex_lock(wmxsdk->connect_mutex);
383         /* Guess what the current radio state is; if it is ON
384          * already, don't redo it. */
385         dev_status = iwmx_cm_status_get(wmxsdk);
386         if ((int) dev_status < 0) {
387                 result = dev_status;
388                 goto error_get_status;
389         }
390         switch (dev_status) {
391         case WIMAX_API_DEVICE_STATUS_UnInitialized:
392                 connman_error("wmxsdk: SW BUG? HW is uninitialized\n");
393                 result = -EINVAL;
394                 goto error_cant_do;
395         case WIMAX_API_DEVICE_STATUS_RF_OFF_HW_SW:
396         case WIMAX_API_DEVICE_STATUS_RF_OFF_HW:
397         case WIMAX_API_DEVICE_STATUS_RF_OFF_SW:
398                 connman_error("wmxsdk: Cannot connect: radio is off\n");
399                 result = -EPERM;
400                 goto error_cant_do;
401         case WIMAX_API_DEVICE_STATUS_Ready:
402         case WIMAX_API_DEVICE_STATUS_Scanning:
403                 break;
404         case WIMAX_API_DEVICE_STATUS_Connecting:
405                 DBG("Connect already pending, waiting for it\n");
406                 result = -EINPROGRESS;
407                 goto error_cant_do;
408         case WIMAX_API_DEVICE_STATUS_Data_Connected:
409         case WIMAX_API_DEVICE_STATUS_Connection_Idle:
410                 connman_error("wmxsdk: BUG? need to disconnect?\n");
411                 result = -EINVAL;
412                 goto error_cant_do;
413         default:
414                 g_assert(1);
415         }
416
417         /* Ok, do the connection, wait for a callback */
418         wmxsdk->connecting_nw = connman_network_ref(nw);
419         sdk_nspname = connman_network_get_blob(nw, "WiMAX.NSP.name",
420                                                         &sdk_nspname_size);
421         g_assert(sdk_nspname != NULL);
422         r = CmdConnectToNetwork(&wmxsdk->device_id, (void *) sdk_nspname, 0, 0);
423         if (r != WIMAX_API_RET_SUCCESS) {
424                 GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size);
425                 connman_error("wmxsdk: Cannot connect to network %s: %d (%s)"
426                               " - device is in state '%s'\n",
427                               station_name, r, errstr,
428                               iwmx_sdk_get_device_status_str(wmxsdk));
429                 result = -EIO;
430                 connman_network_unref(nw);
431                 wmxsdk->connecting_nw = NULL;
432         } else
433                 result = -EINPROGRESS;
434 error_cant_do:
435 error_get_status:
436         g_mutex_unlock(wmxsdk->connect_mutex);
437         return result;
438 }
439
440 /*
441  * Callback for a Disconnect command
442  *
443  * Called by the WiMAX API when a command sent to connect is
444  * completed. This is just a confirmation of what happened with the
445  * command.
446  *
447  * When the device changes state, the state change callback is called
448  * and that will fiddle with the connman internals.
449  *
450  * We just update the result of the command and wake up anybody who is
451  * waiting for this conditional variable.
452  */
453 static void __iwmx_sdk_disconnect_cb(struct WIMAX_API_DEVICE_ID *device_id,
454                                         WIMAX_API_NETWORK_CONNECTION_RESP resp)
455 {
456         struct wmxsdk *wmxsdk = deviceid_to_wmxsdk(device_id);
457         WIMAX_API_DEVICE_STATUS status;
458
459         status = iwmx_cm_status_get(wmxsdk);
460         if (resp == WIMAX_API_CONNECTION_SUCCESS) {
461                 if (status == WIMAX_API_DEVICE_STATUS_Data_Connected
462                     || status == WIMAX_API_DEVICE_STATUS_Connection_Idle)
463                         connman_error("wmxsdk: error: disconnect worked, "
464                                       "but state didn't change (now it is "
465                                       "%d [%s])\n", status,
466                                       iwmx_sdk_dev_status_to_str(status));
467         } else
468                 connman_error("wmxsdk: failed to disconnect (status %d: %s)\n",
469                               status, iwmx_sdk_dev_status_to_str(status));
470 }
471
472 /*
473  * Disconnect from a network
474  *
475  * This function tells the device to disconnect; the state change
476  * callback will take care of inform connman's internals.
477  */
478 int iwmx_sdk_disconnect(struct wmxsdk *wmxsdk)
479 {
480         int result;
481
482         WIMAX_API_RET r;
483         char errstr[512];
484         UINT32 errstr_size = sizeof(errstr);
485         WIMAX_API_DEVICE_STATUS dev_status;
486
487         g_mutex_lock(wmxsdk->connect_mutex);
488         /* Guess what the current radio state is; if it is ON
489          * already, don't redo it. */
490         dev_status = iwmx_sdk_get_device_status(wmxsdk);
491         if ((int) dev_status < 0) {
492                 result = dev_status;
493                 goto error_get_status;
494         }
495         switch (dev_status) {
496         case WIMAX_API_DEVICE_STATUS_UnInitialized:
497                 connman_error("wmxsdk: SW BUG? HW is uninitialized\n");
498                 result = -EINVAL;
499                 goto error_cant_do;
500         case WIMAX_API_DEVICE_STATUS_RF_OFF_HW_SW:
501         case WIMAX_API_DEVICE_STATUS_RF_OFF_HW:
502         case WIMAX_API_DEVICE_STATUS_RF_OFF_SW:
503                 DBG("Cannot disconnect, radio is off; ignoring\n");
504                 result = 0;
505                 goto error_cant_do;
506         case WIMAX_API_DEVICE_STATUS_Ready:
507         case WIMAX_API_DEVICE_STATUS_Scanning:
508                 DBG("Cannot disconnect, already disconnected; ignoring\n");
509                 result = 0;
510                 goto error_cant_do;
511         case WIMAX_API_DEVICE_STATUS_Connecting:
512         case WIMAX_API_DEVICE_STATUS_Data_Connected:
513         case WIMAX_API_DEVICE_STATUS_Connection_Idle:
514                 break;
515         default:
516                 g_assert(1);
517         }
518         /* Ok, flip the radio */
519         r = CmdDisconnectFromNetwork(&wmxsdk->device_id);
520         if (r != WIMAX_API_RET_SUCCESS) {
521                 GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size);
522                 connman_error("wmxsdk: Cannot disconnect from network: "
523                               "%d (%s)\n", r, errstr);
524                 result = -EIO;
525         } else
526                 result = -EINPROGRESS;
527 error_cant_do:
528 error_get_status:
529         g_mutex_unlock(wmxsdk->connect_mutex);
530         return result;
531 }
532
533 /*
534  * Callback for state change messages
535  *
536  * Just pass them to the state transition handler
537  */
538 static void __iwmx_sdk_state_change_cb(struct WIMAX_API_DEVICE_ID *device_id,
539                                         WIMAX_API_DEVICE_STATUS status,
540                                         WIMAX_API_STATUS_REASON reason,
541                                         WIMAX_API_CONNECTION_PROGRESS_INFO pi)
542 {
543         struct wmxsdk *wmxsdk = deviceid_to_wmxsdk(device_id);
544         iwmx_cm_state_change(wmxsdk, status);
545 }
546
547 /*
548  * Called by _iwmx_sdk_*scan_cb() when [wide or preferred] scan results
549  * are available.
550  *
551  * From here we update the connman core idea of which networks are
552  * available.
553  */
554 static void __iwmx_sdk_scan_common_cb(struct WIMAX_API_DEVICE_ID *device_id,
555                                         struct WIMAX_API_NSP_INFO_EX *nsp_list,
556                                                         UINT32 nsp_list_size)
557 {
558         struct wmxsdk *wmxsdk = deviceid_to_wmxsdk(device_id);
559         unsigned itr;
560         char station_name[256];
561
562         g_static_mutex_lock(&wmxsdk->network_mutex);
563         for (itr = 0; itr < nsp_list_size; itr++) {
564                 int strength;
565                 struct WIMAX_API_NSP_INFO_EX *nsp_info = &nsp_list[itr];
566                 snprintf(station_name, sizeof(station_name),
567                          "%s", (char *)nsp_info->NSPName);
568                 /* CAPI is reporing link quality as zero -- if it is
569                  * zero, check if it is a bug by computing it based on
570                  * CINR. If it is different, use the computed one. */
571                 strength = nsp_info->linkQuality;
572                 if (strength == 0) {    /* huh */
573                         int linkq_expected =
574                                 cinr_to_percentage(nsp_info->CINR - 10);
575                         if (linkq_expected != strength)
576                                 strength = linkq_expected;
577                 }
578
579                 __iwmx_cm_network_available(
580                         wmxsdk, station_name,
581                         iwmx_sdk_network_type_name(nsp_info->networkType),
582                         nsp_info->NSPName,
583                         strlen((char *) nsp_info->NSPName) + 1,
584                         strength);
585         }
586         g_static_mutex_unlock(&wmxsdk->network_mutex);
587 }
588
589 /*
590  * Called by the WiMAX API when we get a wide scan result
591  *
592  * We treat them same as wide, so we just call that.
593  */
594 static void __iwmx_sdk_wide_scan_cb(struct WIMAX_API_DEVICE_ID *device_id,
595                                 struct WIMAX_API_NSP_INFO_EX *nsp_list,
596                                                         UINT32 nsp_list_size)
597 {
598         __iwmx_sdk_scan_common_cb(device_id, nsp_list, nsp_list_size);
599 }
600
601 /*
602  * Called by the WiMAX API when we get a normal (non wide) scan result
603  *
604  * We treat them same as wide, so we just call that.
605  */
606 static void __iwmx_sdk_scan_cb(struct WIMAX_API_DEVICE_ID *device_id,
607                                 struct WIMAX_API_NSP_INFO_EX *nsp_list,
608                                 UINT32 nsp_list_size, UINT32 searchProgress)
609 {
610         __iwmx_sdk_scan_common_cb(device_id, nsp_list, nsp_list_size);
611 }
612
613 /*
614  * Called to ask the device to scan for networks
615  *
616  * We don't really scan as the WiMAX SDK daemon scans in the
617  * background for us. We just get the results. See iwmx_sdk_setup().
618  */
619 int iwmx_sdk_scan(struct wmxsdk *wmxsdk)
620 {
621         int result;
622
623         UINT32 nsp_list_length = 10;
624         struct WIMAX_API_NSP_INFO_EX nsp_list[10];      /* FIXME: up to 32? */
625
626         WIMAX_API_RET r;
627         char errstr[512];
628         UINT32 errstr_size = sizeof(errstr);
629
630         r = GetNetworkListEx(&wmxsdk->device_id, nsp_list, &nsp_list_length);
631         if (r != WIMAX_API_RET_SUCCESS) {
632                 GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size);
633                 connman_error("wmxsdk: Cannot get network list: %d (%s)\n",
634                               r, errstr);
635                 result = -EIO;
636                 goto error_scan;
637         }
638
639         if (nsp_list_length == 0)
640                 DBG("no networks\n");
641         else
642                 __iwmx_sdk_scan_common_cb(&wmxsdk->device_id, nsp_list,
643                                         nsp_list_length);
644         result = 0;
645 error_scan:
646         return result;
647 }
648
649 /*
650  * Initialize the WiMAX API, register with it, setup callbacks
651  *
652  * Called through
653  *
654  * iwmx_sdk_dev_add
655  *   connman_inet_create_device
656  *      connman_register
657  *         iwmx_cm_probe()
658  */
659 int iwmx_sdk_setup(struct wmxsdk *wmxsdk)
660 {
661         int result;
662
663         WIMAX_API_RET r;
664
665         char errstr[512];
666         UINT32 errstr_size = sizeof(errstr);
667
668         result = -ENFILE;
669
670         /* device_id initialized by iwmx_sdk_dev_add */
671
672         r = WiMaxDeviceOpen(&wmxsdk->device_id);
673         if (r != WIMAX_API_RET_SUCCESS) {
674                 GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size);
675                 connman_error("wmxsdk: Cannot open device: %d (%s)\n",
676                               r, errstr);
677                 goto error_wimaxdeviceopen;
678         }
679
680         /*
681          * We scan in auto mode (in the background)
682          *
683          * Otherwise is messy -- if we have connman triggering a scan
684          * when we call iwmx_cm_scan() -> iwmx_sdk_scan(), most of the
685          * times that causes a race condition when the UI asks for a
686          * scan right before displaying the network menu. As there is
687          * no way to cancel an ongoing scan before connecting, we are
688          * stuck. So we do auto bg and have iwmx_sdk_scan() just return
689          * the current network list.
690          */
691         r = SetConnectionMode(&wmxsdk->device_id,
692                               WIMAX_API_CONNECTION_AUTO_SCAN_MANUAL_CONNECT);
693         if (r != WIMAX_API_RET_SUCCESS) {
694                 GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size);
695                 connman_error("wmxsdk: Cannot set connectin mode to manual: "
696                               "%d (%s)\n", r, errstr);
697                 goto error_connection_mode;
698         }
699
700         r = SubscribeControlPowerManagement(&wmxsdk->device_id,
701                                             __iwmx_sdk_rf_state_cb);
702         if (r != WIMAX_API_RET_SUCCESS) {
703                 GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size);
704                 connman_error("wmxsdk: Cannot subscribe to radio change "
705                               "events: %u (%s)\n", r, errstr);
706                 result = -EIO;
707                 goto error_subscribe_rf_state;
708         }
709
710         r = SubscribeDeviceStatusChange(&wmxsdk->device_id,
711                                         __iwmx_sdk_state_change_cb);
712         if (r != WIMAX_API_RET_SUCCESS) {
713                 GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size);
714                 connman_error("wmxsdk: Cannot subscribe to state chaneg events:"
715                               "%d (%s)\n", r, errstr);
716                 goto error_subscribe_state_change;
717         }
718
719         r = SubscribeNetworkSearchWideScanEx(&wmxsdk->device_id,
720                                              __iwmx_sdk_wide_scan_cb);
721         if (r != WIMAX_API_RET_SUCCESS) {
722                 GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size);
723                 connman_error("wmxsdk: Cannot subscribe to wide scan events: "
724                               "%d (%s)\n", r, errstr);
725                 goto error_subscribe_wide_scan;
726         }
727         r = SubscribeNetworkSearchEx(&wmxsdk->device_id, __iwmx_sdk_scan_cb);
728         if (r != WIMAX_API_RET_SUCCESS) {
729                 GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size);
730                 connman_error("wmxsdk: Cannot subscribe to scan events: "
731                               "%d (%s)\n", r, errstr);
732                 goto error_subscribe_scan;
733         }
734
735         r = SubscribeConnectToNetwork(&wmxsdk->device_id,
736                                       __iwmx_sdk_connect_cb);
737         if (r != WIMAX_API_RET_SUCCESS) {
738                 GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size);
739                 connman_error("wmxsdk: Cannot subscribe to connect events: "
740                               "%d (%s)\n", r, errstr);
741                 goto error_subscribe_connect;
742         }
743
744         r = SubscribeDisconnectToNetwork(&wmxsdk->device_id,
745                                          __iwmx_sdk_disconnect_cb);
746         if (r != WIMAX_API_RET_SUCCESS) {
747                 GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size);
748                 connman_error("wmxsdk: Cannot subscribe to disconnect events: "
749                               "%d (%s)\n", r, errstr);
750                 goto error_subscribe_disconnect;
751         }
752         result = 0;
753 out:
754         return result;
755
756         UnsubscribeDisconnectToNetwork(&wmxsdk->device_id);
757 error_subscribe_disconnect:
758         UnsubscribeConnectToNetwork(&wmxsdk->device_id);
759 error_subscribe_connect:
760         UnsubscribeNetworkSearchEx(&wmxsdk->device_id);
761 error_subscribe_scan:
762         UnsubscribeNetworkSearchWideScanEx(&wmxsdk->device_id);
763 error_subscribe_wide_scan:
764         UnsubscribeDeviceStatusChange(&wmxsdk->device_id);
765 error_subscribe_state_change:
766         UnsubscribeControlPowerManagement(&wmxsdk->device_id);
767 error_subscribe_rf_state:
768 error_connection_mode:
769         WiMaxDeviceClose(&wmxsdk->device_id);
770 error_wimaxdeviceopen:
771         goto out;
772 }
773
774 /*
775  * Called when a device is removed from connman
776  *
777  * Cleanup all that is done in iwmx_sdk_setup(). Remove callbacks,
778  * unregister from the WiMAX API.
779  */
780 void iwmx_sdk_remove(struct wmxsdk *wmxsdk)
781 {
782         UnsubscribeDisconnectToNetwork(&wmxsdk->device_id);
783         UnsubscribeConnectToNetwork(&wmxsdk->device_id);
784         UnsubscribeNetworkSearchEx(&wmxsdk->device_id);
785         UnsubscribeNetworkSearchWideScanEx(&wmxsdk->device_id);
786         UnsubscribeDeviceStatusChange(&wmxsdk->device_id);
787         UnsubscribeControlPowerManagement(&wmxsdk->device_id);
788         WiMaxDeviceClose(&wmxsdk->device_id);
789 }
790
791 static void iwmx_sdk_dev_add(unsigned idx, unsigned api_idx, const char *name)
792 {
793         int result, ifindex;
794         struct wmxsdk *wmxsdk;
795         const char *s;
796
797         if (idx >= IWMX_SDK_DEV_MAX) {
798                 connman_error("BUG! idx (%u) >= IWMX_SDK_DEV_MAX (%u)\n",
799                               idx, IWMX_SDK_DEV_MAX);
800                 goto error_bug;
801         }
802         wmxsdk = &g_iwmx_sdk_devs[idx];
803         if (wmxsdk->dev != NULL) {
804                 connman_error("BUG! device index %u already enumerated?\n",
805                               idx);
806                 goto error_bug;
807         }
808
809         memset(wmxsdk, 0, sizeof(*wmxsdk));
810         wmxsdk_init(wmxsdk);
811         /*
812          * This depends on a hack in the WiMAX Network Service; it has
813          * to return, as part of the device name, a string "if:IFNAME"
814          * where the OS's device name is stored.
815          */
816         s = strstr(name, "if:");
817         if (s == NULL
818             || sscanf(s, "if:%15[^ \f\n\r\t\v]", wmxsdk->ifname) != 1) {
819                 connman_error("Cannot extract network interface name off '%s'",
820                               name);
821                 goto error_noifname;
822         }
823         DBG("network interface name: '%s'", wmxsdk->ifname);
824
825         ifindex = if_nametoindex(wmxsdk->ifname);
826         if (ifindex <= 0) {
827                 result = -ENFILE;
828                 connman_error("wxmsdk: %s: cannot find interface index\n",
829                               wmxsdk->ifname);
830                 goto error_noifname;
831         }
832
833         wmxsdk->dev = connman_inet_create_device(ifindex);
834         if (wmxsdk->dev == NULL) {
835                 connman_error("wmxsdk: %s: failed to create connman_device\n",
836                               name);
837                 goto error_create;
838         }
839         strncpy(wmxsdk->name, name, sizeof(wmxsdk->name));
840         connman_device_set_data(wmxsdk->dev, wmxsdk);
841
842         wmxsdk->device_id.privilege = WIMAX_API_PRIVILEGE_READ_WRITE;
843         wmxsdk->device_id.deviceIndex = api_idx;
844
845         result = connman_device_register(wmxsdk->dev);
846         if (result < 0) {
847                 connman_error("wmxsdk: %s: failed to register: %d\n",
848                               wmxsdk->ifname, result);
849                 goto error_dev_add;
850         }
851         return;
852
853 error_dev_add:
854         wmxsdk->name[0] = 0;
855         connman_device_unref(wmxsdk->dev);
856         wmxsdk->dev = NULL;
857 error_noifname:
858 error_create:
859 error_bug:
860         return;
861 }
862
863 static void iwmx_sdk_dev_rm(unsigned idx)
864 {
865         struct wmxsdk *wmxsdk;
866
867         if (idx >= IWMX_SDK_DEV_MAX) {
868                 connman_error("BUG! idx (%u) >= IWMX_SDK_DEV_MAX (%u)\n",
869                               idx, IWMX_SDK_DEV_MAX);
870                 goto error_bug;
871         }
872         wmxsdk = &g_iwmx_sdk_devs[idx];
873         if (wmxsdk->dev == NULL) {
874                 DBG("device index %u not enumerated? ignoring\n", idx);
875                 goto error_bug;
876         }
877
878         connman_device_unregister(wmxsdk->dev);
879         wmxsdk->name[0] = 0;
880         connman_device_unref(wmxsdk->dev);
881         memset(wmxsdk, 0, sizeof(*wmxsdk));
882 error_bug:
883         return;
884 }
885
886 static void iwmx_sdk_addremove_cb(struct WIMAX_API_DEVICE_ID *devid,
887                                                                 BOOL presence)
888 {
889         unsigned int cnt;
890         WIMAX_API_RET r;
891         struct WIMAX_API_HW_DEVICE_ID device_id_list[5];
892         UINT32 device_id_list_size = ARRAY_SIZE(device_id_list);
893
894         char errstr[512];
895         UINT32 errstr_size = sizeof(errstr);
896
897         DBG("cb: handle %u index #%u is %d\n", devid->sdkHandle,
898             devid->deviceIndex, presence);
899
900         r = GetListDevice(devid, device_id_list, &device_id_list_size);
901         if (r != WIMAX_API_RET_SUCCESS) {
902                 GetErrorString(devid, r, errstr, &errstr_size);
903                 connman_error("wmxsdk: Cannot obtain list "
904                               "of devices: %d (%s)\n", r, errstr);
905                 return;
906         }
907
908         if (device_id_list_size == 0)
909                 DBG("No WiMAX devices reported\n");
910         else
911                 for (cnt = 0; cnt < device_id_list_size; cnt++) {
912                         struct WIMAX_API_HW_DEVICE_ID *dev =
913                                 device_id_list + cnt;
914                         DBG("#%u index #%u device %s\n",
915                             cnt, dev->deviceIndex, dev->deviceName);
916                 }
917         if (device_id_list_size < devid->deviceIndex) {
918                 connman_error("wmxsdk: changed device (%u) not in the list? "
919                               "(%u items)\n",
920                               devid->deviceIndex, device_id_list_size);
921                 return;
922         }
923
924         if (presence) {
925                 struct WIMAX_API_HW_DEVICE_ID *dev =
926                         device_id_list + devid->deviceIndex;
927                 iwmx_sdk_dev_add(devid->deviceIndex, dev->deviceIndex,
928                                dev->deviceName);
929         } else {
930                 iwmx_sdk_dev_rm(devid->deviceIndex);
931         }
932 }
933
934 /*
935  * Initialize the WiMAX API, register with it, setup callbacks for
936  * device coming up / dissapearing
937  */
938 int iwmx_sdk_api_init(void)
939 {
940         int result;
941         unsigned int cnt;
942         WIMAX_API_RET r;
943         char errstr[512];
944         UINT32 errstr_size = sizeof(errstr);
945
946         struct WIMAX_API_HW_DEVICE_ID device_id_list[5];
947         UINT32 device_id_list_size = ARRAY_SIZE(device_id_list);
948
949         memset(&g_api, 0, sizeof(g_api));
950         g_api.privilege = WIMAX_API_PRIVILEGE_READ_WRITE;
951
952         result = -EIO;
953         r = WiMaxAPIOpen(&g_api);
954         if (r != WIMAX_API_RET_SUCCESS) {
955                 GetErrorString(&g_api, r, errstr, &errstr_size);
956                 connman_error("wmxsdk: WiMaxAPIOpen failed with %d (%s)\n",
957                               r, errstr);
958                 goto error_wimaxapiopen;
959         }
960
961         r = SubscribeDeviceInsertRemove(&g_api, iwmx_sdk_addremove_cb);
962         if (r != WIMAX_API_RET_SUCCESS) {
963                 GetErrorString(&g_api, r, errstr, &errstr_size);
964                 connman_error("wmxsdk: insert/remove subscribe failed with "
965                               "%d (%s)\n", r, errstr);
966                 goto error_close;
967         }
968
969         r = GetListDevice(&g_api, device_id_list, &device_id_list_size);
970         if (r != WIMAX_API_RET_SUCCESS) {
971                 GetErrorString(&g_api, r, errstr, &errstr_size);
972                 connman_error("wmxsdk: Cannot obtain list "
973                               "of devices: %d (%s)\n", r, errstr);
974                 goto error_close;
975         }
976         if (device_id_list_size < g_api.deviceIndex) {
977                 connman_error("wmxsdk: changed device (%u) not in the list? "
978                               "(%u items)\n",
979                               g_api.deviceIndex, device_id_list_size);
980         }
981
982         if (device_id_list_size == 0)
983                 DBG("No WiMAX devices reported\n");
984         else
985                 for (cnt = 0; cnt < device_id_list_size; cnt++) {
986                         struct WIMAX_API_HW_DEVICE_ID *dev =
987                                 device_id_list + cnt;
988                         DBG("#%u index #%u device %s\n",
989                             cnt, dev->deviceIndex, dev->deviceName);
990                         iwmx_sdk_dev_add(cnt, dev->deviceIndex,
991                                          dev->deviceName);
992                 }
993         return 0;
994
995 error_close:
996         WiMaxAPIClose(&g_api);
997 error_wimaxapiopen:
998         return result;
999 }
1000
1001 void iwmx_sdk_api_exit(void)
1002 {
1003         WIMAX_API_RET r;
1004
1005         char errstr[512];
1006         UINT32 errstr_size = sizeof(errstr);
1007
1008         r = WiMaxAPIClose(&g_api);
1009         if (r != WIMAX_API_RET_SUCCESS) {
1010                 GetErrorString(&g_api, r, errstr, &errstr_size);
1011                 connman_error("wmxsdk: WiMaxAPIClose failed with %d (%s)\n",
1012                               r, errstr);
1013         }
1014         return;
1015 }