diff options
author | Luis Carlos Cobo <luisca@cozybit.com> | 2008-02-23 09:17:11 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-03-06 15:30:41 -0500 |
commit | ee3858551ae6d044578f598f8001db5f1a9fd52e (patch) | |
tree | 5a9b61aecccb65210e29850c34801f3cfe6259a9 /net/mac80211 | |
parent | 33b64eb2b1b1759cbdafbe5c59df652f1e7c746e (diff) |
mac80211: mesh data structures and first mesh changes
Includes integration in struct sta_info of mesh peer link elements, previously
on their own mesh peer link table.
Signed-off-by: Luis Carlos Cobo <luisca@cozybit.com>
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r-- | net/mac80211/cfg.c | 2 | ||||
-rw-r--r-- | net/mac80211/ieee80211.c | 2 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 170 | ||||
-rw-r--r-- | net/mac80211/ieee80211_iface.c | 62 | ||||
-rw-r--r-- | net/mac80211/ieee80211_ioctl.c | 1 | ||||
-rw-r--r-- | net/mac80211/ieee80211_sta.c | 70 | ||||
-rw-r--r-- | net/mac80211/rc80211_pid_algo.c | 14 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 42 | ||||
-rw-r--r-- | net/mac80211/sta_info.h | 30 | ||||
-rw-r--r-- | net/mac80211/util.c | 51 |
10 files changed, 394 insertions, 50 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 006da6a2e71..0e97ceee640 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -50,7 +50,7 @@ static int ieee80211_add_iface(struct wiphy *wiphy, char *name, | |||
50 | if (itype == IEEE80211_IF_TYPE_INVALID) | 50 | if (itype == IEEE80211_IF_TYPE_INVALID) |
51 | return -EINVAL; | 51 | return -EINVAL; |
52 | 52 | ||
53 | err = ieee80211_if_add(local->mdev, name, &dev, itype); | 53 | err = ieee80211_if_add(local->mdev, name, &dev, itype, params); |
54 | if (err || itype != IEEE80211_IF_TYPE_MNTR || !flags) | 54 | if (err || itype != IEEE80211_IF_TYPE_MNTR || !flags) |
55 | return err; | 55 | return err; |
56 | 56 | ||
diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 1ddb8e1b6ab..190917a74c3 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c | |||
@@ -1663,7 +1663,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
1663 | 1663 | ||
1664 | /* add one default STA interface */ | 1664 | /* add one default STA interface */ |
1665 | result = ieee80211_if_add(local->mdev, "wlan%d", NULL, | 1665 | result = ieee80211_if_add(local->mdev, "wlan%d", NULL, |
1666 | IEEE80211_IF_TYPE_STA); | 1666 | IEEE80211_IF_TYPE_STA, NULL); |
1667 | if (result) | 1667 | if (result) |
1668 | printk(KERN_WARNING "%s: Failed to add default virtual iface\n", | 1668 | printk(KERN_WARNING "%s: Failed to add default virtual iface\n", |
1669 | wiphy_name(local->hw.wiphy)); | 1669 | wiphy_name(local->hw.wiphy)); |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index b07b3cbfd03..49466b6996d 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -90,6 +90,12 @@ struct ieee80211_sta_bss { | |||
90 | size_t wmm_ie_len; | 90 | size_t wmm_ie_len; |
91 | u8 *ht_ie; | 91 | u8 *ht_ie; |
92 | size_t ht_ie_len; | 92 | size_t ht_ie_len; |
93 | #ifdef CONFIG_MAC80211_MESH | ||
94 | u8 *mesh_id; | ||
95 | size_t mesh_id_len; | ||
96 | #endif | ||
97 | /* mesh_cfg left out the ifdef to reduce clutter on bss handling */ | ||
98 | u8 *mesh_cfg; | ||
93 | #define IEEE80211_MAX_SUPP_RATES 32 | 99 | #define IEEE80211_MAX_SUPP_RATES 32 |
94 | u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; | 100 | u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; |
95 | size_t supp_rates_len; | 101 | size_t supp_rates_len; |
@@ -227,6 +233,43 @@ struct ieee80211_if_vlan { | |||
227 | struct list_head list; | 233 | struct list_head list; |
228 | }; | 234 | }; |
229 | 235 | ||
236 | #ifdef CONFIG_MAC80211_MESH | ||
237 | struct mesh_stats { | ||
238 | __u32 fwded_frames; /* Mesh forwarded frames */ | ||
239 | __u32 dropped_frames_ttl; /* Not transmitted since mesh_ttl == 0*/ | ||
240 | __u32 dropped_frames_no_route; /* Not transmitted, no route found */ | ||
241 | atomic_t estab_plinks; | ||
242 | }; | ||
243 | |||
244 | #define PREQ_Q_F_START 0x1 | ||
245 | #define PREQ_Q_F_REFRESH 0x2 | ||
246 | struct mesh_preq_queue { | ||
247 | struct list_head list; | ||
248 | u8 dst[ETH_ALEN]; | ||
249 | u8 flags; | ||
250 | }; | ||
251 | |||
252 | |||
253 | struct mesh_config { | ||
254 | /* Timeouts in ms */ | ||
255 | /* Mesh plink management parameters */ | ||
256 | u16 dot11MeshRetryTimeout; | ||
257 | u16 dot11MeshConfirmTimeout; | ||
258 | u16 dot11MeshHoldingTimeout; | ||
259 | u16 dot11MeshMaxPeerLinks; | ||
260 | u8 dot11MeshMaxRetries; | ||
261 | u8 dot11MeshTTL; | ||
262 | bool auto_open_plinks; | ||
263 | /* HWMP parameters */ | ||
264 | u32 dot11MeshHWMPactivePathTimeout; | ||
265 | u16 dot11MeshHWMPpreqMinInterval; | ||
266 | u16 dot11MeshHWMPnetDiameterTraversalTime; | ||
267 | u8 dot11MeshHWMPmaxPREQretries; | ||
268 | u32 path_refresh_time; | ||
269 | u16 min_discovery_timeout; | ||
270 | }; | ||
271 | #endif | ||
272 | |||
230 | /* flags used in struct ieee80211_if_sta.flags */ | 273 | /* flags used in struct ieee80211_if_sta.flags */ |
231 | #define IEEE80211_STA_SSID_SET BIT(0) | 274 | #define IEEE80211_STA_SSID_SET BIT(0) |
232 | #define IEEE80211_STA_BSSID_SET BIT(1) | 275 | #define IEEE80211_STA_BSSID_SET BIT(1) |
@@ -245,7 +288,8 @@ struct ieee80211_if_sta { | |||
245 | enum { | 288 | enum { |
246 | IEEE80211_DISABLED, IEEE80211_AUTHENTICATE, | 289 | IEEE80211_DISABLED, IEEE80211_AUTHENTICATE, |
247 | IEEE80211_ASSOCIATE, IEEE80211_ASSOCIATED, | 290 | IEEE80211_ASSOCIATE, IEEE80211_ASSOCIATED, |
248 | IEEE80211_IBSS_SEARCH, IEEE80211_IBSS_JOINED | 291 | IEEE80211_IBSS_SEARCH, IEEE80211_IBSS_JOINED, |
292 | IEEE80211_MESH_UP | ||
249 | } state; | 293 | } state; |
250 | struct timer_list timer; | 294 | struct timer_list timer; |
251 | struct work_struct work; | 295 | struct work_struct work; |
@@ -254,6 +298,34 @@ struct ieee80211_if_sta { | |||
254 | size_t ssid_len; | 298 | size_t ssid_len; |
255 | u8 scan_ssid[IEEE80211_MAX_SSID_LEN]; | 299 | u8 scan_ssid[IEEE80211_MAX_SSID_LEN]; |
256 | size_t scan_ssid_len; | 300 | size_t scan_ssid_len; |
301 | #ifdef CONFIG_MAC80211_MESH | ||
302 | struct timer_list mesh_path_timer; | ||
303 | u8 mesh_id[IEEE80211_MAX_MESH_ID_LEN]; | ||
304 | bool accepting_plinks; | ||
305 | size_t mesh_id_len; | ||
306 | /* Active Path Selection Protocol Identifier */ | ||
307 | u8 mesh_pp_id[4]; | ||
308 | /* Active Path Selection Metric Identifier */ | ||
309 | u8 mesh_pm_id[4]; | ||
310 | /* Congestion Control Mode Identifier */ | ||
311 | u8 mesh_cc_id[4]; | ||
312 | /* Local mesh Destination Sequence Number */ | ||
313 | u32 dsn; | ||
314 | /* Last used PREQ ID */ | ||
315 | u32 preq_id; | ||
316 | atomic_t mpaths; | ||
317 | /* Timestamp of last DSN update */ | ||
318 | unsigned long last_dsn_update; | ||
319 | /* Timestamp of last DSN sent */ | ||
320 | unsigned long last_preq; | ||
321 | struct mesh_rmc *rmc; | ||
322 | spinlock_t mesh_preq_queue_lock; | ||
323 | struct mesh_preq_queue preq_queue; | ||
324 | int preq_queue_len; | ||
325 | struct mesh_stats mshstats; | ||
326 | struct mesh_config mshcfg; | ||
327 | u8 mesh_seqnum[3]; | ||
328 | #endif | ||
257 | u16 aid; | 329 | u16 aid; |
258 | u16 ap_capab, capab; | 330 | u16 ap_capab, capab; |
259 | u8 *extra_ie; /* to be added to the end of AssocReq */ | 331 | u8 *extra_ie; /* to be added to the end of AssocReq */ |
@@ -286,6 +358,7 @@ struct ieee80211_if_sta { | |||
286 | u32 supp_rates_bits[IEEE80211_NUM_BANDS]; | 358 | u32 supp_rates_bits[IEEE80211_NUM_BANDS]; |
287 | 359 | ||
288 | int wmm_last_param_set; | 360 | int wmm_last_param_set; |
361 | int num_beacons; /* number of TXed beacon frames by this STA */ | ||
289 | }; | 362 | }; |
290 | 363 | ||
291 | 364 | ||
@@ -365,6 +438,7 @@ struct ieee80211_sub_if_data { | |||
365 | struct dentry *auth_alg; | 438 | struct dentry *auth_alg; |
366 | struct dentry *auth_transaction; | 439 | struct dentry *auth_transaction; |
367 | struct dentry *flags; | 440 | struct dentry *flags; |
441 | struct dentry *num_beacons_sta; | ||
368 | } sta; | 442 | } sta; |
369 | struct { | 443 | struct { |
370 | struct dentry *channel_use; | 444 | struct dentry *channel_use; |
@@ -390,6 +464,35 @@ struct ieee80211_sub_if_data { | |||
390 | } monitor; | 464 | } monitor; |
391 | struct dentry *default_key; | 465 | struct dentry *default_key; |
392 | } debugfs; | 466 | } debugfs; |
467 | |||
468 | #ifdef CONFIG_MAC80211_MESH | ||
469 | struct dentry *mesh_stats_dir; | ||
470 | struct { | ||
471 | struct dentry *fwded_frames; | ||
472 | struct dentry *dropped_frames_ttl; | ||
473 | struct dentry *dropped_frames_no_route; | ||
474 | struct dentry *estab_plinks; | ||
475 | struct timer_list mesh_path_timer; | ||
476 | } mesh_stats; | ||
477 | |||
478 | struct dentry *mesh_config_dir; | ||
479 | struct { | ||
480 | struct dentry *dot11MeshRetryTimeout; | ||
481 | struct dentry *dot11MeshConfirmTimeout; | ||
482 | struct dentry *dot11MeshHoldingTimeout; | ||
483 | struct dentry *dot11MeshMaxRetries; | ||
484 | struct dentry *dot11MeshTTL; | ||
485 | struct dentry *auto_open_plinks; | ||
486 | struct dentry *dot11MeshMaxPeerLinks; | ||
487 | struct dentry *dot11MeshHWMPactivePathTimeout; | ||
488 | struct dentry *dot11MeshHWMPpreqMinInterval; | ||
489 | struct dentry *dot11MeshHWMPnetDiameterTraversalTime; | ||
490 | struct dentry *dot11MeshHWMPmaxPREQretries; | ||
491 | struct dentry *path_refresh_time; | ||
492 | struct dentry *min_discovery_timeout; | ||
493 | } mesh_config; | ||
494 | #endif | ||
495 | |||
393 | #endif | 496 | #endif |
394 | /* must be last, dynamically sized area in this! */ | 497 | /* must be last, dynamically sized area in this! */ |
395 | struct ieee80211_vif vif; | 498 | struct ieee80211_vif vif; |
@@ -617,6 +720,57 @@ struct ieee80211_ra_tid { | |||
617 | u16 tid; | 720 | u16 tid; |
618 | }; | 721 | }; |
619 | 722 | ||
723 | /* Parsed Information Elements */ | ||
724 | struct ieee802_11_elems { | ||
725 | /* pointers to IEs */ | ||
726 | u8 *ssid; | ||
727 | u8 *supp_rates; | ||
728 | u8 *fh_params; | ||
729 | u8 *ds_params; | ||
730 | u8 *cf_params; | ||
731 | u8 *tim; | ||
732 | u8 *ibss_params; | ||
733 | u8 *challenge; | ||
734 | u8 *wpa; | ||
735 | u8 *rsn; | ||
736 | u8 *erp_info; | ||
737 | u8 *ext_supp_rates; | ||
738 | u8 *wmm_info; | ||
739 | u8 *wmm_param; | ||
740 | u8 *ht_cap_elem; | ||
741 | u8 *ht_info_elem; | ||
742 | u8 *mesh_config; | ||
743 | u8 *mesh_id; | ||
744 | u8 *peer_link; | ||
745 | u8 *preq; | ||
746 | u8 *prep; | ||
747 | u8 *perr; | ||
748 | |||
749 | /* length of them, respectively */ | ||
750 | u8 ssid_len; | ||
751 | u8 supp_rates_len; | ||
752 | u8 fh_params_len; | ||
753 | u8 ds_params_len; | ||
754 | u8 cf_params_len; | ||
755 | u8 tim_len; | ||
756 | u8 ibss_params_len; | ||
757 | u8 challenge_len; | ||
758 | u8 wpa_len; | ||
759 | u8 rsn_len; | ||
760 | u8 erp_info_len; | ||
761 | u8 ext_supp_rates_len; | ||
762 | u8 wmm_info_len; | ||
763 | u8 wmm_param_len; | ||
764 | u8 ht_cap_elem_len; | ||
765 | u8 ht_info_elem_len; | ||
766 | u8 mesh_config_len; | ||
767 | u8 mesh_id_len; | ||
768 | u8 peer_link_len; | ||
769 | u8 preq_len; | ||
770 | u8 prep_len; | ||
771 | u8 perr_len; | ||
772 | }; | ||
773 | |||
620 | static inline struct ieee80211_local *hw_to_local( | 774 | static inline struct ieee80211_local *hw_to_local( |
621 | struct ieee80211_hw *hw) | 775 | struct ieee80211_hw *hw) |
622 | { | 776 | { |
@@ -686,6 +840,7 @@ int ieee80211_set_compression(struct ieee80211_local *local, | |||
686 | struct net_device *dev, struct sta_info *sta); | 840 | struct net_device *dev, struct sta_info *sta); |
687 | int ieee80211_set_freq(struct ieee80211_local *local, int freq); | 841 | int ieee80211_set_freq(struct ieee80211_local *local, int freq); |
688 | /* ieee80211_sta.c */ | 842 | /* ieee80211_sta.c */ |
843 | #define IEEE80211_FC(type, stype) cpu_to_le16(type | stype) | ||
689 | void ieee80211_sta_timer(unsigned long data); | 844 | void ieee80211_sta_timer(unsigned long data); |
690 | void ieee80211_sta_work(struct work_struct *work); | 845 | void ieee80211_sta_work(struct work_struct *work); |
691 | void ieee80211_sta_scan_work(struct work_struct *work); | 846 | void ieee80211_sta_scan_work(struct work_struct *work); |
@@ -726,9 +881,20 @@ void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *da, | |||
726 | u16 tid, u16 initiator, u16 reason); | 881 | u16 tid, u16 initiator, u16 reason); |
727 | void sta_rx_agg_session_timer_expired(unsigned long data); | 882 | void sta_rx_agg_session_timer_expired(unsigned long data); |
728 | void sta_addba_resp_timer_expired(unsigned long data); | 883 | void sta_addba_resp_timer_expired(unsigned long data); |
884 | u64 ieee80211_sta_get_rates(struct ieee80211_local *local, | ||
885 | struct ieee802_11_elems *elems, | ||
886 | enum ieee80211_band band); | ||
887 | void ieee80211_start_mesh(struct net_device *dev); | ||
888 | void ieee80211_sta_tx(struct net_device *dev, struct sk_buff *skb, | ||
889 | int encrypt); | ||
890 | void ieee802_11_parse_elems(u8 *start, size_t len, | ||
891 | struct ieee802_11_elems *elems); | ||
892 | |||
893 | |||
729 | /* ieee80211_iface.c */ | 894 | /* ieee80211_iface.c */ |
730 | int ieee80211_if_add(struct net_device *dev, const char *name, | 895 | int ieee80211_if_add(struct net_device *dev, const char *name, |
731 | struct net_device **new_dev, int type); | 896 | struct net_device **new_dev, int type, |
897 | struct vif_params *params); | ||
732 | void ieee80211_if_set_type(struct net_device *dev, int type); | 898 | void ieee80211_if_set_type(struct net_device *dev, int type); |
733 | void ieee80211_if_reinit(struct net_device *dev); | 899 | void ieee80211_if_reinit(struct net_device *dev); |
734 | void __ieee80211_if_del(struct ieee80211_local *local, | 900 | void __ieee80211_if_del(struct ieee80211_local *local, |
diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c index 9523aeb7103..c2f92b78bfc 100644 --- a/net/mac80211/ieee80211_iface.c +++ b/net/mac80211/ieee80211_iface.c | |||
@@ -15,6 +15,9 @@ | |||
15 | #include "ieee80211_i.h" | 15 | #include "ieee80211_i.h" |
16 | #include "sta_info.h" | 16 | #include "sta_info.h" |
17 | #include "debugfs_netdev.h" | 17 | #include "debugfs_netdev.h" |
18 | #ifdef CONFIG_MAC80211_MESH | ||
19 | #include "mesh.h" | ||
20 | #endif | ||
18 | 21 | ||
19 | void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata) | 22 | void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata) |
20 | { | 23 | { |
@@ -39,7 +42,8 @@ static void ieee80211_if_sdata_deinit(struct ieee80211_sub_if_data *sdata) | |||
39 | 42 | ||
40 | /* Must be called with rtnl lock held. */ | 43 | /* Must be called with rtnl lock held. */ |
41 | int ieee80211_if_add(struct net_device *dev, const char *name, | 44 | int ieee80211_if_add(struct net_device *dev, const char *name, |
42 | struct net_device **new_dev, int type) | 45 | struct net_device **new_dev, int type, |
46 | struct vif_params *params) | ||
43 | { | 47 | { |
44 | struct net_device *ndev; | 48 | struct net_device *ndev; |
45 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 49 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
@@ -78,6 +82,15 @@ int ieee80211_if_add(struct net_device *dev, const char *name, | |||
78 | ieee80211_debugfs_add_netdev(sdata); | 82 | ieee80211_debugfs_add_netdev(sdata); |
79 | ieee80211_if_set_type(ndev, type); | 83 | ieee80211_if_set_type(ndev, type); |
80 | 84 | ||
85 | #ifdef CONFIG_MAC80211_MESH | ||
86 | if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT && | ||
87 | params && params->mesh_id_len) { | ||
88 | sdata->u.sta.mesh_id_len = params->mesh_id_len; | ||
89 | memcpy(sdata->u.sta.mesh_id, params->mesh_id, | ||
90 | params->mesh_id_len); | ||
91 | } | ||
92 | #endif | ||
93 | |||
81 | /* we're under RTNL so all this is fine */ | 94 | /* we're under RTNL so all this is fine */ |
82 | if (unlikely(local->reg_state == IEEE80211_DEV_UNREGISTERED)) { | 95 | if (unlikely(local->reg_state == IEEE80211_DEV_UNREGISTERED)) { |
83 | __ieee80211_if_del(local, sdata); | 96 | __ieee80211_if_del(local, sdata); |
@@ -134,6 +147,7 @@ void ieee80211_if_set_type(struct net_device *dev, int type) | |||
134 | sdata->bss = &sdata->u.ap; | 147 | sdata->bss = &sdata->u.ap; |
135 | INIT_LIST_HEAD(&sdata->u.ap.vlans); | 148 | INIT_LIST_HEAD(&sdata->u.ap.vlans); |
136 | break; | 149 | break; |
150 | case IEEE80211_IF_TYPE_MESH_POINT: | ||
137 | case IEEE80211_IF_TYPE_STA: | 151 | case IEEE80211_IF_TYPE_STA: |
138 | case IEEE80211_IF_TYPE_IBSS: { | 152 | case IEEE80211_IF_TYPE_IBSS: { |
139 | struct ieee80211_sub_if_data *msdata; | 153 | struct ieee80211_sub_if_data *msdata; |
@@ -155,6 +169,48 @@ void ieee80211_if_set_type(struct net_device *dev, int type) | |||
155 | 169 | ||
156 | msdata = IEEE80211_DEV_TO_SUB_IF(sdata->local->mdev); | 170 | msdata = IEEE80211_DEV_TO_SUB_IF(sdata->local->mdev); |
157 | sdata->bss = &msdata->u.ap; | 171 | sdata->bss = &msdata->u.ap; |
172 | |||
173 | #ifdef CONFIG_MAC80211_MESH | ||
174 | if (type == IEEE80211_IF_TYPE_MESH_POINT) { | ||
175 | ifsta->mshcfg.dot11MeshRetryTimeout = MESH_RET_T; | ||
176 | ifsta->mshcfg.dot11MeshConfirmTimeout = MESH_CONF_T; | ||
177 | ifsta->mshcfg.dot11MeshHoldingTimeout = MESH_HOLD_T; | ||
178 | ifsta->mshcfg.dot11MeshMaxRetries = MESH_MAX_RETR; | ||
179 | ifsta->mshcfg.dot11MeshTTL = MESH_TTL; | ||
180 | ifsta->mshcfg.auto_open_plinks = true; | ||
181 | ifsta->mshcfg.dot11MeshMaxPeerLinks = | ||
182 | MESH_MAX_ESTAB_PLINKS; | ||
183 | ifsta->mshcfg.dot11MeshHWMPactivePathTimeout = | ||
184 | MESH_PATH_TIMEOUT; | ||
185 | ifsta->mshcfg.dot11MeshHWMPpreqMinInterval = | ||
186 | MESH_PREQ_MIN_INT; | ||
187 | ifsta->mshcfg.dot11MeshHWMPnetDiameterTraversalTime = | ||
188 | MESH_DIAM_TRAVERSAL_TIME; | ||
189 | ifsta->mshcfg.dot11MeshHWMPmaxPREQretries = | ||
190 | MESH_MAX_PREQ_RETRIES; | ||
191 | ifsta->mshcfg.path_refresh_time = | ||
192 | MESH_PATH_REFRESH_TIME; | ||
193 | ifsta->mshcfg.min_discovery_timeout = | ||
194 | MESH_MIN_DISCOVERY_TIMEOUT; | ||
195 | ifsta->accepting_plinks = true; | ||
196 | ifsta->preq_id = 0; | ||
197 | ifsta->dsn = 0; | ||
198 | atomic_set(&ifsta->mpaths, 0); | ||
199 | mesh_rmc_init(dev); | ||
200 | ifsta->last_preq = jiffies; | ||
201 | /* Allocate all mesh structures when creating the first | ||
202 | * mesh interface. | ||
203 | */ | ||
204 | if (!mesh_allocated) | ||
205 | ieee80211s_init(); | ||
206 | mesh_ids_set_default(ifsta); | ||
207 | setup_timer(&ifsta->mesh_path_timer, | ||
208 | ieee80211_mesh_path_timer, | ||
209 | (unsigned long) sdata); | ||
210 | INIT_LIST_HEAD(&ifsta->preq_queue.list); | ||
211 | spin_lock_init(&ifsta->mesh_preq_queue_lock); | ||
212 | } | ||
213 | #endif | ||
158 | break; | 214 | break; |
159 | } | 215 | } |
160 | case IEEE80211_IF_TYPE_MNTR: | 216 | case IEEE80211_IF_TYPE_MNTR: |
@@ -236,6 +292,10 @@ void ieee80211_if_reinit(struct net_device *dev) | |||
236 | } | 292 | } |
237 | break; | 293 | break; |
238 | case IEEE80211_IF_TYPE_MESH_POINT: | 294 | case IEEE80211_IF_TYPE_MESH_POINT: |
295 | #ifdef CONFIG_MAC80211_MESH | ||
296 | mesh_rmc_free(dev); | ||
297 | #endif | ||
298 | /* fall through */ | ||
239 | case IEEE80211_IF_TYPE_STA: | 299 | case IEEE80211_IF_TYPE_STA: |
240 | case IEEE80211_IF_TYPE_IBSS: | 300 | case IEEE80211_IF_TYPE_IBSS: |
241 | kfree(sdata->u.sta.extra_ie); | 301 | kfree(sdata->u.sta.extra_ie); |
diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index 7551db3f3ab..38e2d83e15f 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c | |||
@@ -525,6 +525,7 @@ static int ieee80211_ioctl_siwscan(struct net_device *dev, | |||
525 | 525 | ||
526 | if (sdata->vif.type != IEEE80211_IF_TYPE_STA && | 526 | if (sdata->vif.type != IEEE80211_IF_TYPE_STA && |
527 | sdata->vif.type != IEEE80211_IF_TYPE_IBSS && | 527 | sdata->vif.type != IEEE80211_IF_TYPE_IBSS && |
528 | sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT && | ||
528 | sdata->vif.type != IEEE80211_IF_TYPE_AP) | 529 | sdata->vif.type != IEEE80211_IF_TYPE_AP) |
529 | return -EOPNOTSUPP; | 530 | return -EOPNOTSUPP; |
530 | 531 | ||
diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index ddb5832f37c..b4b498ae60f 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c | |||
@@ -87,46 +87,8 @@ static int ieee80211_sta_config_auth(struct net_device *dev, | |||
87 | struct ieee80211_if_sta *ifsta); | 87 | struct ieee80211_if_sta *ifsta); |
88 | 88 | ||
89 | 89 | ||
90 | /* Parsed Information Elements */ | 90 | void ieee802_11_parse_elems(u8 *start, size_t len, |
91 | struct ieee802_11_elems { | 91 | struct ieee802_11_elems *elems) |
92 | /* pointers to IEs */ | ||
93 | u8 *ssid; | ||
94 | u8 *supp_rates; | ||
95 | u8 *fh_params; | ||
96 | u8 *ds_params; | ||
97 | u8 *cf_params; | ||
98 | u8 *tim; | ||
99 | u8 *ibss_params; | ||
100 | u8 *challenge; | ||
101 | u8 *wpa; | ||
102 | u8 *rsn; | ||
103 | u8 *erp_info; | ||
104 | u8 *ext_supp_rates; | ||
105 | u8 *wmm_info; | ||
106 | u8 *wmm_param; | ||
107 | u8 *ht_cap_elem; | ||
108 | u8 *ht_info_elem; | ||
109 | /* length of them, respectively */ | ||
110 | u8 ssid_len; | ||
111 | u8 supp_rates_len; | ||
112 | u8 fh_params_len; | ||
113 | u8 ds_params_len; | ||
114 | u8 cf_params_len; | ||
115 | u8 tim_len; | ||
116 | u8 ibss_params_len; | ||
117 | u8 challenge_len; | ||
118 | u8 wpa_len; | ||
119 | u8 rsn_len; | ||
120 | u8 erp_info_len; | ||
121 | u8 ext_supp_rates_len; | ||
122 | u8 wmm_info_len; | ||
123 | u8 wmm_param_len; | ||
124 | u8 ht_cap_elem_len; | ||
125 | u8 ht_info_elem_len; | ||
126 | }; | ||
127 | |||
128 | static void ieee802_11_parse_elems(u8 *start, size_t len, | ||
129 | struct ieee802_11_elems *elems) | ||
130 | { | 92 | { |
131 | size_t left = len; | 93 | size_t left = len; |
132 | u8 *pos = start; | 94 | u8 *pos = start; |
@@ -215,6 +177,30 @@ static void ieee802_11_parse_elems(u8 *start, size_t len, | |||
215 | elems->ht_info_elem = pos; | 177 | elems->ht_info_elem = pos; |
216 | elems->ht_info_elem_len = elen; | 178 | elems->ht_info_elem_len = elen; |
217 | break; | 179 | break; |
180 | case WLAN_EID_MESH_ID: | ||
181 | elems->mesh_id = pos; | ||
182 | elems->mesh_id_len = elen; | ||
183 | break; | ||
184 | case WLAN_EID_MESH_CONFIG: | ||
185 | elems->mesh_config = pos; | ||
186 | elems->mesh_config_len = elen; | ||
187 | break; | ||
188 | case WLAN_EID_PEER_LINK: | ||
189 | elems->peer_link = pos; | ||
190 | elems->peer_link_len = elen; | ||
191 | break; | ||
192 | case WLAN_EID_PREQ: | ||
193 | elems->preq = pos; | ||
194 | elems->preq_len = elen; | ||
195 | break; | ||
196 | case WLAN_EID_PREP: | ||
197 | elems->prep = pos; | ||
198 | elems->prep_len = elen; | ||
199 | break; | ||
200 | case WLAN_EID_PERR: | ||
201 | elems->perr = pos; | ||
202 | elems->perr_len = elen; | ||
203 | break; | ||
218 | default: | 204 | default: |
219 | break; | 205 | break; |
220 | } | 206 | } |
@@ -501,8 +487,8 @@ static void ieee80211_set_disassoc(struct net_device *dev, | |||
501 | ieee80211_set_associated(dev, ifsta, 0); | 487 | ieee80211_set_associated(dev, ifsta, 0); |
502 | } | 488 | } |
503 | 489 | ||
504 | static void ieee80211_sta_tx(struct net_device *dev, struct sk_buff *skb, | 490 | void ieee80211_sta_tx(struct net_device *dev, struct sk_buff *skb, |
505 | int encrypt) | 491 | int encrypt) |
506 | { | 492 | { |
507 | struct ieee80211_sub_if_data *sdata; | 493 | struct ieee80211_sub_if_data *sdata; |
508 | struct ieee80211_tx_packet_data *pkt_data; | 494 | struct ieee80211_tx_packet_data *pkt_data; |
diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c index 9762803e487..4a51647a41a 100644 --- a/net/mac80211/rc80211_pid_algo.c +++ b/net/mac80211/rc80211_pid_algo.c | |||
@@ -15,6 +15,9 @@ | |||
15 | #include <linux/debugfs.h> | 15 | #include <linux/debugfs.h> |
16 | #include <net/mac80211.h> | 16 | #include <net/mac80211.h> |
17 | #include "ieee80211_rate.h" | 17 | #include "ieee80211_rate.h" |
18 | #ifdef CONFIG_MAC80211_MESH | ||
19 | #include "mesh.h" | ||
20 | #endif | ||
18 | 21 | ||
19 | #include "rc80211_pid.h" | 22 | #include "rc80211_pid.h" |
20 | 23 | ||
@@ -148,6 +151,9 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo, | |||
148 | struct ieee80211_local *local, | 151 | struct ieee80211_local *local, |
149 | struct sta_info *sta) | 152 | struct sta_info *sta) |
150 | { | 153 | { |
154 | #ifdef CONFIG_MAC80211_MESH | ||
155 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); | ||
156 | #endif | ||
151 | struct rc_pid_sta_info *spinfo = sta->rate_ctrl_priv; | 157 | struct rc_pid_sta_info *spinfo = sta->rate_ctrl_priv; |
152 | struct rc_pid_rateinfo *rinfo = pinfo->rinfo; | 158 | struct rc_pid_rateinfo *rinfo = pinfo->rinfo; |
153 | struct ieee80211_supported_band *sband; | 159 | struct ieee80211_supported_band *sband; |
@@ -178,7 +184,14 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo, | |||
178 | pf = spinfo->last_pf; | 184 | pf = spinfo->last_pf; |
179 | else { | 185 | else { |
180 | pf = spinfo->tx_num_failed * 100 / spinfo->tx_num_xmit; | 186 | pf = spinfo->tx_num_failed * 100 / spinfo->tx_num_xmit; |
187 | #ifdef CONFIG_MAC80211_MESH | ||
188 | if (pf == 100 && | ||
189 | sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) | ||
190 | mesh_plink_broken(sta); | ||
191 | #endif | ||
181 | pf <<= RC_PID_ARITH_SHIFT; | 192 | pf <<= RC_PID_ARITH_SHIFT; |
193 | sta->fail_avg = ((pf + (spinfo->last_pf << 3)) / 9) | ||
194 | >> RC_PID_ARITH_SHIFT; | ||
182 | } | 195 | } |
183 | 196 | ||
184 | spinfo->tx_num_xmit = 0; | 197 | spinfo->tx_num_xmit = 0; |
@@ -357,6 +370,7 @@ static void rate_control_pid_rate_init(void *priv, void *priv_sta, | |||
357 | 370 | ||
358 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 371 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
359 | sta->txrate_idx = rate_lowest_index(local, sband, sta); | 372 | sta->txrate_idx = rate_lowest_index(local, sband, sta); |
373 | sta->fail_avg = 0; | ||
360 | } | 374 | } |
361 | 375 | ||
362 | static void *rate_control_pid_alloc(struct ieee80211_local *local) | 376 | static void *rate_control_pid_alloc(struct ieee80211_local *local) |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index e384e6632d9..1f3c9eb9850 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -21,6 +21,9 @@ | |||
21 | #include "ieee80211_rate.h" | 21 | #include "ieee80211_rate.h" |
22 | #include "sta_info.h" | 22 | #include "sta_info.h" |
23 | #include "debugfs_sta.h" | 23 | #include "debugfs_sta.h" |
24 | #ifdef CONFIG_MAC80211_MESH | ||
25 | #include "mesh.h" | ||
26 | #endif | ||
24 | 27 | ||
25 | /* Caller must hold local->sta_lock */ | 28 | /* Caller must hold local->sta_lock */ |
26 | static void sta_info_hash_add(struct ieee80211_local *local, | 29 | static void sta_info_hash_add(struct ieee80211_local *local, |
@@ -84,6 +87,27 @@ struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr) | |||
84 | } | 87 | } |
85 | EXPORT_SYMBOL(sta_info_get); | 88 | EXPORT_SYMBOL(sta_info_get); |
86 | 89 | ||
90 | struct sta_info *sta_info_get_by_idx(struct ieee80211_local *local, int idx, | ||
91 | struct net_device *dev) | ||
92 | { | ||
93 | struct sta_info *sta; | ||
94 | int i = 0; | ||
95 | |||
96 | read_lock_bh(&local->sta_lock); | ||
97 | list_for_each_entry(sta, &local->sta_list, list) { | ||
98 | if (i < idx) { | ||
99 | ++i; | ||
100 | continue; | ||
101 | } else if (!dev || dev == sta->dev) { | ||
102 | __sta_info_get(sta); | ||
103 | read_unlock_bh(&local->sta_lock); | ||
104 | return sta; | ||
105 | } | ||
106 | } | ||
107 | read_unlock_bh(&local->sta_lock); | ||
108 | |||
109 | return NULL; | ||
110 | } | ||
87 | 111 | ||
88 | static void sta_info_release(struct kref *kref) | 112 | static void sta_info_release(struct kref *kref) |
89 | { | 113 | { |
@@ -284,12 +308,19 @@ void sta_info_remove(struct sta_info *sta) | |||
284 | __sta_info_clear_tim_bit(sdata->bss, sta); | 308 | __sta_info_clear_tim_bit(sdata->bss, sta); |
285 | } | 309 | } |
286 | local->num_sta--; | 310 | local->num_sta--; |
311 | |||
312 | #ifdef CONFIG_MAC80211_MESH | ||
313 | if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) | ||
314 | mesh_accept_plinks_update(sdata->dev); | ||
315 | #endif | ||
287 | } | 316 | } |
288 | 317 | ||
289 | void sta_info_free(struct sta_info *sta) | 318 | void sta_info_free(struct sta_info *sta) |
290 | { | 319 | { |
291 | struct sk_buff *skb; | 320 | struct sk_buff *skb; |
292 | struct ieee80211_local *local = sta->local; | 321 | struct ieee80211_local *local = sta->local; |
322 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); | ||
323 | |||
293 | DECLARE_MAC_BUF(mac); | 324 | DECLARE_MAC_BUF(mac); |
294 | 325 | ||
295 | might_sleep(); | 326 | might_sleep(); |
@@ -298,6 +329,14 @@ void sta_info_free(struct sta_info *sta) | |||
298 | sta_info_remove(sta); | 329 | sta_info_remove(sta); |
299 | write_unlock_bh(&local->sta_lock); | 330 | write_unlock_bh(&local->sta_lock); |
300 | 331 | ||
332 | #ifdef CONFIG_MAC80211_MESH | ||
333 | if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) { | ||
334 | spin_lock_bh(&sta->plink_lock); | ||
335 | mesh_plink_deactivate(sta); | ||
336 | spin_unlock_bh(&sta->plink_lock); | ||
337 | } | ||
338 | #endif | ||
339 | |||
301 | while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { | 340 | while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { |
302 | local->total_ps_buffered--; | 341 | local->total_ps_buffered--; |
303 | dev_kfree_skb(skb); | 342 | dev_kfree_skb(skb); |
@@ -315,9 +354,6 @@ void sta_info_free(struct sta_info *sta) | |||
315 | WARN_ON(sta->key); | 354 | WARN_ON(sta->key); |
316 | 355 | ||
317 | if (local->ops->sta_notify) { | 356 | if (local->ops->sta_notify) { |
318 | struct ieee80211_sub_if_data *sdata; | ||
319 | |||
320 | sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); | ||
321 | 357 | ||
322 | if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN) | 358 | if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN) |
323 | sdata = sdata->u.vlan.ap; | 359 | sdata = sdata->u.vlan.ap; |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 86eed40ada7..9d1d7a0e311 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -107,6 +107,18 @@ struct tid_ampdu_rx { | |||
107 | struct timer_list session_timer; | 107 | struct timer_list session_timer; |
108 | }; | 108 | }; |
109 | 109 | ||
110 | #ifdef CONFIG_MAC80211_MESH | ||
111 | enum plink_state { | ||
112 | LISTEN, | ||
113 | OPN_SNT, | ||
114 | OPN_RCVD, | ||
115 | CNF_RCVD, | ||
116 | ESTAB, | ||
117 | HOLDING, | ||
118 | BLOCKED | ||
119 | }; | ||
120 | #endif | ||
121 | |||
110 | /** | 122 | /** |
111 | * struct sta_ampdu_mlme - STA aggregation information. | 123 | * struct sta_ampdu_mlme - STA aggregation information. |
112 | * | 124 | * |
@@ -144,6 +156,8 @@ struct sta_info { | |||
144 | unsigned long rx_bytes, tx_bytes; | 156 | unsigned long rx_bytes, tx_bytes; |
145 | unsigned long tx_retry_failed, tx_retry_count; | 157 | unsigned long tx_retry_failed, tx_retry_count; |
146 | unsigned long tx_filtered_count; | 158 | unsigned long tx_filtered_count; |
159 | /* moving percentage of failed MSDUs */ | ||
160 | unsigned int fail_avg; | ||
147 | 161 | ||
148 | unsigned int wep_weak_iv_count; /* number of RX frames with weak IV */ | 162 | unsigned int wep_weak_iv_count; /* number of RX frames with weak IV */ |
149 | 163 | ||
@@ -192,6 +206,20 @@ struct sta_info { | |||
192 | struct sta_ampdu_mlme ampdu_mlme; | 206 | struct sta_ampdu_mlme ampdu_mlme; |
193 | u8 timer_to_tid[STA_TID_NUM]; /* convert timer id to tid */ | 207 | u8 timer_to_tid[STA_TID_NUM]; /* convert timer id to tid */ |
194 | u8 tid_to_tx_q[STA_TID_NUM]; /* map tid to tx queue */ | 208 | u8 tid_to_tx_q[STA_TID_NUM]; /* map tid to tx queue */ |
209 | #ifdef CONFIG_MAC80211_MESH | ||
210 | /* mesh peer link attributes */ | ||
211 | __le16 llid; /* Local link ID */ | ||
212 | __le16 plid; /* Peer link ID */ | ||
213 | __le16 reason; /* Buffer for cancel reason on HOLDING state */ | ||
214 | enum plink_state plink_state; | ||
215 | u32 plink_timeout; | ||
216 | struct timer_list plink_timer; | ||
217 | u8 plink_retries; /* Retries in establishment */ | ||
218 | bool ignore_plink_timer; | ||
219 | spinlock_t plink_lock; /* For peer_state reads / updates and other | ||
220 | updates in the structure. Ensures robust | ||
221 | transitions for the peerlink FSM */ | ||
222 | #endif | ||
195 | 223 | ||
196 | #ifdef CONFIG_MAC80211_DEBUGFS | 224 | #ifdef CONFIG_MAC80211_DEBUGFS |
197 | struct sta_info_debugfsdentries { | 225 | struct sta_info_debugfsdentries { |
@@ -234,6 +262,8 @@ static inline void __sta_info_get(struct sta_info *sta) | |||
234 | } | 262 | } |
235 | 263 | ||
236 | struct sta_info * sta_info_get(struct ieee80211_local *local, u8 *addr); | 264 | struct sta_info * sta_info_get(struct ieee80211_local *local, u8 *addr); |
265 | struct sta_info *sta_info_get_by_idx(struct ieee80211_local *local, int idx, | ||
266 | struct net_device *dev); | ||
237 | void sta_info_put(struct sta_info *sta); | 267 | void sta_info_put(struct sta_info *sta); |
238 | struct sta_info *sta_info_add(struct ieee80211_local *local, | 268 | struct sta_info *sta_info_add(struct ieee80211_local *local, |
239 | struct net_device *dev, u8 *addr, gfp_t gfp); | 269 | struct net_device *dev, u8 *addr, gfp_t gfp); |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 790c32f894c..6b50b6c12da 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -26,6 +26,9 @@ | |||
26 | 26 | ||
27 | #include "ieee80211_i.h" | 27 | #include "ieee80211_i.h" |
28 | #include "ieee80211_rate.h" | 28 | #include "ieee80211_rate.h" |
29 | #ifdef CONFIG_MAC80211_MESH | ||
30 | #include "mesh.h" | ||
31 | #endif | ||
29 | #include "wme.h" | 32 | #include "wme.h" |
30 | 33 | ||
31 | /* privid for wiphys to determine whether they belong to us or not */ | 34 | /* privid for wiphys to determine whether they belong to us or not */ |
@@ -146,6 +149,26 @@ int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb) | |||
146 | } | 149 | } |
147 | EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb); | 150 | EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb); |
148 | 151 | ||
152 | #ifdef CONFIG_MAC80211_MESH | ||
153 | int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) | ||
154 | { | ||
155 | int ae = meshhdr->flags & IEEE80211S_FLAGS_AE; | ||
156 | /* 7.1.3.5a.2 */ | ||
157 | switch (ae) { | ||
158 | case 0: | ||
159 | return 5; | ||
160 | case 1: | ||
161 | return 11; | ||
162 | case 2: | ||
163 | return 17; | ||
164 | case 3: | ||
165 | return 23; | ||
166 | default: | ||
167 | return 5; | ||
168 | } | ||
169 | } | ||
170 | #endif | ||
171 | |||
149 | void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx) | 172 | void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx) |
150 | { | 173 | { |
151 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; | 174 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; |
@@ -395,3 +418,31 @@ void ieee80211_iterate_active_interfaces( | |||
395 | rcu_read_unlock(); | 418 | rcu_read_unlock(); |
396 | } | 419 | } |
397 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces); | 420 | EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces); |
421 | |||
422 | #ifdef CONFIG_MAC80211_MESH | ||
423 | /** | ||
424 | * ieee80211_new_mesh_header - create a new mesh header | ||
425 | * @meshhdr: uninitialized mesh header | ||
426 | * @sdata: mesh interface to be used | ||
427 | * | ||
428 | * Return the header length. | ||
429 | */ | ||
430 | int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr, | ||
431 | struct ieee80211_sub_if_data *sdata) | ||
432 | { | ||
433 | meshhdr->flags = 0; | ||
434 | meshhdr->ttl = sdata->u.sta.mshcfg.dot11MeshTTL; | ||
435 | |||
436 | meshhdr->seqnum[0] = sdata->u.sta.mesh_seqnum[0]++; | ||
437 | meshhdr->seqnum[1] = sdata->u.sta.mesh_seqnum[1]; | ||
438 | meshhdr->seqnum[2] = sdata->u.sta.mesh_seqnum[2]; | ||
439 | |||
440 | if (sdata->u.sta.mesh_seqnum[0] == 0) { | ||
441 | sdata->u.sta.mesh_seqnum[1]++; | ||
442 | if (sdata->u.sta.mesh_seqnum[1] == 0) | ||
443 | sdata->u.sta.mesh_seqnum[2]++; | ||
444 | } | ||
445 | |||
446 | return 5; | ||
447 | } | ||
448 | #endif | ||