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 if (strncmp((char*) cm->candidate.bssid.octet,
00088 "\xff\xff\xff\xff\xff\xff", 6))
00089 if (!equal_bssid(&cm->candidate.bssid,
00090 &wl_network[i].bssid))
00091 continue;
00092
00093
00094 return &wl_network[i];
00095 }
00096
00097 return NULL;
00098 }
00099
00100
00104 static void
00105 select_net(struct cm* cm)
00106 {
00107 struct wl_network_t *candidate_net;
00108 struct wl_network_t *current_net;
00109 int ret;
00110
00111 current_net = wl_get_current_network();
00112 candidate_net = find_best_candidate(cm);
00113
00114
00115 if (cm->candidate.ssid.len != 0 && current_net == NULL && candidate_net == NULL) {
00116 ;
00117
00118
00119 } else if (current_net == candidate_net) {
00120 return;
00121
00122
00123 } else if (current_net == NULL && candidate_net) {
00124 ret = wl_connect(candidate_net->ssid.ssid,
00125 candidate_net->ssid.len);
00126 switch (ret) {
00127 case WL_SUCCESS :
00128 return;
00129 case WL_BUSY:
00130 wl_disconnect();
00131 return;
00132 default :
00133 break;
00134 }
00135
00136 CM_DPRINTF("CM: failed to connect\n");
00137
00138
00139 } else if (current_net) {
00140 if (wl_disconnect() == WL_SUCCESS)
00141 return;
00142
00143 CM_DPRINTF("CM: failed to disconnect\n");
00144 }
00145
00146
00147 if (wl_scan() != WL_SUCCESS)
00148 CM_DPRINTF("CM: failed to scan\n");
00149 }
00150
00151
00155 static void
00156 wl_scan_complete_cb(void* ctx)
00157 {
00158 struct cm *cm = ctx;
00159
00160 CM_DPRINTF("CM: scan completed\n");
00161
00162 if (cm->scan_cb)
00163 cm->scan_cb(cm->ctx);
00164
00165 select_net(cm);
00166 }
00167
00171 static void
00172 wl_media_connected_cb(void* ctx)
00173 {
00174 struct cm *cm = ctx;
00175 struct wl_network_t *net = wl_get_current_network();
00176 char ssid[WL_SSID_MAX_LENGTH + 1];
00177
00178 memset(ssid, 0, sizeof(ssid));
00179 strncpy(ssid, net->ssid.ssid, net->ssid.len);
00180 CM_DPRINTF("CM: connected to %s\n", ssid);
00181 if (cm->conn_cb)
00182 cm->conn_cb(net, cm->ctx);
00183 }
00184
00185
00189 static void
00190 wl_conn_failure_cb(void* ctx)
00191 {
00192 CM_DPRINTF("CM: connect failed, scanning\n");
00193
00194 if (wl_scan() != WL_SUCCESS)
00195
00196 CM_DPRINTF("CM: could not start scan after connect fail!\n");
00197 }
00198
00199
00203 static void
00204 wl_conn_lost_cb(void* ctx)
00205 {
00206 struct cm *cm = ctx;
00207 CM_DPRINTF("CM: connection lost, scanning\n");
00208
00209 if (cm->disconn_cb)
00210 cm->disconn_cb(cm->ctx);
00211
00212 if (wl_scan() != WL_SUCCESS)
00213
00214 CM_DPRINTF("CM: could not start scan after connect lost!\n");
00215 }
00216
00217
00221 static void
00222 wl_event_cb(struct wl_event_t event, void* ctx)
00223 {
00224 struct cm *cm = ctx;
00225
00226 switch (event.id) {
00227 case WL_EVENT_MEDIA_CONNECTED:
00228 wl_media_connected_cb(cm);
00229 break;
00230
00231 case WL_EVENT_CONN_FAILURE:
00232 wl_conn_failure_cb(cm);
00233 break;
00234
00235 case WL_EVENT_MEDIA_DISCONNECTED:
00236 CM_DPRINTF("CM: disconnected\n");
00237 wl_conn_lost_cb(cm);
00238 break;
00239
00240 case WL_EVENT_CONN_LOST:
00241 wl_conn_lost_cb(cm);
00242 break;
00243
00244 case WL_EVENT_SCAN_COMPLETE:
00245 wl_scan_complete_cb(cm);
00246 break;
00247
00248 default:
00249 CM_DPRINTF("CM: unhandled event\n");
00250 };
00251 }
00252
00253 static struct cm *cm = NULL;
00254
00255
00259 wl_err_t
00260 wl_cm_start(cm_scan_cb_t scan_cb,
00261 cm_conn_cb_t conn_cb,
00262 cm_disconn_cb_t disconn_cb,
00263 void* ctx)
00264 {
00265 if (cm != NULL)
00266 return WL_FAILURE;
00267
00268 cm = calloc(1, sizeof(struct cm));
00269 if (cm == NULL) {
00270 CM_DPRINTF("CM: out of memory\n");
00271 return WL_FAILURE;
00272 }
00273
00274 if (wl_register_event_cb(wl_event_cb, cm) != WL_SUCCESS) {
00275 CM_DPRINTF("CM: could not register event cb\n");
00276 return WL_FAILURE;
00277 }
00278
00279 cm->scan_cb = scan_cb;
00280 cm->conn_cb = conn_cb;
00281 cm->disconn_cb = disconn_cb;
00282 cm->ctx = ctx;
00283 if (wl_scan() != WL_SUCCESS)
00284 CM_DPRINTF("CM: could not scan\n");
00285
00286 CM_DPRINTF("CM: initialized\n");
00287 return WL_SUCCESS;
00288 }
00289
00290
00304 wl_err_t
00305 wl_cm_set_network(struct wl_ssid_t *ssid, struct wl_mac_addr_t *bssid)
00306 {
00307 if (cm == NULL)
00308 return WL_FAILURE;
00309
00310 if (ssid)
00311 memcpy(&cm->candidate.ssid, ssid, sizeof(cm->candidate.ssid));
00312 else
00313 cm->candidate.ssid.len = 0;
00314
00315 if (bssid)
00316 memcpy(&cm->candidate.bssid, bssid,
00317 sizeof(cm->candidate.bssid));
00318 else
00319 memset(&cm->candidate.bssid, 0xff, sizeof(cm->candidate.bssid));
00320 (void) wl_scan();
00321 return WL_SUCCESS;
00322 }
00323
00324
00325