diff options
-rw-r--r-- | drivers/net/wireless/mwifiex/11n_aggr.c | 125 | ||||
-rw-r--r-- | drivers/net/wireless/mwifiex/sta_rx.c | 22 |
2 files changed, 20 insertions, 127 deletions
diff --git a/drivers/net/wireless/mwifiex/11n_aggr.c b/drivers/net/wireless/mwifiex/11n_aggr.c index 2b2cca5e6d0f..d3d5e0853c45 100644 --- a/drivers/net/wireless/mwifiex/11n_aggr.c +++ b/drivers/net/wireless/mwifiex/11n_aggr.c | |||
@@ -136,131 +136,6 @@ mwifiex_11n_form_amsdu_txpd(struct mwifiex_private *priv, | |||
136 | } | 136 | } |
137 | 137 | ||
138 | /* | 138 | /* |
139 | * Counts the number of subframes in an aggregate packet. | ||
140 | * | ||
141 | * This function parses an aggregate packet buffer, looking for | ||
142 | * subframes and counting the number of such subframe found. The | ||
143 | * function automatically skips the DA/SA fields at the beginning | ||
144 | * of each subframe and padding at the end. | ||
145 | */ | ||
146 | static int | ||
147 | mwifiex_11n_get_num_aggr_pkts(u8 *data, int total_pkt_len) | ||
148 | { | ||
149 | int pkt_count = 0, pkt_len, pad; | ||
150 | |||
151 | while (total_pkt_len > 0) { | ||
152 | /* Length will be in network format, change it to host */ | ||
153 | pkt_len = ntohs((*(__be16 *)(data + 2 * ETH_ALEN))); | ||
154 | pad = (((pkt_len + sizeof(struct ethhdr)) & 3)) ? | ||
155 | (4 - ((pkt_len + sizeof(struct ethhdr)) & 3)) : 0; | ||
156 | data += pkt_len + pad + sizeof(struct ethhdr); | ||
157 | total_pkt_len -= pkt_len + pad + sizeof(struct ethhdr); | ||
158 | ++pkt_count; | ||
159 | } | ||
160 | |||
161 | return pkt_count; | ||
162 | } | ||
163 | |||
164 | /* | ||
165 | * De-aggregate received packets. | ||
166 | * | ||
167 | * This function parses the received aggregate buffer, extracts each subframe, | ||
168 | * strips off the SNAP header from them and sends the data portion for further | ||
169 | * processing. | ||
170 | * | ||
171 | * Each subframe body is copied onto a separate buffer, which are freed by | ||
172 | * upper layer after processing. The function also performs sanity tests on | ||
173 | * the received buffer. | ||
174 | */ | ||
175 | int mwifiex_11n_deaggregate_pkt(struct mwifiex_private *priv, | ||
176 | struct sk_buff *skb) | ||
177 | { | ||
178 | u16 pkt_len; | ||
179 | int total_pkt_len; | ||
180 | u8 *data; | ||
181 | int pad; | ||
182 | struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); | ||
183 | struct rxpd *local_rx_pd = (struct rxpd *) skb->data; | ||
184 | struct sk_buff *skb_daggr; | ||
185 | struct mwifiex_rxinfo *rx_info_daggr; | ||
186 | int ret = -1; | ||
187 | struct rx_packet_hdr *rx_pkt_hdr; | ||
188 | struct mwifiex_adapter *adapter = priv->adapter; | ||
189 | u8 rfc1042_eth_hdr[ETH_ALEN] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; | ||
190 | |||
191 | data = (u8 *) (local_rx_pd + local_rx_pd->rx_pkt_offset); | ||
192 | total_pkt_len = local_rx_pd->rx_pkt_length; | ||
193 | |||
194 | /* Sanity test */ | ||
195 | if (total_pkt_len > MWIFIEX_RX_DATA_BUF_SIZE) { | ||
196 | dev_err(adapter->dev, "total pkt len greater than buffer" | ||
197 | " size %d\n", total_pkt_len); | ||
198 | return -1; | ||
199 | } | ||
200 | |||
201 | rx_info->use_count = mwifiex_11n_get_num_aggr_pkts(data, total_pkt_len); | ||
202 | |||
203 | while (total_pkt_len > 0) { | ||
204 | rx_pkt_hdr = (struct rx_packet_hdr *) data; | ||
205 | /* Length will be in network format, change it to host */ | ||
206 | pkt_len = ntohs((*(__be16 *) (data + 2 * ETH_ALEN))); | ||
207 | if (pkt_len > total_pkt_len) { | ||
208 | dev_err(adapter->dev, "pkt_len %d > total_pkt_len %d\n", | ||
209 | total_pkt_len, pkt_len); | ||
210 | break; | ||
211 | } | ||
212 | |||
213 | pad = (((pkt_len + sizeof(struct ethhdr)) & 3)) ? | ||
214 | (4 - ((pkt_len + sizeof(struct ethhdr)) & 3)) : 0; | ||
215 | |||
216 | total_pkt_len -= pkt_len + pad + sizeof(struct ethhdr); | ||
217 | |||
218 | if (memcmp(&rx_pkt_hdr->rfc1042_hdr, | ||
219 | rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr)) == 0) { | ||
220 | memmove(data + LLC_SNAP_LEN, data, 2 * ETH_ALEN); | ||
221 | data += LLC_SNAP_LEN; | ||
222 | pkt_len += sizeof(struct ethhdr) - LLC_SNAP_LEN; | ||
223 | } else { | ||
224 | *(u16 *) (data + 2 * ETH_ALEN) = (u16) 0; | ||
225 | pkt_len += sizeof(struct ethhdr); | ||
226 | } | ||
227 | |||
228 | skb_daggr = dev_alloc_skb(pkt_len); | ||
229 | if (!skb_daggr) { | ||
230 | dev_err(adapter->dev, "%s: failed to alloc skb_daggr\n", | ||
231 | __func__); | ||
232 | return -1; | ||
233 | } | ||
234 | rx_info_daggr = MWIFIEX_SKB_RXCB(skb_daggr); | ||
235 | |||
236 | rx_info_daggr->bss_index = rx_info->bss_index; | ||
237 | skb_daggr->tstamp = skb->tstamp; | ||
238 | rx_info_daggr->parent = skb; | ||
239 | skb_daggr->priority = skb->priority; | ||
240 | skb_put(skb_daggr, pkt_len); | ||
241 | memcpy(skb_daggr->data, data, pkt_len); | ||
242 | |||
243 | ret = mwifiex_recv_packet(adapter, skb_daggr); | ||
244 | |||
245 | switch (ret) { | ||
246 | case -EINPROGRESS: | ||
247 | break; | ||
248 | case -1: | ||
249 | dev_err(adapter->dev, "deaggr: host_to_card failed\n"); | ||
250 | case 0: | ||
251 | mwifiex_recv_packet_complete(adapter, skb_daggr, ret); | ||
252 | break; | ||
253 | default: | ||
254 | break; | ||
255 | } | ||
256 | |||
257 | data += pkt_len + pad; | ||
258 | } | ||
259 | |||
260 | return ret; | ||
261 | } | ||
262 | |||
263 | /* | ||
264 | * Create aggregated packet. | 139 | * Create aggregated packet. |
265 | * | 140 | * |
266 | * This function creates an aggregated MSDU packet, by combining buffers | 141 | * This function creates an aggregated MSDU packet, by combining buffers |
diff --git a/drivers/net/wireless/mwifiex/sta_rx.c b/drivers/net/wireless/mwifiex/sta_rx.c index e047f0d8a983..1fdddece7479 100644 --- a/drivers/net/wireless/mwifiex/sta_rx.c +++ b/drivers/net/wireless/mwifiex/sta_rx.c | |||
@@ -141,10 +141,28 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *adapter, | |||
141 | dev_kfree_skb_any(skb); | 141 | dev_kfree_skb_any(skb); |
142 | return ret; | 142 | return ret; |
143 | } | 143 | } |
144 | |||
144 | if (local_rx_pd->rx_pkt_type == PKT_TYPE_AMSDU) { | 145 | if (local_rx_pd->rx_pkt_type == PKT_TYPE_AMSDU) { |
145 | mwifiex_11n_deaggregate_pkt(priv, skb); | 146 | struct sk_buff_head list; |
146 | return ret; | 147 | struct sk_buff *rx_skb; |
148 | |||
149 | __skb_queue_head_init(&list); | ||
150 | |||
151 | skb_pull(skb, local_rx_pd->rx_pkt_offset); | ||
152 | skb_trim(skb, local_rx_pd->rx_pkt_length); | ||
153 | |||
154 | ieee80211_amsdu_to_8023s(skb, &list, priv->curr_addr, | ||
155 | priv->wdev->iftype, 0, false); | ||
156 | |||
157 | while (!skb_queue_empty(&list)) { | ||
158 | rx_skb = __skb_dequeue(&list); | ||
159 | ret = mwifiex_recv_packet(adapter, rx_skb); | ||
160 | if (ret == -1) | ||
161 | dev_err(adapter->dev, "Rx of A-MSDU failed"); | ||
162 | } | ||
163 | return 0; | ||
147 | } | 164 | } |
165 | |||
148 | /* | 166 | /* |
149 | * If the packet is not an unicast packet then send the packet | 167 | * If the packet is not an unicast packet then send the packet |
150 | * directly to os. Don't pass thru rx reordering | 168 | * directly to os. Don't pass thru rx reordering |