diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/rx.c | 195 |
1 files changed, 133 insertions, 62 deletions
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 474f13662c84..1159a43a3df6 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -77,6 +77,134 @@ static inline int should_drop_frame(struct ieee80211_rx_status *status, | |||
77 | return 0; | 77 | return 0; |
78 | } | 78 | } |
79 | 79 | ||
80 | static int | ||
81 | ieee80211_rx_radiotap_len(struct ieee80211_local *local, | ||
82 | struct ieee80211_rx_status *status) | ||
83 | { | ||
84 | int len; | ||
85 | |||
86 | /* always present fields */ | ||
87 | len = sizeof(struct ieee80211_radiotap_header) + 9; | ||
88 | |||
89 | if (status->flag & RX_FLAG_TSFT) | ||
90 | len += 8; | ||
91 | if (local->hw.flags & IEEE80211_HW_SIGNAL_DB || | ||
92 | local->hw.flags & IEEE80211_HW_SIGNAL_DBM) | ||
93 | len += 1; | ||
94 | if (local->hw.flags & IEEE80211_HW_NOISE_DBM) | ||
95 | len += 1; | ||
96 | |||
97 | if (len & 1) /* padding for RX_FLAGS if necessary */ | ||
98 | len++; | ||
99 | |||
100 | /* make sure radiotap starts at a naturally aligned address */ | ||
101 | if (len % 8) | ||
102 | len = roundup(len, 8); | ||
103 | |||
104 | return len; | ||
105 | } | ||
106 | |||
107 | /** | ||
108 | * ieee80211_add_rx_radiotap_header - add radiotap header | ||
109 | * | ||
110 | * add a radiotap header containing all the fields which the hardware provided. | ||
111 | */ | ||
112 | static void | ||
113 | ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | ||
114 | struct sk_buff *skb, | ||
115 | struct ieee80211_rx_status *status, | ||
116 | struct ieee80211_rate *rate, | ||
117 | int rtap_len) | ||
118 | { | ||
119 | struct ieee80211_radiotap_header *rthdr; | ||
120 | unsigned char *pos; | ||
121 | |||
122 | rthdr = (struct ieee80211_radiotap_header *)skb_push(skb, rtap_len); | ||
123 | memset(rthdr, 0, rtap_len); | ||
124 | |||
125 | /* radiotap header, set always present flags */ | ||
126 | rthdr->it_present = | ||
127 | cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) | | ||
128 | (1 << IEEE80211_RADIOTAP_RATE) | | ||
129 | (1 << IEEE80211_RADIOTAP_CHANNEL) | | ||
130 | (1 << IEEE80211_RADIOTAP_ANTENNA) | | ||
131 | (1 << IEEE80211_RADIOTAP_RX_FLAGS)); | ||
132 | rthdr->it_len = cpu_to_le16(rtap_len); | ||
133 | |||
134 | pos = (unsigned char *)(rthdr+1); | ||
135 | |||
136 | /* the order of the following fields is important */ | ||
137 | |||
138 | /* IEEE80211_RADIOTAP_TSFT */ | ||
139 | if (status->flag & RX_FLAG_TSFT) { | ||
140 | *(__le64 *)pos = cpu_to_le64(status->mactime); | ||
141 | rthdr->it_present |= | ||
142 | cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT); | ||
143 | pos += 8; | ||
144 | } | ||
145 | |||
146 | /* IEEE80211_RADIOTAP_FLAGS */ | ||
147 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) | ||
148 | *pos |= IEEE80211_RADIOTAP_F_FCS; | ||
149 | pos++; | ||
150 | |||
151 | /* IEEE80211_RADIOTAP_RATE */ | ||
152 | *pos = rate->bitrate / 5; | ||
153 | pos++; | ||
154 | |||
155 | /* IEEE80211_RADIOTAP_CHANNEL */ | ||
156 | *(__le16 *)pos = cpu_to_le16(status->freq); | ||
157 | pos += 2; | ||
158 | if (status->band == IEEE80211_BAND_5GHZ) | ||
159 | *(__le16 *)pos = cpu_to_le16(IEEE80211_CHAN_OFDM | | ||
160 | IEEE80211_CHAN_5GHZ); | ||
161 | else | ||
162 | *(__le16 *)pos = cpu_to_le16(IEEE80211_CHAN_DYN | | ||
163 | IEEE80211_CHAN_2GHZ); | ||
164 | pos += 2; | ||
165 | |||
166 | /* IEEE80211_RADIOTAP_DBM_ANTSIGNAL */ | ||
167 | if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) { | ||
168 | *pos = status->signal; | ||
169 | rthdr->it_present |= | ||
170 | cpu_to_le32(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL); | ||
171 | pos++; | ||
172 | } | ||
173 | |||
174 | /* IEEE80211_RADIOTAP_DBM_ANTNOISE */ | ||
175 | if (local->hw.flags & IEEE80211_HW_NOISE_DBM) { | ||
176 | *pos = status->noise; | ||
177 | rthdr->it_present |= | ||
178 | cpu_to_le32(1 << IEEE80211_RADIOTAP_DBM_ANTNOISE); | ||
179 | pos++; | ||
180 | } | ||
181 | |||
182 | /* IEEE80211_RADIOTAP_LOCK_QUALITY is missing */ | ||
183 | |||
184 | /* IEEE80211_RADIOTAP_ANTENNA */ | ||
185 | *pos = status->antenna; | ||
186 | pos++; | ||
187 | |||
188 | /* IEEE80211_RADIOTAP_DB_ANTSIGNAL */ | ||
189 | if (local->hw.flags & IEEE80211_HW_SIGNAL_DB) { | ||
190 | *pos = status->signal; | ||
191 | rthdr->it_present |= | ||
192 | cpu_to_le32(1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL); | ||
193 | pos++; | ||
194 | } | ||
195 | |||
196 | /* IEEE80211_RADIOTAP_DB_ANTNOISE is not used */ | ||
197 | |||
198 | /* IEEE80211_RADIOTAP_RX_FLAGS */ | ||
199 | /* ensure 2 byte alignment for the 2 byte field as required */ | ||
200 | if ((pos - (unsigned char *)rthdr) & 1) | ||
201 | pos++; | ||
202 | /* FIXME: when radiotap gets a 'bad PLCP' flag use it here */ | ||
203 | if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC)) | ||
204 | *(__le16 *)pos |= cpu_to_le16(IEEE80211_RADIOTAP_F_RX_BADFCS); | ||
205 | pos += 2; | ||
206 | } | ||
207 | |||
80 | /* | 208 | /* |
81 | * This function copies a received frame to all monitor interfaces and | 209 | * This function copies a received frame to all monitor interfaces and |
82 | * returns a cleaned-up SKB that no longer includes the FCS nor the | 210 | * returns a cleaned-up SKB that no longer includes the FCS nor the |
@@ -89,17 +217,6 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, | |||
89 | { | 217 | { |
90 | struct ieee80211_sub_if_data *sdata; | 218 | struct ieee80211_sub_if_data *sdata; |
91 | int needed_headroom = 0; | 219 | int needed_headroom = 0; |
92 | struct ieee80211_radiotap_header *rthdr; | ||
93 | __le64 *rttsft = NULL; | ||
94 | struct ieee80211_rtap_fixed_data { | ||
95 | u8 flags; | ||
96 | u8 rate; | ||
97 | __le16 chan_freq; | ||
98 | __le16 chan_flags; | ||
99 | u8 antsignal; | ||
100 | u8 padding_for_rxflags; | ||
101 | __le16 rx_flags; | ||
102 | } __attribute__ ((packed)) *rtfixed; | ||
103 | struct sk_buff *skb, *skb2; | 220 | struct sk_buff *skb, *skb2; |
104 | struct net_device *prev_dev = NULL; | 221 | struct net_device *prev_dev = NULL; |
105 | int present_fcs_len = 0; | 222 | int present_fcs_len = 0; |
@@ -116,8 +233,8 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, | |||
116 | if (status->flag & RX_FLAG_RADIOTAP) | 233 | if (status->flag & RX_FLAG_RADIOTAP) |
117 | rtap_len = ieee80211_get_radiotap_len(origskb->data); | 234 | rtap_len = ieee80211_get_radiotap_len(origskb->data); |
118 | else | 235 | else |
119 | /* room for radiotap header, always present fields and TSFT */ | 236 | /* room for the radiotap header based on driver features */ |
120 | needed_headroom = sizeof(*rthdr) + sizeof(*rtfixed) + 8; | 237 | needed_headroom = ieee80211_rx_radiotap_len(local, status); |
121 | 238 | ||
122 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) | 239 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) |
123 | present_fcs_len = FCS_LEN; | 240 | present_fcs_len = FCS_LEN; |
@@ -163,55 +280,9 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, | |||
163 | } | 280 | } |
164 | 281 | ||
165 | /* if necessary, prepend radiotap information */ | 282 | /* if necessary, prepend radiotap information */ |
166 | if (!(status->flag & RX_FLAG_RADIOTAP)) { | 283 | if (!(status->flag & RX_FLAG_RADIOTAP)) |
167 | rtfixed = (void *) skb_push(skb, sizeof(*rtfixed)); | 284 | ieee80211_add_rx_radiotap_header(local, skb, status, rate, |
168 | rtap_len = sizeof(*rthdr) + sizeof(*rtfixed); | 285 | needed_headroom); |
169 | if (status->flag & RX_FLAG_TSFT) { | ||
170 | rttsft = (void *) skb_push(skb, sizeof(*rttsft)); | ||
171 | rtap_len += 8; | ||
172 | } | ||
173 | rthdr = (void *) skb_push(skb, sizeof(*rthdr)); | ||
174 | memset(rthdr, 0, sizeof(*rthdr)); | ||
175 | memset(rtfixed, 0, sizeof(*rtfixed)); | ||
176 | rthdr->it_present = | ||
177 | cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) | | ||
178 | (1 << IEEE80211_RADIOTAP_RATE) | | ||
179 | (1 << IEEE80211_RADIOTAP_CHANNEL) | | ||
180 | (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) | | ||
181 | (1 << IEEE80211_RADIOTAP_RX_FLAGS)); | ||
182 | rtfixed->flags = 0; | ||
183 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) | ||
184 | rtfixed->flags |= IEEE80211_RADIOTAP_F_FCS; | ||
185 | |||
186 | if (rttsft) { | ||
187 | *rttsft = cpu_to_le64(status->mactime); | ||
188 | rthdr->it_present |= | ||
189 | cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT); | ||
190 | } | ||
191 | |||
192 | /* FIXME: when radiotap gets a 'bad PLCP' flag use it here */ | ||
193 | rtfixed->rx_flags = 0; | ||
194 | if (status->flag & | ||
195 | (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC)) | ||
196 | rtfixed->rx_flags |= | ||
197 | cpu_to_le16(IEEE80211_RADIOTAP_F_RX_BADFCS); | ||
198 | |||
199 | rtfixed->rate = rate->bitrate / 5; | ||
200 | |||
201 | rtfixed->chan_freq = cpu_to_le16(status->freq); | ||
202 | |||
203 | if (status->band == IEEE80211_BAND_5GHZ) | ||
204 | rtfixed->chan_flags = | ||
205 | cpu_to_le16(IEEE80211_CHAN_OFDM | | ||
206 | IEEE80211_CHAN_5GHZ); | ||
207 | else | ||
208 | rtfixed->chan_flags = | ||
209 | cpu_to_le16(IEEE80211_CHAN_DYN | | ||
210 | IEEE80211_CHAN_2GHZ); | ||
211 | |||
212 | rtfixed->antsignal = status->signal; | ||
213 | rthdr->it_len = cpu_to_le16(rtap_len); | ||
214 | } | ||
215 | 286 | ||
216 | skb_reset_mac_header(skb); | 287 | skb_reset_mac_header(skb); |
217 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 288 | skb->ip_summed = CHECKSUM_UNNECESSARY; |