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 CM_DPRINTF("CM: connected to %s\n", ssid2str(&net->ssid));
00177 if (cm->conn_cb)
00178 cm->conn_cb(net, cm->ctx);
00179 }
00180
00181
00185 static void
00186 wl_conn_failure_cb(void* ctx)
00187 {
00188 CM_DPRINTF("CM: connect failed, scanning\n");
00189
00190 if (wl_scan() != WL_SUCCESS)
00191
00192 CM_DPRINTF("CM: could not start scan after connect fail!\n");
00193 }
00194
00195
00199 static void
00200 wl_conn_lost_cb(void* ctx)
00201 {
00202 struct cm *cm = ctx;
00203 CM_DPRINTF("CM: connection lost, scanning\n");
00204
00205 if (cm->disconn_cb)
00206 cm->disconn_cb(cm->ctx);
00207
00208 if (wl_scan() != WL_SUCCESS)
00209
00210 CM_DPRINTF("CM: could not start scan after connect lost!\n");
00211 }
00212
00213
00217 static void
00218 wl_event_cb(struct wl_event_t event, void* ctx)
00219 {
00220 struct cm *cm = ctx;
00221
00222 switch (event.id) {
00223 case WL_EVENT_MEDIA_CONNECTED:
00224 wl_media_connected_cb(cm);
00225 break;
00226
00227 case WL_EVENT_CONN_FAILURE:
00228 wl_conn_failure_cb(cm);
00229 break;
00230
00231 case WL_EVENT_MEDIA_DISCONNECTED:
00232 CM_DPRINTF("CM: disconnected\n");
00233 wl_conn_lost_cb(cm);
00234 break;
00235
00236 case WL_EVENT_CONN_LOST:
00237 wl_conn_lost_cb(cm);
00238 break;
00239
00240 case WL_EVENT_SCAN_COMPLETE:
00241 wl_scan_complete_cb(cm);
00242 break;
00243
00244 default:
00245 CM_DPRINTF("CM: unhandled event\n");
00246 };
00247 }
00248
00249 static struct cm *cm = NULL;
00250
00251
00255 wl_err_t
00256 wl_cm_start(cm_scan_cb_t scan_cb,
00257 cm_conn_cb_t conn_cb,
00258 cm_disconn_cb_t disconn_cb,
00259 void* ctx)
00260 {
00261 if (cm != NULL)
00262 return WL_FAILURE;
00263
00264 cm = calloc(1, sizeof(struct cm));
00265 if (cm == NULL) {
00266 CM_DPRINTF("CM: out of memory\n");
00267 return WL_FAILURE;
00268 }
00269
00270 if (wl_register_event_cb(wl_event_cb, cm) != WL_SUCCESS) {
00271 CM_DPRINTF("CM: could not register event cb\n");
00272 return WL_FAILURE;
00273 }
00274
00275 cm->scan_cb = scan_cb;
00276 cm->conn_cb = conn_cb;
00277 cm->disconn_cb = disconn_cb;
00278 cm->ctx = ctx;
00279 if (wl_scan() != WL_SUCCESS)
00280 CM_DPRINTF("CM: could not scan\n");
00281
00282 CM_DPRINTF("CM: initialized\n");
00283 return WL_SUCCESS;
00284 }
00285
00286
00300 wl_err_t
00301 wl_cm_set_network(struct wl_ssid_t *ssid, struct wl_mac_addr_t *bssid)
00302 {
00303 if (cm == NULL)
00304 return WL_FAILURE;
00305
00306 if (ssid)
00307 memcpy(&cm->candidate.ssid, ssid, sizeof(cm->candidate.ssid));
00308 else
00309 cm->candidate.ssid.len = 0;
00310
00311 if (bssid)
00312 memcpy(&cm->candidate.bssid, bssid,
00313 sizeof(cm->candidate.bssid));
00314 else
00315 memset(&cm->candidate.bssid, 0xff, sizeof(cm->candidate.bssid));
00316 (void) wl_scan();
00317 return WL_SUCCESS;
00318 }
00319
00320
00321