/* iwl_mvm_create_skb Adds the rxb to a new skb */ static void iwl_mvm_create_skb(struct sk_buff *skb, struct ieee80211_hdr *hdr, u16 len, u8 crypt_len, struct iwl_rx_cmd_buffer *rxb) { unsigned int hdrlen, fraglen; /* If frame is small enough to fit in skb->head, pull it completely. * If not, only pull ieee80211_hdr (including crypto if present, and * an additional 8 bytes for SNAP/ethertype, see below) so that * splice() or TCP coalesce are more efficient. * * Since, in addition, ieee80211_data_to_8023() always pull in at * least 8 bytes (possibly more for mesh) we can do the same here * to save the cost of doing it later. That still doesn't pull in * the actual IP header since the typical case has a SNAP header. * If the latter changes (there are efforts in the standards group * to do so) we should revisit this and ieee80211_data_to_8023(). */ hdrlen = (len <= skb_tailroom(skb)) ? len : sizeof(*hdr) + crypt_len + 8; memcpy(skb_put(skb, hdrlen), hdr, hdrlen); fraglen = len - hdrlen; if (fraglen) { int offset = (void *)hdr + hdrlen - rxb_addr(rxb) + rxb_offset(rxb); skb_add_rx_frag(skb, 0, rxb_steal_page(rxb), offset, fraglen, rxb->truesize); } }
/* * iwl_mvm_pass_packet_to_mac80211 - builds the packet for mac80211 * * Adds the rxb to a new skb and give it to mac80211 */ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm, struct ieee80211_sta *sta, struct napi_struct *napi, struct sk_buff *skb, struct ieee80211_hdr *hdr, u16 len, u8 crypt_len, struct iwl_rx_cmd_buffer *rxb) { unsigned int hdrlen = ieee80211_hdrlen(hdr->frame_control); unsigned int fraglen; /* * The 'hdrlen' (plus the 8 bytes for the SNAP and the crypt_len, * but those are all multiples of 4 long) all goes away, but we * want the *end* of it, which is going to be the start of the IP * header, to be aligned when it gets pulled in. * The beginning of the skb->data is aligned on at least a 4-byte * boundary after allocation. Everything here is aligned at least * on a 2-byte boundary so we can just take hdrlen & 3 and pad by * the result. */ skb_reserve(skb, hdrlen & 3); /* If frame is small enough to fit in skb->head, pull it completely. * If not, only pull ieee80211_hdr (including crypto if present, and * an additional 8 bytes for SNAP/ethertype, see below) so that * splice() or TCP coalesce are more efficient. * * Since, in addition, ieee80211_data_to_8023() always pull in at * least 8 bytes (possibly more for mesh) we can do the same here * to save the cost of doing it later. That still doesn't pull in * the actual IP header since the typical case has a SNAP header. * If the latter changes (there are efforts in the standards group * to do so) we should revisit this and ieee80211_data_to_8023(). */ hdrlen = (len <= skb_tailroom(skb)) ? len : hdrlen + crypt_len + 8; skb_put_data(skb, hdr, hdrlen); fraglen = len - hdrlen; if (fraglen) { int offset = (void *)hdr + hdrlen - rxb_addr(rxb) + rxb_offset(rxb); skb_add_rx_frag(skb, 0, rxb_steal_page(rxb), offset, fraglen, rxb->truesize); } ieee80211_rx_napi(mvm->hw, sta, skb, napi); }
/* iwl_mvm_create_skb Adds the rxb to a new skb */ static void iwl_mvm_create_skb(struct sk_buff *skb, struct ieee80211_hdr *hdr, u16 len, u8 crypt_len, struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_rx_mpdu_desc *desc = (void *)pkt->data; unsigned int headlen, fraglen, pad_len = 0; unsigned int hdrlen = ieee80211_hdrlen(hdr->frame_control); if (desc->mac_flags2 & IWL_RX_MPDU_MFLG2_PAD) pad_len = 2; len -= pad_len; /* If frame is small enough to fit in skb->head, pull it completely. * If not, only pull ieee80211_hdr (including crypto if present, and * an additional 8 bytes for SNAP/ethertype, see below) so that * splice() or TCP coalesce are more efficient. * * Since, in addition, ieee80211_data_to_8023() always pull in at * least 8 bytes (possibly more for mesh) we can do the same here * to save the cost of doing it later. That still doesn't pull in * the actual IP header since the typical case has a SNAP header. * If the latter changes (there are efforts in the standards group * to do so) we should revisit this and ieee80211_data_to_8023(). */ headlen = (len <= skb_tailroom(skb)) ? len : hdrlen + crypt_len + 8; /* The firmware may align the packet to DWORD. * The padding is inserted after the IV. * After copying the header + IV skip the padding if * present before copying packet data. */ hdrlen += crypt_len; memcpy(skb_put(skb, hdrlen), hdr, hdrlen); memcpy(skb_put(skb, headlen - hdrlen), (u8 *)hdr + hdrlen + pad_len, headlen - hdrlen); fraglen = len - headlen; if (fraglen) { int offset = (void *)hdr + headlen + pad_len - rxb_addr(rxb) + rxb_offset(rxb); skb_add_rx_frag(skb, 0, rxb_steal_page(rxb), offset, fraglen, rxb->truesize); } }
/* * iwl_mvm_pass_packet_to_mac80211 - builds the packet for mac80211 * * Adds the rxb to a new skb and give it to mac80211 */ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr, u16 len, u32 ampdu_status, struct iwl_rx_cmd_buffer *rxb, struct ieee80211_rx_status *stats) { struct sk_buff *skb; unsigned int hdrlen, fraglen; /* Dont use dev_alloc_skb(), we'll have enough headroom once * ieee80211_hdr pulled. */ skb = alloc_skb(128, GFP_ATOMIC); if (!skb) { IWL_ERR(mvm, "alloc_skb failed\n"); return; } /* If frame is small enough to fit in skb->head, pull it completely. * If not, only pull ieee80211_hdr so that splice() or TCP coalesce * are more efficient. */ hdrlen = (len <= skb_tailroom(skb)) ? len : sizeof(*hdr); memcpy(skb_put(skb, hdrlen), hdr, hdrlen); fraglen = len - hdrlen; if (fraglen) { int offset = (void *)hdr + hdrlen - rxb_addr(rxb) + rxb_offset(rxb); skb_add_rx_frag(skb, 0, rxb_steal_page(rxb), offset, fraglen, rxb->truesize); } memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); ieee80211_rx_ni(mvm->hw, skb); }