if (entry->skb != NULL)
dev_kfree_skb_any(entry->skb);
entry->first_frag_time = jiffies;
entry->seq = seq;
entry->last_frag = frag;
entry->skb = skb;
memcpy(entry->src_addr, hdr->addr2, ETH_ALEN);
memcpy(entry->dst_addr, hdr->addr1, ETH_ALEN);
} else { /* received a fragment of a frame for which the head fragment
* should have already been received */
entry = libipw_frag_cache_find(ieee, seq, frag, hdr->addr2,
hdr->addr1); if (entry != NULL) {
entry->last_frag = frag;
skb = entry->skb;
}
}
return skb;
}
/* Called only as a tasklet (software IRQ) */ staticint libipw_frag_cache_invalidate(struct libipw_device *ieee, struct libipw_hdr_4addr *hdr)
{
u16 sc; unsignedint seq; struct libipw_frag_entry *entry;
if (entry == NULL) {
LIBIPW_DEBUG_FRAG("could not invalidate fragment cache " "entry (seq=%u)\n", seq); return -1;
}
entry->skb = NULL; return 0;
}
#ifdef NOT_YET /* libipw_rx_frame_mgtmt * * Responsible for handling management control frames *
* Called by libipw_rx */ staticint
libipw_rx_frame_mgmt(struct libipw_device *ieee, struct sk_buff *skb, struct libipw_rx_stats *rx_stats, u16 type,
u16 stype)
{ if (ieee->iw_mode == IW_MODE_MASTER) {
printk(KERN_DEBUG "%s: Master mode not yet supported.\n",
ieee->dev->name); return 0; /* hostap_update_sta_ps(ieee, (struct hostap_libipw_hdr_4addr *)
skb->data);*/
}
if (ieee->hostapd && type == WLAN_FC_TYPE_MGMT) { if (stype == WLAN_FC_STYPE_BEACON &&
ieee->iw_mode == IW_MODE_MASTER) { struct sk_buff *skb2; /* Process beacon frames also in kernel driver to
* update STA(AP) table statistics */
skb2 = skb_clone(skb, GFP_ATOMIC); if (skb2)
hostap_rx(skb2->dev, skb2, rx_stats);
}
/* send management frames to the user space daemon for
* processing */
ieee->apdevstats.rx_packets++;
ieee->apdevstats.rx_bytes += skb->len;
prism2_rx_80211(ieee->apdev, skb, rx_stats, PRISM2_RX_MGMT); return 0;
}
if (ieee->iw_mode == IW_MODE_MASTER) { if (type != WLAN_FC_TYPE_MGMT && type != WLAN_FC_TYPE_CTRL) {
printk(KERN_DEBUG "%s: unknown management frame " "(type=0x%02x, stype=0x%02x) dropped\n",
skb->dev->name, type, stype); return -1;
}
hostap_rx(skb->dev, skb, rx_stats); return 0;
}
printk(KERN_DEBUG "%s: hostap_rx_frame_mgmt: management frame " "received in non-Host AP mode\n", skb->dev->name); return -1;
} #endif
/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ /* Ethernet-II snap header (RFC1042 for most EtherTypes) */ staticunsignedchar libipw_rfc1042_header[] =
{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ staticunsignedchar libipw_bridge_tunnel_header[] =
{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; /* No encapsulation header if EtherType < 0x600 (=length) */
hdr = (struct libipw_hdr_3addr *)skb->data;
fc = le16_to_cpu(hdr->frame_ctl);
/* check that the frame is unicast frame to us */ if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
IEEE80211_FCTL_TODS &&
ether_addr_equal(hdr->addr1, dev->dev_addr) &&
ether_addr_equal(hdr->addr3, dev->dev_addr)) { /* ToDS frame with own addr BSSID and DA */
} elseif ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
IEEE80211_FCTL_FROMDS &&
ether_addr_equal(hdr->addr1, dev->dev_addr)) { /* FromDS frame with own addr as DA */
} else return 0;
if (skb->len < 24 + 8) return 0;
/* check for port access entity Ethernet type */
pos = skb->data + 24;
ethertype = (pos[6] << 8) | pos[7]; if (ethertype == ETH_P_PAE) return 1;
return 0;
}
/* Called only as a tasklet (software IRQ), by libipw_rx */ staticint
libipw_rx_frame_decrypt(struct libipw_device *ieee, struct sk_buff *skb, struct libipw_crypt_data *crypt)
{ struct libipw_hdr_3addr *hdr; int res, hdrlen;
if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL) return 0;
/* Called only as a tasklet (software IRQ), by libipw_rx */ staticint
libipw_rx_frame_decrypt_msdu(struct libipw_device *ieee, struct sk_buff *skb, int keyidx, struct libipw_crypt_data *crypt)
{ struct libipw_hdr_3addr *hdr; int res, hdrlen;
if (crypt == NULL || crypt->ops->decrypt_msdu == NULL) return 0;
/* All received frames are sent to this function. @skb contains the frame in * IEEE 802.11 format, i.e., in the format it was sent over air.
* This function is called only as a tasklet (software IRQ). */ int libipw_rx(struct libipw_device *ieee, struct sk_buff *skb, struct libipw_rx_stats *rx_stats)
{ struct net_device *dev = ieee->dev; struct libipw_hdr_4addr *hdr;
size_t hdrlen;
u16 fc, type, stype, sc; unsignedint frag;
u8 *payload;
u16 ethertype; #ifdef NOT_YET struct net_device *wds = NULL; struct sk_buff *skb2 = NULL; struct net_device *wds = NULL; int frame_authorized = 0; int from_assoc_ap = 0; void *sta = NULL; #endif
u8 dst[ETH_ALEN];
u8 src[ETH_ALEN]; struct libipw_crypt_data *crypt = NULL; int keyidx = 0; int can_be_decrypted = 0;
/* Put this code here so that we avoid duplicating it in all
* Rx paths. - Jean II */ #ifdef CONFIG_WIRELESS_EXT #ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */ /* If spy monitoring on */ if (ieee->spy_data.spy_number > 0) { struct iw_quality wstats;
if (can_be_decrypted) { if (skb->len >= hdrlen + 3) { /* Top two-bits of byte 3 are the key index */
keyidx = skb->data[hdrlen + 3] >> 6;
}
/* ieee->crypt[] is WEP_KEY (4) in length. Given that keyidx * is only allowed 2-bits of storage, no value of keyidx can * be provided via above code that would result in keyidx
* being out of range */
crypt = ieee->crypt_info.crypt[keyidx];
#ifdef NOT_YET
sta = NULL;
/* Use station specific key to override default keys if the * receiver address is a unicast address ("individual RA"). If * bcrx_sta_key parameter is set, station specific key is used * even with broad/multicast targets (this is against IEEE * 802.11, but makes it easier to use different keys with
* stations that do not support WEP key mapping). */
if (is_unicast_ether_addr(hdr->addr1) || local->bcrx_sta_key)
(void)hostap_handle_sta_crypto(local, hdr, &crypt,
&sta); #endif
/* allow NULL decrypt to indicate an station specific override
* for default encryption */ if (crypt && (crypt->ops == NULL ||
crypt->ops->decrypt_mpdu == NULL))
crypt = NULL;
if (!crypt && (fc & IEEE80211_FCTL_PROTECTED)) { /* This seems to be triggered by some (multicast?) * frames from other than current BSS, so just drop the * frames silently instead of filling system log with
* these reports. */
LIBIPW_DEBUG_DROP("Decryption failed (not set)" " (SA=%pM)\n", hdr->addr2);
ieee->ieee_stats.rx_discards_undecryptable++; goto rx_dropped;
}
} #ifdef NOT_YET if (type != WLAN_FC_TYPE_DATA) { if (type == WLAN_FC_TYPE_MGMT && stype == WLAN_FC_STYPE_AUTH &&
fc & IEEE80211_FCTL_PROTECTED && ieee->host_decrypt &&
(keyidx = hostap_rx_frame_decrypt(ieee, skb, crypt)) < 0) {
printk(KERN_DEBUG "%s: failed to decrypt mgmt::auth " "from %pM\n", dev->name, hdr->addr2); /* TODO: could inform hostapd about this so that it
* could send auth failure report */ goto rx_dropped;
}
#ifdef NOT_YET if (hostap_rx_frame_wds(ieee, hdr, fc, &wds)) goto rx_dropped; if (wds) {
skb->dev = dev = wds;
stats = hostap_get_stats(dev);
}
if (ieee->iw_mode == IW_MODE_MASTER && !wds &&
(fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
IEEE80211_FCTL_FROMDS && ieee->stadev &&
ether_addr_equal(hdr->addr2, ieee->assoc_ap_addr)) { /* Frame from BSSID of the AP for which we are a client */
skb->dev = dev = ieee->stadev;
stats = hostap_get_stats(dev);
from_assoc_ap = 1;
} #endif
#ifdef NOT_YET if ((ieee->iw_mode == IW_MODE_MASTER ||
ieee->iw_mode == IW_MODE_REPEAT) && !from_assoc_ap) { switch (hostap_handle_sta_rx(ieee, dev, skb, rx_stats,
wds != NULL)) { case AP_RX_CONTINUE_NOT_AUTHORIZED:
frame_authorized = 0; break; case AP_RX_CONTINUE:
frame_authorized = 1; break; case AP_RX_DROP: goto rx_dropped; case AP_RX_EXIT: goto rx_exit;
}
} #endif
/* Nullfunc frames may have PS-bit set, so they must be passed to
* hostap_handle_sta_rx() before being dropped here. */
stype &= ~IEEE80211_STYPE_QOS_DATA;
if (stype != IEEE80211_STYPE_DATA &&
stype != IEEE80211_STYPE_DATA_CFACK &&
stype != IEEE80211_STYPE_DATA_CFPOLL &&
stype != IEEE80211_STYPE_DATA_CFACKPOLL) { if (stype != IEEE80211_STYPE_NULLFUNC)
LIBIPW_DEBUG_DROP("RX: dropped data frame " "with no data (type=0x%02x, " "subtype=0x%02x, len=%d)\n",
type, stype, skb->len); goto rx_dropped;
}
/* skb: hdr + (possibly fragmented) plaintext payload */ // PR: FIXME: hostap has additional conditions in the "if" below: // ieee->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) && if ((frag != 0) || (fc & IEEE80211_FCTL_MOREFRAGS)) { int flen; struct sk_buff *frag_skb = libipw_frag_cache_get(ieee, hdr);
LIBIPW_DEBUG_FRAG("Rx Fragment received (%u)\n", frag);
if (!frag_skb) {
LIBIPW_DEBUG(LIBIPW_DL_RX | LIBIPW_DL_FRAG, "Rx cannot get skb from fragment " "cache (morefrag=%d seq=%u frag=%u)\n",
(fc & IEEE80211_FCTL_MOREFRAGS) != 0,
WLAN_GET_SEQ_SEQ(sc), frag); goto rx_dropped;
}
flen = skb->len; if (frag != 0)
flen -= hdrlen;
if (frag_skb->tail + flen > frag_skb->end) {
printk(KERN_WARNING "%s: host decrypted and " "reassembled frame did not fit skb\n",
dev->name);
libipw_frag_cache_invalidate(ieee, hdr); goto rx_dropped;
}
if (frag == 0) { /* copy first fragment (including full headers) into
* beginning of the fragment cache skb */
skb_copy_from_linear_data(skb, skb_put(frag_skb, flen), flen);
} else { /* append frame payload to the end of the fragment
* cache skb */
skb_copy_from_linear_data_offset(skb, hdrlen,
skb_put(frag_skb, flen), flen);
}
dev_kfree_skb_any(skb);
skb = NULL;
if (fc & IEEE80211_FCTL_MOREFRAGS) { /* more fragments expected - leave the skb in fragment * cache for now; it will be delivered to upper layers
* after all fragments have been received */ goto rx_exit;
}
/* this was the last fragment and the frame will be
* delivered, so remove skb from fragment cache */
skb = frag_skb;
hdr = (struct libipw_hdr_4addr *)skb->data;
libipw_frag_cache_invalidate(ieee, hdr);
}
/* skb: hdr + (possible reassembled) full MSDU payload; possibly still
* encrypted/authenticated */ if ((fc & IEEE80211_FCTL_PROTECTED) && can_be_decrypted &&
libipw_rx_frame_decrypt_msdu(ieee, skb, keyidx, crypt)) goto rx_dropped;
hdr = (struct libipw_hdr_4addr *)skb->data; if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !ieee->open_wep) { if ( /*ieee->ieee802_1x && */
libipw_is_eapol_frame(ieee, skb)) { /* pass unencrypted EAPOL frames even if encryption is
* configured */
} else {
LIBIPW_DEBUG_DROP("encryption configured, but RX " "frame not encrypted (SA=%pM)\n",
hdr->addr2); goto rx_dropped;
}
}
if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !ieee->open_wep &&
!libipw_is_eapol_frame(ieee, skb)) {
LIBIPW_DEBUG_DROP("dropped unencrypted RX data " "frame from %pM (drop_unencrypted=1)\n",
hdr->addr2); goto rx_dropped;
}
/* If the frame was decrypted in hardware, we may need to strip off
* any security data (IV, ICV, etc) that was left behind */ if (!can_be_decrypted && (fc & IEEE80211_FCTL_PROTECTED) &&
ieee->host_strip_iv_icv) { int trimlen = 0;
/* Top two-bits of byte 3 are the key index */ if (skb->len >= hdrlen + 3)
keyidx = skb->data[hdrlen + 3] >> 6;
/* To strip off any security data which appears before the * payload, we simply increase hdrlen (as the header gets * chopped off immediately below). For the security data which
* appears after the payload, we use skb_trim. */
#ifdef NOT_YET if (ieee->iw_mode == IW_MODE_MASTER && !wds && ieee->ap->bridge_packets) { if (is_multicast_ether_addr(dst)) { /* copy multicast frame both to the higher layers and
* to the wireless media */
ieee->ap->bridged_multicast++;
skb2 = skb_clone(skb, GFP_ATOMIC); if (skb2 == NULL)
printk(KERN_DEBUG "%s: skb_clone failed for " "multicast frame\n", dev->name);
} elseif (hostap_is_sta_assoc(ieee->ap, dst)) { /* send frame directly to the associated STA using
* wireless media and not passing to higher layers */
ieee->ap->bridged_unicast++;
skb2 = skb;
skb = NULL;
}
}
if (skb2 != NULL) { /* send to wireless media */
skb2->dev = dev;
skb2->protocol = htons(ETH_P_802_3);
skb_reset_mac_header(skb2);
skb_reset_network_header(skb2); /* skb2->network_header += ETH_HLEN; */
dev_queue_xmit(skb2);
} #endif
if (skb) {
skb->protocol = eth_type_trans(skb, dev);
memset(skb->cb, 0, sizeof(skb->cb));
skb->ip_summed = CHECKSUM_NONE; /* 802.11 crc not sufficient */ if (netif_rx(skb) == NET_RX_DROP) { /* netif_rx always succeeds, but it might drop * the packet. If it drops the packet, we log that
* in our stats. */
LIBIPW_DEBUG_DROP
("RX: netif_rx dropped the packet\n");
dev->stats.rx_dropped++;
}
}
rx_exit: #ifdef NOT_YET if (sta)
hostap_handle_sta_release(sta); #endif return 1;
rx_dropped:
dev->stats.rx_dropped++;
/* Returning 0 indicates to caller that we have not handled the SKB-- * so it is still allocated and can be used again by underlying
* hardware as a DMA target */ return 0;
}
/* * Make the structure we read from the beacon packet to have * the right values
*/ staticint libipw_verify_qos_info(struct libipw_qos_information_element
*info_element, int sub_type)
{ if (info_element->elementID != QOS_ELEMENT_ID) return -1; if (info_element->qui_subtype != sub_type) return -1; if (memcmp(info_element->qui, qos_oui, QOS_OUI_LEN)) return -1; if (info_element->qui_type != QOS_OUI_TYPE) return -1; if (info_element->version != QOS_VERSION_1) return -1;
/* * we have a generic data element which it may contain QoS information or * parameters element. check the information element length to decide * which type to read
*/ staticint libipw_parse_qos_info_param_IE(struct libipw_info_element
*info_element, struct libipw_network *network)
{ int rc = 0; struct libipw_qos_parameters *qos_param = NULL; struct libipw_qos_information_element qos_info_element;
case WLAN_EID_IBSS_PARAMS:
network->atim_window = info_element->data[0];
LIBIPW_DEBUG_MGMT("WLAN_EID_IBSS_PARAMS: %d\n",
network->atim_window); break;
case WLAN_EID_CHALLENGE:
LIBIPW_DEBUG_MGMT("WLAN_EID_CHALLENGE: ignored\n"); break;
case WLAN_EID_VENDOR_SPECIFIC:
LIBIPW_DEBUG_MGMT("WLAN_EID_VENDOR_SPECIFIC: %d bytes\n",
info_element->len); if (!libipw_parse_qos_info_param_IE(info_element,
network)) break;
if (stats->freq == LIBIPW_52GHZ_BAND) { /* for A band (No DS info) */
network->channel = stats->received_channel;
} else
network->flags |= NETWORK_HAS_CCK;
network->wpa_ie_len = 0;
network->rsn_ie_len = 0;
if (libipw_parse_info_param((void *)frame->variable,
stats->len - sizeof(*frame), network)) return 1;
network->mode = 0; if (stats->freq == LIBIPW_52GHZ_BAND)
network->mode = IEEE_A; else { if (network->flags & NETWORK_HAS_OFDM)
network->mode |= IEEE_G; if (network->flags & NETWORK_HAS_CCK)
network->mode |= IEEE_B;
}
if (stats->freq == LIBIPW_52GHZ_BAND) { /* for A band (No DS info) */
network->channel = stats->received_channel;
} else
network->flags |= NETWORK_HAS_CCK;
network->wpa_ie_len = 0;
network->rsn_ie_len = 0;
if (libipw_parse_info_param((void *)beacon->variable,
stats->len - sizeof(*beacon), network)) return 1;
network->mode = 0; if (stats->freq == LIBIPW_52GHZ_BAND)
network->mode = IEEE_A; else { if (network->flags & NETWORK_HAS_OFDM)
network->mode |= IEEE_G; if (network->flags & NETWORK_HAS_CCK)
network->mode |= IEEE_B;
}
if (network->mode == 0) {
LIBIPW_DEBUG_SCAN("Filtered out '%*pE (%pM)' network.\n",
network->ssid_len, network->ssid,
network->bssid); return 1;
}
staticinlineint is_same_network(struct libipw_network *src, struct libipw_network *dst)
{ /* A network is only a duplicate if the channel, BSSID, and ESSID * all match. We treat all <hidden> with the same BSSID and channel
* as one network */ return ((src->ssid_len == dst->ssid_len) &&
(src->channel == dst->channel) &&
ether_addr_equal_64bits(src->bssid, dst->bssid) &&
!memcmp(src->ssid, dst->ssid, src->ssid_len));
}
/* We only update the statistics if they were created by receiving * the network information on the actual channel the network is on. * * This keeps beacons received on neighbor channels from bringing
* down the signal level of an AP. */ if (dst->channel == src->stats.received_channel)
memcpy(&dst->stats, &src->stats, sizeof(struct libipw_rx_stats)); else
LIBIPW_DEBUG_SCAN("Network %pM info received " "off channel (%d vs. %d)\n", src->bssid,
dst->channel, src->stats.received_channel);
/* The network parsed correctly -- so now we scan our known networks * to see if we can find it in our list. * * NOTE: This search is definitely not optimized. Once its doing * the "right thing" we'll optimize it for efficiency if
* necessary */
/* Search for this entry in the list and update it if it is
* already there. */
spin_lock_irqsave(&ieee->lock, flags);
list_for_each_entry(target, &ieee->network_list, list) { if (is_same_network(target, &network)) break;
/* If we didn't find a match, then get a new network slot to initialize
* with this beacon's information */ if (&target->list == &ieee->network_list) { if (list_empty(&ieee->network_free_list)) { /* If there are no more slots, expire the oldest */
list_del(&oldest->list);
target = oldest;
LIBIPW_DEBUG_SCAN("Expired '%*pE' (%pM) from network list.\n",
target->ssid_len, target->ssid,
target->bssid);
} else { /* Otherwise just pull from the free list */
target = list_entry(ieee->network_free_list.next, struct libipw_network, list);
list_del(ieee->network_free_list.next);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.