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; |
