📄 ieee80211_output.c.svn-base
字号:
struct sk_buff *skb; struct ieee80211_frame *wh; u_int8_t *frm; skb = ieee80211_getmgtframe(&frm, 0); if (skb == NULL) { /* XXX debug msg */ vap->iv_stats.is_tx_nobuf++; ieee80211_unref_node(&ni); return -ENOMEM; } wh = (struct ieee80211_frame *) skb_push(skb, sizeof(struct ieee80211_frame)); ieee80211_send_setup(vap, ni, wh, IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_NULL, vap->iv_myaddr, ni->ni_macaddr, vap->iv_bssid); /* NB: power management bit is never sent by an AP */ if ((IEEE80211_VAP_IS_SLEEPING(ni->ni_vap)) && vap->iv_opmode != IEEE80211_M_HOSTAP && vap->iv_opmode != IEEE80211_M_WDS) wh->i_fc[1] |= IEEE80211_FC1_PWR_MGT; IEEE80211_NODE_STAT(ni, tx_data); IEEE80211_DPRINTF(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, "[" MAC_FMT "] send null data frame on channel %u, pwr mgt %s\n", MAC_ADDR(ni->ni_macaddr), ieee80211_chan2ieee(ic, ic->ic_curchan), wh->i_fc[1] & IEEE80211_FC1_PWR_MGT ? "ena" : "dis"); /* XXX assign some priority; this probably is wrong */ skb->priority = WME_AC_BE; SKB_NI(skb) = PASS_NODE(ni); (void) ic->ic_mgtstart(ic, skb); /* cheat */ return 0;}/* * NB: unlike ieee80211_send_nulldata(), the node refcnt is * bumped within this function. */intieee80211_send_qosnulldata(struct ieee80211_node *ni, int ac){ struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; struct sk_buff *skb; struct ieee80211_qosframe *qwh; u_int8_t *frm; int tid; skb = ieee80211_getmgtframe(&frm, 2); if (skb == NULL) { /* XXX debug msg */ vap->iv_stats.is_tx_nobuf++; return -ENOMEM; } SKB_NI(skb) = ieee80211_ref_node(ni); skb->priority = ac; qwh = (struct ieee80211_qosframe *)skb_push(skb, sizeof(struct ieee80211_qosframe)); qwh = (struct ieee80211_qosframe *)skb->data; ieee80211_send_setup(vap, ni, (struct ieee80211_frame *)qwh, IEEE80211_FC0_TYPE_DATA, vap->iv_myaddr, /* SA */ ni->ni_macaddr, /* DA */ vap->iv_bssid); qwh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS_NULL; if (IEEE80211_VAP_IS_SLEEPING(ni->ni_vap)) qwh->i_fc[1] |= IEEE80211_FC1_PWR_MGT; /* map from access class/queue to 11e header priority value */ tid = WME_AC_TO_TID(ac); qwh->i_qos[0] = tid & IEEE80211_QOS_TID; if (ic->ic_wme.wme_wmeChanParams.cap_wmeParams[ac].wmep_noackPolicy) qwh->i_qos[0] |= (1 << IEEE80211_QOS_ACKPOLICY_S) & IEEE80211_QOS_ACKPOLICY; qwh->i_qos[1] = 0; IEEE80211_NODE_STAT(ni, tx_data); if (WME_UAPSD_AC_CAN_TRIGGER(skb->priority, ni)) { /* U-APSD power save queue */ /* XXXAPSD: assuming triggerable means deliverable */ M_FLAG_SET(skb, M_UAPSD); } (void) ic->ic_mgtstart(ic, skb); /* cheat */ return 0;}EXPORT_SYMBOL(ieee80211_send_qosnulldata);/* * Ensure there is sufficient headroom and tailroom to * encapsulate the 802.11 data frame. If room isn't * already there, reallocate so there is enough space. * Drivers and cipher modules assume we have done the * necessary work and fail rudely if they don't find * the space they need. */static struct sk_buff *ieee80211_skbhdr_adjust(struct ieee80211vap *vap, int hdrsize, struct ieee80211_key *key, struct sk_buff *skb, int ismulticast){ /* XXX pre-calculate per node? */ int need_headroom = LLC_SNAPFRAMELEN + hdrsize + IEEE80211_ADDR_LEN; int need_tailroom = 0;#ifdef ATH_SUPERG_FF int isff = ATH_FF_MAGIC_PRESENT(skb); int inter_headroom = sizeof(struct ether_header) + LLC_SNAPFRAMELEN + ATH_FF_MAX_HDR_PAD; struct sk_buff *skb2 = NULL; if (isff) { need_headroom += sizeof(struct athl2p_tunnel_hdr) + ATH_FF_MAX_HDR_PAD + inter_headroom; skb2 = skb->next; }#endif if (key != NULL) { const struct ieee80211_cipher *cip = key->wk_cipher; /* * Adjust for crypto needs. When hardware crypto is * being used we assume the hardware/driver will deal * with any padding (on the fly, without needing to * expand the frame contents). When software crypto * is used we need to ensure room is available at the * front and back and also for any per-MSDU additions. */ /* XXX belongs in crypto code? */ need_headroom += cip->ic_header; /* XXX pre-calculate per key */ if (key->wk_flags & IEEE80211_KEY_SWCRYPT) need_tailroom += cip->ic_trailer; /* ** If tx frag is needed and cipher is TKIP, ** then allocate the additional tailroom for SW MIC computation. */ if (skb->len > vap->iv_fragthreshold && !ismulticast && cip->ic_cipher == IEEE80211_CIPHER_TKIP) need_tailroom += cip->ic_miclen; else if (key->wk_flags & IEEE80211_KEY_SWMIC) need_tailroom += cip->ic_miclen; } if (skb_shared(skb)) { /* Take our own reference to the node in the clone */ ieee80211_ref_node(SKB_NI(skb)); /* Unshare the node, decrementing users in the old skb */ skb = skb_unshare(skb, GFP_ATOMIC); }#ifdef ATH_SUPERG_FF if (isff) { if (skb == NULL) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, "%s: cannot unshare for encapsulation\n", __func__); vap->iv_stats.is_tx_nobuf++; ieee80211_dev_kfree_skb(&skb2); return NULL; } /* first skb header */ if (skb_headroom(skb) < need_headroom) { struct sk_buff *tmp = skb; skb = skb_realloc_headroom(skb, need_headroom); if (skb == NULL) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, "%s: cannot expand storage (head1)\n", __func__); vap->iv_stats.is_tx_nobuf++; ieee80211_dev_kfree_skb(&skb2); return NULL; } else ieee80211_skb_copy_noderef(tmp, skb); ieee80211_dev_kfree_skb(&tmp); /* NB: cb[] area was copied, but not next ptr. must do that * prior to return on success. */ } /* second skb with header and tail adjustments possible */ if (skb_tailroom(skb2) < need_tailroom) { int n = 0; if (inter_headroom > skb_headroom(skb2)) n = inter_headroom - skb_headroom(skb2); if (pskb_expand_head(skb2, n, need_tailroom - skb_tailroom(skb2), GFP_ATOMIC)) { ieee80211_dev_kfree_skb(&skb2); IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, "%s: cannot expand storage (tail2)\n", __func__); vap->iv_stats.is_tx_nobuf++; /* this shouldn't happen, but don't send first ff either */ ieee80211_dev_kfree_skb(&skb); } } else if (skb_headroom(skb2) < inter_headroom) { struct sk_buff *tmp = skb2; skb2 = skb_realloc_headroom(skb2, inter_headroom); if (skb2 == NULL) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, "%s: cannot expand storage (head2)\n", __func__); vap->iv_stats.is_tx_nobuf++; /* this shouldn't happen, but don't send first ff either */ ieee80211_dev_kfree_skb(&skb); skb = NULL; } else ieee80211_skb_copy_noderef(tmp, skb); ieee80211_dev_kfree_skb(&tmp); } if (skb) { skb->next = skb2; } return skb; }#endif /* ATH_SUPERG_FF */ if (skb == NULL) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, "%s: cannot unshare for encapsulation\n", __func__); vap->iv_stats.is_tx_nobuf++; } else if (skb_tailroom(skb) < need_tailroom) { int n = 0; if (need_headroom > skb_headroom(skb)) n = need_headroom - skb_headroom(skb); if (pskb_expand_head(skb, n, need_tailroom - skb_tailroom(skb), GFP_ATOMIC)) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, "%s: cannot expand storage (tail)\n", __func__); vap->iv_stats.is_tx_nobuf++; ieee80211_dev_kfree_skb(&skb); } } else if (skb_headroom(skb) < need_headroom) { struct sk_buff *tmp = skb; skb = skb_realloc_headroom(skb, need_headroom); /* Increment reference count after copy */ if (skb == NULL) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, "%s: cannot expand storage (head)\n", __func__); vap->iv_stats.is_tx_nobuf++; } else ieee80211_skb_copy_noderef(tmp, skb); ieee80211_dev_kfree_skb(&tmp); } return skb;}#define KEY_UNDEFINED(k) ((k).wk_cipher == &ieee80211_cipher_none)/* * Return the transmit key to use in sending a unicast frame. * If a unicast key is set we use that. When no unicast key is set * we fall back to the default transmit key. */static __inline struct ieee80211_key *ieee80211_crypto_getucastkey(struct ieee80211vap *vap, struct ieee80211_node *ni){ if (KEY_UNDEFINED(ni->ni_ucastkey)) { if (vap->iv_def_txkey == IEEE80211_KEYIX_NONE || KEY_UNDEFINED(vap->iv_nw_keys[vap->iv_def_txkey])) return NULL; return &vap->iv_nw_keys[vap->iv_def_txkey]; } else return &ni->ni_ucastkey;}/* * Return the transmit key to use in sending a multicast frame. * Multicast traffic always uses the group key which is installed as * the default tx key. */static __inline struct ieee80211_key *ieee80211_crypto_getmcastkey(struct ieee80211vap *vap, struct ieee80211_node *ni){ if (vap->iv_def_txkey == IEEE80211_KEYIX_NONE || KEY_UNDEFINED(vap->iv_nw_keys[vap->iv_def_txkey])) return NULL; return &vap->iv_nw_keys[vap->iv_def_txkey];}/* * Encapsulate an outbound data frame. The mbuf chain is updated and * a reference to the destination node is returned. If an error is * encountered NULL is returned and the node reference will also be NULL. * * NB: The caller is responsible for freeing a returned node reference. * The convention is ic_bss is not reference counted; the caller must * maintain that. */struct sk_buff *ieee80211_encap(struct ieee80211_node *ni, struct sk_buff *skb, int *framecnt){#define WH4(wh) ((struct ieee80211_frame_addr4 *)wh) struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; struct ether_header eh; struct ieee80211_frame *wh, *twh; struct ieee80211_key *key; struct llc *llc; int hdrsize, datalen, addqos; int hdrsize_nopad; struct sk_buff *framelist = NULL; struct sk_buff *tskb; int fragcnt = 1; int pdusize = 0; int ismulticast = 0; int use4addr = 0;#ifdef ATH_SUPERG_FF struct sk_buff *skb2 = NULL; struct ether_header eh2; int isff = ATH_FF_MAGIC_PRESENT(skb); if (isff) {#if 0 IEEE80211_DPRINTF(vap, IEEE80211_MSG_SUPG, "%s: handling fast-frame skb (%p)\n", __func__, skb);#endif skb2 = skb->next; if (skb2 == NULL) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_SUPG, "%s: fast-frame error, only 1 skb\n", __func__); goto bad; } memcpy(&eh2, skb2->data, sizeof(struct ether_header)); skb_pull(skb2, sizeof(struct ether_header)); }#endif memcpy(&eh, skb->data, sizeof(struct ether_header)); skb_pull(skb, sizeof(struct ether_header)); /* * Ensure space for additional headers. First identify * transmit key to use in calculating any buffer adjustments * required. This is also used below to do privacy * encapsulation work. Then calculate the 802.11 header * size and any padding required by the driver. * * Note key may be NULL if we fall back to the default * transmit key and that is not set. In that case the * buffer may not be expanded as needed by the cipher * routines, but they will/should discard it. */ if (vap->iv_flags & IEEE80211_F_PRIVACY) { if (vap->iv_opmode == IEEE80211_M_STA || !IEEE80211_IS_MULTICAST(eh.ether_dhost)) key = ieee80211_crypto_getucastkey(vap, ni); else key = ieee80211_crypto_getmcastkey(vap, ni); if ((key == NULL) && (eh.ether_type != htons(ETHERTYPE_PAE))) { IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, eh.ether_dhost, "no default transmit key (%s) deftxkey %u", __func__, vap->iv_def_txkey); vap->iv_stats.is_tx_nodefkey++; goto bad; } } else key = NULL; addqos = (ni->ni_flags & IEEE80211_NODE_QOS) && (eh.ether_type != htons(ETHERTYPE_PAE)); if (addqos) hdrsize = sizeof(struct ieee80211_qosframe); else hdrsize = sizeof(struct ieee80211_frame); switch (vap->iv_opmode) { case IEEE80211_M_IBSS: case IEEE80211_M_AHDEMO: ismulticast = IEEE80211_IS_MULTICAST(eh.ether_dhost); break; case IEEE80211_M_WDS: use4addr = 1; ismulticast = IEEE80211_IS_MULTICAST(ni->ni_macaddr); break; case IEEE80211_M_HOSTAP: if (!IEEE80211_IS_MULTICAST(eh.ether_dhost) && !IEEE80211_ADDR_EQ(eh.ether_dhost, ni->ni_macaddr)) { use4addr = 1; ismulticast = IEEE80211_IS_MULTICAST(ni->ni_macaddr); } else ismulticast = IEEE80211_IS_MULTICAST(eh.ether_dhost); break; case IEEE80211_M_STA: if ((vap->iv_flags_ext & IEEE80211_FEXT_WDS) && !IEEE80211_ADDR_EQ(eh.ether_shost, vap->iv_myaddr)) { use4addr = 1; ismulticast = IEEE80211_IS_MULTICAST(ni->ni_macaddr); /* Add a WDS entry to the station VAP */ if (IEEE80211_IS_MULTICAST(eh.ether_dhost)) { struct ieee80211_node_table *nt = &ic->ic_sta; struct ieee80211_node *ni_wds = ieee80211_find_wds_node(nt, eh.ether_shost); if (ni_wds) ieee80211_unref_node(&ni_wds); else ieee80211_add_wds_addr(nt, ni, eh.ether_shost, 0); } } else ismulticast = IEEE80211_IS_MULTICAST(vap->iv_bssid); break; default: break; } if (use4addr) hdrsize += IEEE80211_ADDR_LEN; hdrsize_nopad = hdrsize; if (ic->ic_flags & IEEE80211_F_DATAPAD) hdrsize = roundup(hdrsize, sizeof(u_int32_t)); skb = ieee80211_skbhdr_adjust(vap, hdrsize, key, skb, ismulticast); if (skb == NULL) { /* NB: ieee80211_skbhdr_adjust handles msgs+statistics */ goto bad; }#ifdef ATH_SUPERG_FF if (isff) { struct ether_header *eh_inter; struct athl2p_tunnel_hdr *ffhdr; u_int16_t payload = skb->len + LLC_SNAPFRAMELEN; int padded_len = payload + LLC_SNAPFRAMELEN + sizeof(struct ether_header); /* in case header adjustments altered skb2 */ skb2 = skb->next; if (skb2 == NULL) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_SUPG, "%s: skb (%p) hdr adjust dropped 2nd skb\n", __func__, skb); goto bad; } /* * add first skb tunnel hdrs */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -