/** * Doesn't actually start the CM, just initializing. CM will run whenever * an valid ssid is set through wl_cm_set_network() and wl_cm_start() * has been called. */ wl_err_t wl_cm_init(cm_scan_cb_t scan_cb, cm_conn_cb_t conn_cb, cm_disconn_cb_t disconn_cb, void* ctx) { if (cm != NULL) return WL_FAILURE; cm = calloc(1, sizeof(struct cm)); if (cm == NULL) { CM_DPRINTF("CM: out of memory\n"); return WL_FAILURE; } if (wl_register_event_cb(wl_event_cb, cm) != WL_SUCCESS) { CM_DPRINTF("CM: could not register event cb\n"); return WL_FAILURE; } cm->scan_cb = scan_cb; cm->conn_cb = conn_cb; cm->disconn_cb = disconn_cb; cm->enabled = 0; cm->ctx = ctx; CM_DPRINTF("CM: initialized\n"); return WL_SUCCESS; }
static void wl_event_cb(struct wl_event_t event, void* ctx) { struct cm *cm = ctx; switch (event.id) { case WL_EVENT_MEDIA_CONNECTED: wl_media_connected_cb(cm); break; case WL_EVENT_CONN_FAILURE: wl_conn_failure_cb(cm); break; case WL_EVENT_MEDIA_DISCONNECTED: CM_DPRINTF("CM: disconnected\n"); wl_conn_lost_cb(cm); break; case WL_EVENT_SCAN_COMPLETE: wl_scan_complete_cb(cm); break; default: CM_DPRINTF("CM: unhandled event\n"); }; }
static void wl_conn_failure_cb(void* ctx) { CM_DPRINTF("CM: connect failed, scanning\n"); if (wl_scan() != WL_SUCCESS) /* should never happen */ CM_DPRINTF("CM: could not start scan after connect fail!\n"); }
static void wl_conn_lost_cb(void* ctx) { struct cm *cm = ctx; CM_DPRINTF("CM: connection lost, scanning\n"); if (cm->disconn_cb) cm->disconn_cb(cm->ctx); if (wl_scan() != WL_SUCCESS) /* should never happen */ CM_DPRINTF("CM: could not start scan after connect lost!\n"); }
static void wl_conn_failure_cb(void* ctx) { struct cm *cm = ctx; CM_DPRINTF("CM: connect failed, scanning\n"); ERROR_LED_ON(); LINK_LED_OFF(); if ( 0 == cm->enabled ) { return; } if (wl_scan() != WL_SUCCESS) /* should never happen */ CM_DPRINTF("CM: could not start scan after connect fail!\n"); }
static void wl_media_connected_cb(void* ctx) { struct cm *cm = ctx; struct wl_network_t *net = wl_get_current_network(); CM_DPRINTF("CM: connected to %s\n", ssid2str(&net->ssid)); if (cm->conn_cb) cm->conn_cb(net, cm->ctx); }
static void wl_scan_complete_cb(void* ctx) { struct cm *cm = ctx; CM_DPRINTF("CM: scan completed\n"); if (cm->scan_cb) cm->scan_cb(cm->ctx); select_net(cm); }
static void select_net(struct cm* cm) { struct wl_network_t *candidate_net; struct wl_network_t *current_net; struct wl_ssid_t *ssid_p; int ret; /* Nothing to do */ if (0 == cm->candidate.ssid.len) { return; } current_net = wl_get_current_network(); candidate_net = find_best_candidate(cm); /* Connected to the candidate? ... */ if ( current_net == candidate_net ) { if ( current_net ) { /* ...yes, dont change. */ return; } } /* Roaming checks */ if (current_net && candidate_net) { /* Are we changing BSSs? */ if ( equal_ssid(&candidate_net->ssid, ¤t_net->ssid)) { /* ...no. Does the currently connected * net have a decent RSSI?...*/ if ( current_net->rssi > ROAMING_RSSI_THRESHOLD ) { /* ...yes, stay with it. */ return; } /* ...no. Does the candidate have * sufficiently better RSSI to * motivate a switch to it? */ if ( candidate_net->rssi < current_net->rssi + ROAMING_RSSI_DIFF) { return; } /* ...yes, try to roam to candidate_net */ CM_DPRINTF("CM: Roaming from rssi %d to %d\n", current_net->rssi, candidate_net->rssi); } } /* a candidate is found */ if (candidate_net) { /* We connect to a specific bssid here because * find_best_candidate() might have picked a * particulare AP among many with the same SSID. * wl_connect() would pick one of them at random. */ ret = wl_connect_bssid(candidate_net->bssid); } /* no candidate found */ else { CM_DPRINTF("CM: No candidate found for ssid \"%s\"\n", ssid2str(&cm->candidate.ssid)); /* Might be a hidden SSID so we try to connect to it. * wl_connect() will trigger a directed scan * for the SSID in this case. */ ssid_p = &cm->candidate.ssid; ret = wl_connect(ssid_p->ssid, ssid_p->len); } switch (ret) { case WL_SUCCESS : return; case WL_BUSY: wl_disconnect(); return; case WL_RETRY: break; default : CM_DPRINTF("CM: failed to connect\n"); break; } /* some operation failed or no candidate found */ if (wl_scan() != WL_SUCCESS) CM_DPRINTF("CM: failed to scan\n"); }