00001
00028 #include "wl_cm.h"
00029 #include "wl_util.h"
00030 #include <string.h>
00031
00032
00033
00034 #if 0
00035 # include "printf-stdarg.h"
00036 # define CM_DPRINTF(fmt...) printk(fmt)
00037 #else
00038 # define CM_DPRINTF(fmt...)
00039 #endif
00040
00041
00051 struct cm_candidate {
00052 struct wl_ssid_t ssid;
00053 struct wl_mac_addr_t bssid;
00054 };
00055
00056 struct cm {
00057 cm_scan_cb_t *scan_cb;
00058 cm_conn_cb_t *conn_cb;
00059 cm_disconn_cb_t *disconn_cb;
00060 void* ctx;
00061
00062 struct cm_candidate candidate;
00063 };
00064
00065
00069 static struct wl_network_t*
00070 find_best_candidate(struct cm* cm)
00071 {
00072 struct wl_network_t* wl_network;
00073 uint8_t cnt, i;
00074
00075 wl_get_network_list(&wl_network, &cnt);
00076 if (cnt == 0)
00077 return NULL;
00078
00079 for (i = 0; i < cnt; i++) {
00080
00081 if (cm->candidate.ssid.len)
00082 if (!equal_ssid(&cm->candidate.ssid,
00083 &wl_network[i].ssid))
00084 continue;
00085
00086
00087
00088
00089 if (strncmp((char*) cm->candidate.bssid.octet,
00090 "\xff\xff\xff\xff\xff\xff", 6))
00091 if (!equal_bssid(&cm->candidate.bssid,
00092 &wl_network[i].bssid))
00093 continue;
00094
00095
00096 return &wl_network[i];
00097 }
00098
00099 return NULL;
00100 }
00101
00102
00106 static void
00107 select_net(struct cm* cm)
00108 {
00109 struct wl_network_t *candidate_net;
00110 struct wl_network_t *current_net;
00111 int ret;
00112
00113 current_net = wl_get_current_network();
00114 candidate_net = find_best_candidate(cm);
00115
00116
00117 if (cm->candidate.ssid.len != 0 && current_net == NULL && candidate_net == NULL) {
00118 ;
00119
00120
00121 } else if (current_net == candidate_net) {
00122 return;
00123
00124
00125 } else if (current_net == NULL && candidate_net) {
00126 ret = wl_connect(candidate_net->ssid.ssid,
00127 candidate_net->ssid.len);
00128 switch (ret) {
00129 case WL_SUCCESS :
00130 return;
00131 case WL_BUSY:
00132 wl_disconnect();
00133 return;
00134 default :
00135 break;
00136 }
00137
00138 CM_DPRINTF("CM: failed to connect\n");
00139
00140
00141 } else if (current_net) {
00142 if (wl_disconnect() == WL_SUCCESS)
00143 return;
00144
00145 CM_DPRINTF("CM: failed to disconnect\n");
00146 }
00147
00148
00149 if (wl_scan() != WL_SUCCESS)
00150 CM_DPRINTF("CM: failed to scan\n");
00151 }
00152
00153
00157 static void
00158 wl_scan_complete_cb(void* ctx)
00159 {
00160 struct cm *cm = ctx;
00161
00162 CM_DPRINTF("CM: scan completed\n");
00163
00164 if (cm->scan_cb)
00165 cm->scan_cb(cm->ctx);
00166
00167 select_net(cm);
00168 }
00169
00170
00171
00172
00176 static void
00177 wl_media_connected_cb(void* ctx)
00178 {
00179 struct cm *cm = ctx;
00180 struct wl_network_t *net = wl_get_current_network();
00181 CM_DPRINTF("CM: connected to %32s\n", net->ssid.ssid);
00182 if (cm->conn_cb)
00183 cm->conn_cb(net, cm->ctx);
00184 }
00185
00186
00190 static void
00191 wl_conn_failure_cb(void* ctx)
00192 {
00193 CM_DPRINTF("CM: connect failed, scanning\n");
00194
00195 if (wl_scan() != WL_SUCCESS)
00196
00197 CM_DPRINTF("CM: could not start scan after connect fail!\n");
00198 }
00199
00200
00204 static void
00205 wl_conn_lost_cb(void* ctx)
00206 {
00207 struct cm *cm = ctx;
00208 CM_DPRINTF("CM: connection lost, scanning\n");
00209
00210 if (cm->disconn_cb)
00211 cm->disconn_cb(cm->ctx);
00212
00213 if (wl_scan() != WL_SUCCESS)
00214
00215 CM_DPRINTF("CM: could not start scan after connect lost!\n");
00216 }
00217
00218
00222 static void
00223 wl_event_cb(struct wl_event_t event, void* ctx)
00224 {
00225 struct cm *cm = ctx;
00226
00227 switch (event.id) {
00228 case WL_EVENT_MEDIA_CONNECTED:
00229 wl_media_connected_cb(cm);
00230 break;
00231
00232 case WL_EVENT_CONN_FAILURE:
00233 wl_conn_failure_cb(cm);
00234 break;
00235
00236
00237
00238
00239 case WL_EVENT_MEDIA_DISCONNECTED:
00240 CM_DPRINTF("CM: disconnected\n");
00241 wl_conn_lost_cb(cm);
00242 break;
00243
00244
00245 case WL_EVENT_CONN_LOST:
00246 wl_conn_lost_cb(cm);
00247 break;
00248
00249 case WL_EVENT_SCAN_COMPLETE:
00250 wl_scan_complete_cb(cm);
00251 break;
00252
00253 default:
00254 CM_DPRINTF("CM: unhandled event\n");
00255 };
00256 }
00257
00258
00259
00260 static struct cm *cm = NULL;
00261
00262
00266 wl_err_t
00267 wl_cm_start(cm_scan_cb_t scan_cb,
00268 cm_conn_cb_t conn_cb,
00269 cm_disconn_cb_t disconn_cb,
00270 void* ctx)
00271 {
00272 if (cm != NULL)
00273 return WL_FAILURE;
00274
00275 cm = calloc(1, sizeof(struct cm));
00276 if (cm == NULL) {
00277 CM_DPRINTF("CM: out of memory\n");
00278 return WL_FAILURE;
00279 }
00280
00281 if (wl_register_event_cb(wl_event_cb, cm) != WL_SUCCESS) {
00282 CM_DPRINTF("CM: could not register event cb\n");
00283 return WL_FAILURE;
00284 }
00285
00286 cm->scan_cb = scan_cb;
00287 cm->conn_cb = conn_cb;
00288 cm->disconn_cb = disconn_cb;
00289 cm->ctx = ctx;
00290 if (wl_scan() != WL_SUCCESS)
00291 CM_DPRINTF("CM: could not scan\n");
00292
00293 CM_DPRINTF("CM: initialized\n");
00294 return WL_SUCCESS;
00295 }
00296
00297
00311 wl_err_t
00312 wl_cm_set_network(struct wl_ssid_t *ssid, struct wl_mac_addr_t *bssid)
00313 {
00314 if (cm == NULL)
00315 return WL_FAILURE;
00316
00317 if (ssid)
00318 memcpy(&cm->candidate.ssid, ssid, sizeof(cm->candidate.ssid));
00319 else
00320 cm->candidate.ssid.len = 0;
00321
00322 if (bssid)
00323 memcpy(&cm->candidate.bssid, bssid,
00324 sizeof(cm->candidate.bssid));
00325 else
00326 memset(&cm->candidate.bssid, 0xff, sizeof(cm->candidate.bssid));
00327 (void) wl_scan();
00328 return WL_SUCCESS;
00329 }