in wireless/intel/ipw2x00/ipw2200.c [4472:4926]
static void ipw_rx_notification(struct ipw_priv *priv,
struct ipw_rx_notification *notif)
{
u16 size = le16_to_cpu(notif->size);
IPW_DEBUG_NOTIF("type = %i (%d bytes)\n", notif->subtype, size);
switch (notif->subtype) {
case HOST_NOTIFICATION_STATUS_ASSOCIATED:{
struct notif_association *assoc = ¬if->u.assoc;
switch (assoc->state) {
case CMAS_ASSOCIATED:{
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
IPW_DL_ASSOC,
"associated: '%*pE' %pM\n",
priv->essid_len, priv->essid,
priv->bssid);
switch (priv->ieee->iw_mode) {
case IW_MODE_INFRA:
memcpy(priv->ieee->bssid,
priv->bssid, ETH_ALEN);
break;
case IW_MODE_ADHOC:
memcpy(priv->ieee->bssid,
priv->bssid, ETH_ALEN);
/* clear out the station table */
priv->num_stations = 0;
IPW_DEBUG_ASSOC
("queueing adhoc check\n");
schedule_delayed_work(
&priv->adhoc_check,
le16_to_cpu(priv->
assoc_request.
beacon_interval));
break;
}
priv->status &= ~STATUS_ASSOCIATING;
priv->status |= STATUS_ASSOCIATED;
schedule_work(&priv->system_config);
#ifdef CONFIG_IPW2200_QOS
#define IPW_GET_PACKET_STYPE(x) WLAN_FC_GET_STYPE( \
le16_to_cpu(((struct ieee80211_hdr *)(x))->frame_control))
if ((priv->status & STATUS_AUTH) &&
(IPW_GET_PACKET_STYPE(¬if->u.raw)
== IEEE80211_STYPE_ASSOC_RESP)) {
if ((sizeof
(struct
libipw_assoc_response)
<= size)
&& (size <= 2314)) {
struct
libipw_rx_stats
stats = {
.len = size - 1,
};
IPW_DEBUG_QOS
("QoS Associate "
"size %d\n", size);
libipw_rx_mgt(priv->
ieee,
(struct
libipw_hdr_4addr
*)
¬if->u.raw, &stats);
}
}
#endif
schedule_work(&priv->link_up);
break;
}
case CMAS_AUTHENTICATED:{
if (priv->
status & (STATUS_ASSOCIATED |
STATUS_AUTH)) {
struct notif_authenticate *auth
= ¬if->u.auth;
IPW_DEBUG(IPW_DL_NOTIF |
IPW_DL_STATE |
IPW_DL_ASSOC,
"deauthenticated: '%*pE' %pM: (0x%04X) - %s\n",
priv->essid_len,
priv->essid,
priv->bssid,
le16_to_cpu(auth->status),
ipw_get_status_code
(le16_to_cpu
(auth->status)));
priv->status &=
~(STATUS_ASSOCIATING |
STATUS_AUTH |
STATUS_ASSOCIATED);
schedule_work(&priv->link_down);
break;
}
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
IPW_DL_ASSOC,
"authenticated: '%*pE' %pM\n",
priv->essid_len, priv->essid,
priv->bssid);
break;
}
case CMAS_INIT:{
if (priv->status & STATUS_AUTH) {
struct
libipw_assoc_response
*resp;
resp =
(struct
libipw_assoc_response
*)¬if->u.raw;
IPW_DEBUG(IPW_DL_NOTIF |
IPW_DL_STATE |
IPW_DL_ASSOC,
"association failed (0x%04X): %s\n",
le16_to_cpu(resp->status),
ipw_get_status_code
(le16_to_cpu
(resp->status)));
}
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
IPW_DL_ASSOC,
"disassociated: '%*pE' %pM\n",
priv->essid_len, priv->essid,
priv->bssid);
priv->status &=
~(STATUS_DISASSOCIATING |
STATUS_ASSOCIATING |
STATUS_ASSOCIATED | STATUS_AUTH);
if (priv->assoc_network
&& (priv->assoc_network->
capability &
WLAN_CAPABILITY_IBSS))
ipw_remove_current_network
(priv);
schedule_work(&priv->link_down);
break;
}
case CMAS_RX_ASSOC_RESP:
break;
default:
IPW_ERROR("assoc: unknown (%d)\n",
assoc->state);
break;
}
break;
}
case HOST_NOTIFICATION_STATUS_AUTHENTICATE:{
struct notif_authenticate *auth = ¬if->u.auth;
switch (auth->state) {
case CMAS_AUTHENTICATED:
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE,
"authenticated: '%*pE' %pM\n",
priv->essid_len, priv->essid,
priv->bssid);
priv->status |= STATUS_AUTH;
break;
case CMAS_INIT:
if (priv->status & STATUS_AUTH) {
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
IPW_DL_ASSOC,
"authentication failed (0x%04X): %s\n",
le16_to_cpu(auth->status),
ipw_get_status_code(le16_to_cpu
(auth->
status)));
}
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
IPW_DL_ASSOC,
"deauthenticated: '%*pE' %pM\n",
priv->essid_len, priv->essid,
priv->bssid);
priv->status &= ~(STATUS_ASSOCIATING |
STATUS_AUTH |
STATUS_ASSOCIATED);
schedule_work(&priv->link_down);
break;
case CMAS_TX_AUTH_SEQ_1:
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
IPW_DL_ASSOC, "AUTH_SEQ_1\n");
break;
case CMAS_RX_AUTH_SEQ_2:
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
IPW_DL_ASSOC, "AUTH_SEQ_2\n");
break;
case CMAS_AUTH_SEQ_1_PASS:
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
IPW_DL_ASSOC, "AUTH_SEQ_1_PASS\n");
break;
case CMAS_AUTH_SEQ_1_FAIL:
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
IPW_DL_ASSOC, "AUTH_SEQ_1_FAIL\n");
break;
case CMAS_TX_AUTH_SEQ_3:
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
IPW_DL_ASSOC, "AUTH_SEQ_3\n");
break;
case CMAS_RX_AUTH_SEQ_4:
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
IPW_DL_ASSOC, "RX_AUTH_SEQ_4\n");
break;
case CMAS_AUTH_SEQ_2_PASS:
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
IPW_DL_ASSOC, "AUTH_SEQ_2_PASS\n");
break;
case CMAS_AUTH_SEQ_2_FAIL:
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
IPW_DL_ASSOC, "AUT_SEQ_2_FAIL\n");
break;
case CMAS_TX_ASSOC:
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
IPW_DL_ASSOC, "TX_ASSOC\n");
break;
case CMAS_RX_ASSOC_RESP:
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
IPW_DL_ASSOC, "RX_ASSOC_RESP\n");
break;
case CMAS_ASSOCIATED:
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
IPW_DL_ASSOC, "ASSOCIATED\n");
break;
default:
IPW_DEBUG_NOTIF("auth: failure - %d\n",
auth->state);
break;
}
break;
}
case HOST_NOTIFICATION_STATUS_SCAN_CHANNEL_RESULT:{
struct notif_channel_result *x =
¬if->u.channel_result;
if (size == sizeof(*x)) {
IPW_DEBUG_SCAN("Scan result for channel %d\n",
x->channel_num);
} else {
IPW_DEBUG_SCAN("Scan result of wrong size %d "
"(should be %zd)\n",
size, sizeof(*x));
}
break;
}
case HOST_NOTIFICATION_STATUS_SCAN_COMPLETED:{
struct notif_scan_complete *x = ¬if->u.scan_complete;
if (size == sizeof(*x)) {
IPW_DEBUG_SCAN
("Scan completed: type %d, %d channels, "
"%d status\n", x->scan_type,
x->num_channels, x->status);
} else {
IPW_ERROR("Scan completed of wrong size %d "
"(should be %zd)\n",
size, sizeof(*x));
}
priv->status &=
~(STATUS_SCANNING | STATUS_SCAN_ABORTING);
wake_up_interruptible(&priv->wait_state);
cancel_delayed_work(&priv->scan_check);
if (priv->status & STATUS_EXIT_PENDING)
break;
priv->ieee->scans++;
#ifdef CONFIG_IPW2200_MONITOR
if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
priv->status |= STATUS_SCAN_FORCED;
schedule_delayed_work(&priv->request_scan, 0);
break;
}
priv->status &= ~STATUS_SCAN_FORCED;
#endif /* CONFIG_IPW2200_MONITOR */
/* Do queued direct scans first */
if (priv->status & STATUS_DIRECT_SCAN_PENDING)
schedule_delayed_work(&priv->request_direct_scan, 0);
if (!(priv->status & (STATUS_ASSOCIATED |
STATUS_ASSOCIATING |
STATUS_ROAMING |
STATUS_DISASSOCIATING)))
schedule_work(&priv->associate);
else if (priv->status & STATUS_ROAMING) {
if (x->status == SCAN_COMPLETED_STATUS_COMPLETE)
/* If a scan completed and we are in roam mode, then
* the scan that completed was the one requested as a
* result of entering roam... so, schedule the
* roam work */
schedule_work(&priv->roam);
else
/* Don't schedule if we aborted the scan */
priv->status &= ~STATUS_ROAMING;
} else if (priv->status & STATUS_SCAN_PENDING)
schedule_delayed_work(&priv->request_scan, 0);
else if (priv->config & CFG_BACKGROUND_SCAN
&& priv->status & STATUS_ASSOCIATED)
schedule_delayed_work(&priv->request_scan,
round_jiffies_relative(HZ));
/* Send an empty event to user space.
* We don't send the received data on the event because
* it would require us to do complex transcoding, and
* we want to minimise the work done in the irq handler
* Use a request to extract the data.
* Also, we generate this even for any scan, regardless
* on how the scan was initiated. User space can just
* sync on periodic scan to get fresh data...
* Jean II */
if (x->status == SCAN_COMPLETED_STATUS_COMPLETE)
handle_scan_event(priv);
break;
}
case HOST_NOTIFICATION_STATUS_FRAG_LENGTH:{
struct notif_frag_length *x = ¬if->u.frag_len;
if (size == sizeof(*x))
IPW_ERROR("Frag length: %d\n",
le16_to_cpu(x->frag_length));
else
IPW_ERROR("Frag length of wrong size %d "
"(should be %zd)\n",
size, sizeof(*x));
break;
}
case HOST_NOTIFICATION_STATUS_LINK_DETERIORATION:{
struct notif_link_deterioration *x =
¬if->u.link_deterioration;
if (size == sizeof(*x)) {
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE,
"link deterioration: type %d, cnt %d\n",
x->silence_notification_type,
x->silence_count);
memcpy(&priv->last_link_deterioration, x,
sizeof(*x));
} else {
IPW_ERROR("Link Deterioration of wrong size %d "
"(should be %zd)\n",
size, sizeof(*x));
}
break;
}
case HOST_NOTIFICATION_DINO_CONFIG_RESPONSE:{
IPW_ERROR("Dino config\n");
if (priv->hcmd
&& priv->hcmd->cmd != HOST_CMD_DINO_CONFIG)
IPW_ERROR("Unexpected DINO_CONFIG_RESPONSE\n");
break;
}
case HOST_NOTIFICATION_STATUS_BEACON_STATE:{
struct notif_beacon_state *x = ¬if->u.beacon_state;
if (size != sizeof(*x)) {
IPW_ERROR
("Beacon state of wrong size %d (should "
"be %zd)\n", size, sizeof(*x));
break;
}
if (le32_to_cpu(x->state) ==
HOST_NOTIFICATION_STATUS_BEACON_MISSING)
ipw_handle_missed_beacon(priv,
le32_to_cpu(x->
number));
break;
}
case HOST_NOTIFICATION_STATUS_TGI_TX_KEY:{
struct notif_tgi_tx_key *x = ¬if->u.tgi_tx_key;
if (size == sizeof(*x)) {
IPW_ERROR("TGi Tx Key: state 0x%02x sec type "
"0x%02x station %d\n",
x->key_state, x->security_type,
x->station_index);
break;
}
IPW_ERROR
("TGi Tx Key of wrong size %d (should be %zd)\n",
size, sizeof(*x));
break;
}
case HOST_NOTIFICATION_CALIB_KEEP_RESULTS:{
struct notif_calibration *x = ¬if->u.calibration;
if (size == sizeof(*x)) {
memcpy(&priv->calib, x, sizeof(*x));
IPW_DEBUG_INFO("TODO: Calibration\n");
break;
}
IPW_ERROR
("Calibration of wrong size %d (should be %zd)\n",
size, sizeof(*x));
break;
}
case HOST_NOTIFICATION_NOISE_STATS:{
if (size == sizeof(u32)) {
priv->exp_avg_noise =
exponential_average(priv->exp_avg_noise,
(u8) (le32_to_cpu(notif->u.noise.value) & 0xff),
DEPTH_NOISE);
break;
}
IPW_ERROR
("Noise stat is wrong size %d (should be %zd)\n",
size, sizeof(u32));
break;
}
default:
IPW_DEBUG_NOTIF("Unknown notification: "
"subtype=%d,flags=0x%2x,size=%d\n",
notif->subtype, notif->flags, size);
}
}