aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKalle Valo <kalle.valo@nokia.com>2010-01-05 13:16:19 -0500
committerJohn W. Linville <linville@tuxdriver.com>2010-01-12 13:51:24 -0500
commit7044cc565b45a898c140fb185174a66f2d68a163 (patch)
tree9933e1f178d0cfc8acf69eaf5b7652acaa8825e5
parentb3579d6adcf7b24464274967a96d12467cfb11a7 (diff)
mac80211: add functions to create PS Poll and Nullfunc templates
Some hardware, for example wl1251 and wl1271, handle the transmission of power save related frames in hardware, but the driver is responsible for creating the templates. It's better to create the templates in mac80211, that way all drivers can benefit from this. Add two new functions, ieee80211_pspoll_get() and ieee80211_nullfunc_get() which drivers need to call to get the frame. Drivers are also responsible for updating the templates after each association. Also new struct ieee80211_hdr_3addr is added to ieee80211.h to make it easy to calculate length of the Nullfunc frame. Signed-off-by: Kalle Valo <kalle.valo@nokia.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--include/linux/ieee80211.h9
-rw-r--r--include/net/mac80211.h30
-rw-r--r--net/mac80211/tx.c78
3 files changed, 117 insertions, 0 deletions
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index aeea282bd2fe..602c0692c3fc 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -130,6 +130,15 @@ struct ieee80211_hdr {
130 u8 addr4[6]; 130 u8 addr4[6];
131} __attribute__ ((packed)); 131} __attribute__ ((packed));
132 132
133struct ieee80211_hdr_3addr {
134 __le16 frame_control;
135 __le16 duration_id;
136 u8 addr1[6];
137 u8 addr2[6];
138 u8 addr3[6];
139 __le16 seq_ctrl;
140} __attribute__ ((packed));
141
133/** 142/**
134 * ieee80211_has_tods - check if IEEE80211_FCTL_TODS is set 143 * ieee80211_has_tods - check if IEEE80211_FCTL_TODS is set
135 * @fc: frame control bytes in little-endian byteorder 144 * @fc: frame control bytes in little-endian byteorder
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 7e5af6d90b93..75f46e26ad60 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1875,6 +1875,36 @@ static inline struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
1875} 1875}
1876 1876
1877/** 1877/**
1878 * ieee80211_pspoll_get - retrieve a PS Poll template
1879 * @hw: pointer obtained from ieee80211_alloc_hw().
1880 * @vif: &struct ieee80211_vif pointer from the add_interface callback.
1881 *
1882 * Creates a PS Poll a template which can, for example, uploaded to
1883 * hardware. The template must be updated after association so that correct
1884 * AID, BSSID and MAC address is used.
1885 *
1886 * Note: Caller (or hardware) is responsible for setting the
1887 * &IEEE80211_FCTL_PM bit.
1888 */
1889struct sk_buff *ieee80211_pspoll_get(struct ieee80211_hw *hw,
1890 struct ieee80211_vif *vif);
1891
1892/**
1893 * ieee80211_nullfunc_get - retrieve a nullfunc template
1894 * @hw: pointer obtained from ieee80211_alloc_hw().
1895 * @vif: &struct ieee80211_vif pointer from the add_interface callback.
1896 *
1897 * Creates a Nullfunc template which can, for example, uploaded to
1898 * hardware. The template must be updated after association so that correct
1899 * BSSID and address is used.
1900 *
1901 * Note: Caller (or hardware) is responsible for setting the
1902 * &IEEE80211_FCTL_PM bit as well as Duration and Sequence Control fields.
1903 */
1904struct sk_buff *ieee80211_nullfunc_get(struct ieee80211_hw *hw,
1905 struct ieee80211_vif *vif);
1906
1907/**
1878 * ieee80211_rts_get - RTS frame generation function 1908 * ieee80211_rts_get - RTS frame generation function
1879 * @hw: pointer obtained from ieee80211_alloc_hw(). 1909 * @hw: pointer obtained from ieee80211_alloc_hw().
1880 * @vif: &struct ieee80211_vif pointer from the add_interface callback. 1910 * @vif: &struct ieee80211_vif pointer from the add_interface callback.
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index d3a44812f8bf..055b45b146d9 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -2200,6 +2200,84 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
2200} 2200}
2201EXPORT_SYMBOL(ieee80211_beacon_get_tim); 2201EXPORT_SYMBOL(ieee80211_beacon_get_tim);
2202 2202
2203struct sk_buff *ieee80211_pspoll_get(struct ieee80211_hw *hw,
2204 struct ieee80211_vif *vif)
2205{
2206 struct ieee80211_sub_if_data *sdata;
2207 struct ieee80211_if_managed *ifmgd;
2208 struct ieee80211_pspoll *pspoll;
2209 struct ieee80211_local *local;
2210 struct sk_buff *skb;
2211
2212 if (WARN_ON(vif->type != NL80211_IFTYPE_STATION))
2213 return NULL;
2214
2215 sdata = vif_to_sdata(vif);
2216 ifmgd = &sdata->u.mgd;
2217 local = sdata->local;
2218
2219 skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*pspoll));
2220 if (!skb) {
2221 printk(KERN_DEBUG "%s: failed to allocate buffer for "
2222 "pspoll template\n", sdata->name);
2223 return NULL;
2224 }
2225 skb_reserve(skb, local->hw.extra_tx_headroom);
2226
2227 pspoll = (struct ieee80211_pspoll *) skb_put(skb, sizeof(*pspoll));
2228 memset(pspoll, 0, sizeof(*pspoll));
2229 pspoll->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL |
2230 IEEE80211_STYPE_PSPOLL);
2231 pspoll->aid = cpu_to_le16(ifmgd->aid);
2232
2233 /* aid in PS-Poll has its two MSBs each set to 1 */
2234 pspoll->aid |= cpu_to_le16(1 << 15 | 1 << 14);
2235
2236 memcpy(pspoll->bssid, ifmgd->bssid, ETH_ALEN);
2237 memcpy(pspoll->ta, vif->addr, ETH_ALEN);
2238
2239 return skb;
2240}
2241EXPORT_SYMBOL(ieee80211_pspoll_get);
2242
2243struct sk_buff *ieee80211_nullfunc_get(struct ieee80211_hw *hw,
2244 struct ieee80211_vif *vif)
2245{
2246 struct ieee80211_hdr_3addr *nullfunc;
2247 struct ieee80211_sub_if_data *sdata;
2248 struct ieee80211_if_managed *ifmgd;
2249 struct ieee80211_local *local;
2250 struct sk_buff *skb;
2251
2252 if (WARN_ON(vif->type != NL80211_IFTYPE_STATION))
2253 return NULL;
2254
2255 sdata = vif_to_sdata(vif);
2256 ifmgd = &sdata->u.mgd;
2257 local = sdata->local;
2258
2259 skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*nullfunc));
2260 if (!skb) {
2261 printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc "
2262 "template\n", sdata->name);
2263 return NULL;
2264 }
2265 skb_reserve(skb, local->hw.extra_tx_headroom);
2266
2267 nullfunc = (struct ieee80211_hdr_3addr *) skb_put(skb,
2268 sizeof(*nullfunc));
2269 memset(nullfunc, 0, sizeof(*nullfunc));
2270 nullfunc->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
2271 IEEE80211_STYPE_NULLFUNC |
2272 IEEE80211_FCTL_TODS);
2273 memcpy(nullfunc->addr1, ifmgd->bssid, ETH_ALEN);
2274 memcpy(nullfunc->addr2, vif->addr, ETH_ALEN);
2275 memcpy(nullfunc->addr3, ifmgd->bssid, ETH_ALEN);
2276
2277 return skb;
2278}
2279EXPORT_SYMBOL(ieee80211_nullfunc_get);
2280
2203void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 2281void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
2204 const void *frame, size_t frame_len, 2282 const void *frame, size_t frame_len,
2205 const struct ieee80211_tx_info *frame_txctl, 2283 const struct ieee80211_tx_info *frame_txctl,