diff options
author | David S. Miller <davem@davemloft.net> | 2009-11-18 13:55:32 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-11-18 13:55:32 -0500 |
commit | dfef948ed2ba69cf041840b5e860d6b4e16fa0b1 (patch) | |
tree | eab385cabe589346bcf19385c997ab8dabaef7bd /net | |
parent | ea31ba359c55e0734ff895692185d4c50cf0c537 (diff) | |
parent | c85e9d7739fc8d879c4293ea020760926d6f87cd (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/Kconfig | 13 | ||||
-rw-r--r-- | net/mac80211/cfg.c | 47 | ||||
-rw-r--r-- | net/mac80211/debugfs_netdev.c | 2 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 27 | ||||
-rw-r--r-- | net/mac80211/iface.c | 4 | ||||
-rw-r--r-- | net/mac80211/mesh.c | 143 | ||||
-rw-r--r-- | net/mac80211/mesh.h | 28 | ||||
-rw-r--r-- | net/mac80211/mesh_hwmp.c | 388 | ||||
-rw-r--r-- | net/mac80211/mesh_pathtbl.c | 18 | ||||
-rw-r--r-- | net/mac80211/mesh_plink.c | 56 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 1 | ||||
-rw-r--r-- | net/mac80211/rx.c | 40 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 3 | ||||
-rw-r--r-- | net/mac80211/tx.c | 47 | ||||
-rw-r--r-- | net/mac80211/util.c | 4 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 208 | ||||
-rw-r--r-- | net/wireless/util.c | 4 |
17 files changed, 742 insertions, 291 deletions
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index 4d5543af3123..a10d508b07e1 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig | |||
@@ -194,6 +194,19 @@ config MAC80211_VERBOSE_MPL_DEBUG | |||
194 | 194 | ||
195 | Do not select this option. | 195 | Do not select this option. |
196 | 196 | ||
197 | config MAC80211_VERBOSE_MHWMP_DEBUG | ||
198 | bool "Verbose mesh HWMP routing debugging" | ||
199 | depends on MAC80211_DEBUG_MENU | ||
200 | depends on MAC80211_MESH | ||
201 | ---help--- | ||
202 | Selecting this option causes mac80211 to print out very | ||
203 | verbose mesh routing (HWMP) debugging messages (when mac80211 | ||
204 | is taking part in a mesh network). | ||
205 | It should not be selected on production systems as those | ||
206 | messages are remotely triggerable. | ||
207 | |||
208 | Do not select this option. | ||
209 | |||
197 | config MAC80211_DEBUG_COUNTERS | 210 | config MAC80211_DEBUG_COUNTERS |
198 | bool "Extra statistics for TX/RX debugging" | 211 | bool "Extra statistics for TX/RX debugging" |
199 | depends on MAC80211_DEBUG_MENU | 212 | depends on MAC80211_DEBUG_MENU |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 56319b51d170..7f18c8fa1880 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -36,6 +36,24 @@ static bool nl80211_type_check(enum nl80211_iftype type) | |||
36 | } | 36 | } |
37 | } | 37 | } |
38 | 38 | ||
39 | static bool nl80211_params_check(enum nl80211_iftype type, | ||
40 | struct vif_params *params) | ||
41 | { | ||
42 | if (!nl80211_type_check(type)) | ||
43 | return false; | ||
44 | |||
45 | if (params->use_4addr > 0) { | ||
46 | switch(type) { | ||
47 | case NL80211_IFTYPE_AP_VLAN: | ||
48 | case NL80211_IFTYPE_STATION: | ||
49 | break; | ||
50 | default: | ||
51 | return false; | ||
52 | } | ||
53 | } | ||
54 | return true; | ||
55 | } | ||
56 | |||
39 | static int ieee80211_add_iface(struct wiphy *wiphy, char *name, | 57 | static int ieee80211_add_iface(struct wiphy *wiphy, char *name, |
40 | enum nl80211_iftype type, u32 *flags, | 58 | enum nl80211_iftype type, u32 *flags, |
41 | struct vif_params *params) | 59 | struct vif_params *params) |
@@ -45,7 +63,7 @@ static int ieee80211_add_iface(struct wiphy *wiphy, char *name, | |||
45 | struct ieee80211_sub_if_data *sdata; | 63 | struct ieee80211_sub_if_data *sdata; |
46 | int err; | 64 | int err; |
47 | 65 | ||
48 | if (!nl80211_type_check(type)) | 66 | if (!nl80211_params_check(type, params)) |
49 | return -EINVAL; | 67 | return -EINVAL; |
50 | 68 | ||
51 | err = ieee80211_if_add(local, name, &dev, type, params); | 69 | err = ieee80211_if_add(local, name, &dev, type, params); |
@@ -75,7 +93,7 @@ static int ieee80211_change_iface(struct wiphy *wiphy, | |||
75 | if (netif_running(dev)) | 93 | if (netif_running(dev)) |
76 | return -EBUSY; | 94 | return -EBUSY; |
77 | 95 | ||
78 | if (!nl80211_type_check(type)) | 96 | if (!nl80211_params_check(type, params)) |
79 | return -EINVAL; | 97 | return -EINVAL; |
80 | 98 | ||
81 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 99 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
@@ -89,6 +107,9 @@ static int ieee80211_change_iface(struct wiphy *wiphy, | |||
89 | params->mesh_id_len, | 107 | params->mesh_id_len, |
90 | params->mesh_id); | 108 | params->mesh_id); |
91 | 109 | ||
110 | if (params->use_4addr >= 0) | ||
111 | sdata->use_4addr = !!params->use_4addr; | ||
112 | |||
92 | if (sdata->vif.type != NL80211_IFTYPE_MONITOR || !flags) | 113 | if (sdata->vif.type != NL80211_IFTYPE_MONITOR || !flags) |
93 | return 0; | 114 | return 0; |
94 | 115 | ||
@@ -806,6 +827,13 @@ static int ieee80211_change_station(struct wiphy *wiphy, | |||
806 | return -EINVAL; | 827 | return -EINVAL; |
807 | } | 828 | } |
808 | 829 | ||
830 | if (vlansdata->use_4addr) { | ||
831 | if (vlansdata->u.vlan.sta) | ||
832 | return -EBUSY; | ||
833 | |||
834 | rcu_assign_pointer(vlansdata->u.vlan.sta, sta); | ||
835 | } | ||
836 | |||
809 | sta->sdata = vlansdata; | 837 | sta->sdata = vlansdata; |
810 | ieee80211_send_layer2_update(sta); | 838 | ieee80211_send_layer2_update(sta); |
811 | } | 839 | } |
@@ -907,7 +935,7 @@ static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop, | |||
907 | pinfo->generation = mesh_paths_generation; | 935 | pinfo->generation = mesh_paths_generation; |
908 | 936 | ||
909 | pinfo->filled = MPATH_INFO_FRAME_QLEN | | 937 | pinfo->filled = MPATH_INFO_FRAME_QLEN | |
910 | MPATH_INFO_DSN | | 938 | MPATH_INFO_SN | |
911 | MPATH_INFO_METRIC | | 939 | MPATH_INFO_METRIC | |
912 | MPATH_INFO_EXPTIME | | 940 | MPATH_INFO_EXPTIME | |
913 | MPATH_INFO_DISCOVERY_TIMEOUT | | 941 | MPATH_INFO_DISCOVERY_TIMEOUT | |
@@ -915,7 +943,7 @@ static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop, | |||
915 | MPATH_INFO_FLAGS; | 943 | MPATH_INFO_FLAGS; |
916 | 944 | ||
917 | pinfo->frame_qlen = mpath->frame_queue.qlen; | 945 | pinfo->frame_qlen = mpath->frame_queue.qlen; |
918 | pinfo->dsn = mpath->dsn; | 946 | pinfo->sn = mpath->sn; |
919 | pinfo->metric = mpath->metric; | 947 | pinfo->metric = mpath->metric; |
920 | if (time_before(jiffies, mpath->exp_time)) | 948 | if (time_before(jiffies, mpath->exp_time)) |
921 | pinfo->exptime = jiffies_to_msecs(mpath->exp_time - jiffies); | 949 | pinfo->exptime = jiffies_to_msecs(mpath->exp_time - jiffies); |
@@ -927,8 +955,8 @@ static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop, | |||
927 | pinfo->flags |= NL80211_MPATH_FLAG_ACTIVE; | 955 | pinfo->flags |= NL80211_MPATH_FLAG_ACTIVE; |
928 | if (mpath->flags & MESH_PATH_RESOLVING) | 956 | if (mpath->flags & MESH_PATH_RESOLVING) |
929 | pinfo->flags |= NL80211_MPATH_FLAG_RESOLVING; | 957 | pinfo->flags |= NL80211_MPATH_FLAG_RESOLVING; |
930 | if (mpath->flags & MESH_PATH_DSN_VALID) | 958 | if (mpath->flags & MESH_PATH_SN_VALID) |
931 | pinfo->flags |= NL80211_MPATH_FLAG_DSN_VALID; | 959 | pinfo->flags |= NL80211_MPATH_FLAG_SN_VALID; |
932 | if (mpath->flags & MESH_PATH_FIXED) | 960 | if (mpath->flags & MESH_PATH_FIXED) |
933 | pinfo->flags |= NL80211_MPATH_FLAG_FIXED; | 961 | pinfo->flags |= NL80211_MPATH_FLAG_FIXED; |
934 | if (mpath->flags & MESH_PATH_RESOLVING) | 962 | if (mpath->flags & MESH_PATH_RESOLVING) |
@@ -1001,7 +1029,10 @@ static int ieee80211_set_mesh_params(struct wiphy *wiphy, | |||
1001 | { | 1029 | { |
1002 | struct mesh_config *conf; | 1030 | struct mesh_config *conf; |
1003 | struct ieee80211_sub_if_data *sdata; | 1031 | struct ieee80211_sub_if_data *sdata; |
1032 | struct ieee80211_if_mesh *ifmsh; | ||
1033 | |||
1004 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1034 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
1035 | ifmsh = &sdata->u.mesh; | ||
1005 | 1036 | ||
1006 | /* Set the config options which we are interested in setting */ | 1037 | /* Set the config options which we are interested in setting */ |
1007 | conf = &(sdata->u.mesh.mshcfg); | 1038 | conf = &(sdata->u.mesh.mshcfg); |
@@ -1036,6 +1067,10 @@ static int ieee80211_set_mesh_params(struct wiphy *wiphy, | |||
1036 | mask)) | 1067 | mask)) |
1037 | conf->dot11MeshHWMPnetDiameterTraversalTime = | 1068 | conf->dot11MeshHWMPnetDiameterTraversalTime = |
1038 | nconf->dot11MeshHWMPnetDiameterTraversalTime; | 1069 | nconf->dot11MeshHWMPnetDiameterTraversalTime; |
1070 | if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_ROOTMODE, mask)) { | ||
1071 | conf->dot11MeshHWMPRootMode = nconf->dot11MeshHWMPRootMode; | ||
1072 | ieee80211_mesh_root_setup(ifmsh); | ||
1073 | } | ||
1039 | return 0; | 1074 | return 0; |
1040 | } | 1075 | } |
1041 | 1076 | ||
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 8782264f49e7..472b2039906c 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c | |||
@@ -149,6 +149,8 @@ IEEE80211_IF_FILE(path_refresh_time, | |||
149 | u.mesh.mshcfg.path_refresh_time, DEC); | 149 | u.mesh.mshcfg.path_refresh_time, DEC); |
150 | IEEE80211_IF_FILE(min_discovery_timeout, | 150 | IEEE80211_IF_FILE(min_discovery_timeout, |
151 | u.mesh.mshcfg.min_discovery_timeout, DEC); | 151 | u.mesh.mshcfg.min_discovery_timeout, DEC); |
152 | IEEE80211_IF_FILE(dot11MeshHWMPRootMode, | ||
153 | u.mesh.mshcfg.dot11MeshHWMPRootMode, DEC); | ||
152 | #endif | 154 | #endif |
153 | 155 | ||
154 | 156 | ||
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 1ef767366b77..b63b99fb2fd3 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -208,6 +208,9 @@ struct ieee80211_if_wds { | |||
208 | 208 | ||
209 | struct ieee80211_if_vlan { | 209 | struct ieee80211_if_vlan { |
210 | struct list_head list; | 210 | struct list_head list; |
211 | |||
212 | /* used for all tx if the VLAN is configured to 4-addr mode */ | ||
213 | struct sta_info *sta; | ||
211 | }; | 214 | }; |
212 | 215 | ||
213 | struct mesh_stats { | 216 | struct mesh_stats { |
@@ -352,6 +355,7 @@ struct ieee80211_if_mesh { | |||
352 | struct work_struct work; | 355 | struct work_struct work; |
353 | struct timer_list housekeeping_timer; | 356 | struct timer_list housekeeping_timer; |
354 | struct timer_list mesh_path_timer; | 357 | struct timer_list mesh_path_timer; |
358 | struct timer_list mesh_path_root_timer; | ||
355 | struct sk_buff_head skb_queue; | 359 | struct sk_buff_head skb_queue; |
356 | 360 | ||
357 | unsigned long timers_running; | 361 | unsigned long timers_running; |
@@ -361,23 +365,23 @@ struct ieee80211_if_mesh { | |||
361 | u8 mesh_id[IEEE80211_MAX_MESH_ID_LEN]; | 365 | u8 mesh_id[IEEE80211_MAX_MESH_ID_LEN]; |
362 | size_t mesh_id_len; | 366 | size_t mesh_id_len; |
363 | /* Active Path Selection Protocol Identifier */ | 367 | /* Active Path Selection Protocol Identifier */ |
364 | u8 mesh_pp_id[4]; | 368 | u8 mesh_pp_id; |
365 | /* Active Path Selection Metric Identifier */ | 369 | /* Active Path Selection Metric Identifier */ |
366 | u8 mesh_pm_id[4]; | 370 | u8 mesh_pm_id; |
367 | /* Congestion Control Mode Identifier */ | 371 | /* Congestion Control Mode Identifier */ |
368 | u8 mesh_cc_id[4]; | 372 | u8 mesh_cc_id; |
369 | /* Synchronization Protocol Identifier */ | 373 | /* Synchronization Protocol Identifier */ |
370 | u8 mesh_sp_id[4]; | 374 | u8 mesh_sp_id; |
371 | /* Authentication Protocol Identifier */ | 375 | /* Authentication Protocol Identifier */ |
372 | u8 mesh_auth_id[4]; | 376 | u8 mesh_auth_id; |
373 | /* Local mesh Destination Sequence Number */ | 377 | /* Local mesh Sequence Number */ |
374 | u32 dsn; | 378 | u32 sn; |
375 | /* Last used PREQ ID */ | 379 | /* Last used PREQ ID */ |
376 | u32 preq_id; | 380 | u32 preq_id; |
377 | atomic_t mpaths; | 381 | atomic_t mpaths; |
378 | /* Timestamp of last DSN update */ | 382 | /* Timestamp of last SN update */ |
379 | unsigned long last_dsn_update; | 383 | unsigned long last_sn_update; |
380 | /* Timestamp of last DSN sent */ | 384 | /* Timestamp of last SN sent */ |
381 | unsigned long last_preq; | 385 | unsigned long last_preq; |
382 | struct mesh_rmc *rmc; | 386 | struct mesh_rmc *rmc; |
383 | spinlock_t mesh_preq_queue_lock; | 387 | spinlock_t mesh_preq_queue_lock; |
@@ -457,6 +461,8 @@ struct ieee80211_sub_if_data { | |||
457 | int force_unicast_rateidx; /* forced TX rateidx for unicast frames */ | 461 | int force_unicast_rateidx; /* forced TX rateidx for unicast frames */ |
458 | int max_ratectrl_rateidx; /* max TX rateidx for rate control */ | 462 | int max_ratectrl_rateidx; /* max TX rateidx for rate control */ |
459 | 463 | ||
464 | bool use_4addr; /* use 4-address frames */ | ||
465 | |||
460 | union { | 466 | union { |
461 | struct ieee80211_if_ap ap; | 467 | struct ieee80211_if_ap ap; |
462 | struct ieee80211_if_wds wds; | 468 | struct ieee80211_if_wds wds; |
@@ -799,6 +805,7 @@ struct ieee802_11_elems { | |||
799 | u8 *preq; | 805 | u8 *preq; |
800 | u8 *prep; | 806 | u8 *prep; |
801 | u8 *perr; | 807 | u8 *perr; |
808 | struct ieee80211_rann_ie *rann; | ||
802 | u8 *ch_switch_elem; | 809 | u8 *ch_switch_elem; |
803 | u8 *country_elem; | 810 | u8 *country_elem; |
804 | u8 *pwr_constr_elem; | 811 | u8 *pwr_constr_elem; |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 8495161b99b8..1f02b0610e82 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -752,6 +752,7 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, | |||
752 | ieee80211_mandatory_rates(sdata->local, | 752 | ieee80211_mandatory_rates(sdata->local, |
753 | sdata->local->hw.conf.channel->band); | 753 | sdata->local->hw.conf.channel->band); |
754 | sdata->drop_unencrypted = 0; | 754 | sdata->drop_unencrypted = 0; |
755 | sdata->use_4addr = 0; | ||
755 | 756 | ||
756 | return 0; | 757 | return 0; |
757 | } | 758 | } |
@@ -819,6 +820,9 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
819 | params->mesh_id_len, | 820 | params->mesh_id_len, |
820 | params->mesh_id); | 821 | params->mesh_id); |
821 | 822 | ||
823 | if (params && params->use_4addr >= 0) | ||
824 | sdata->use_4addr = !!params->use_4addr; | ||
825 | |||
822 | mutex_lock(&local->iflist_mtx); | 826 | mutex_lock(&local->iflist_mtx); |
823 | list_add_tail_rcu(&sdata->list, &local->interfaces); | 827 | list_add_tail_rcu(&sdata->list, &local->interfaces); |
824 | mutex_unlock(&local->iflist_mtx); | 828 | mutex_unlock(&local->iflist_mtx); |
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 9a733890eb47..bbd56b087899 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2008 open80211s Ltd. | 2 | * Copyright (c) 2008, 2009 open80211s Ltd. |
3 | * Authors: Luis Carlos Cobo <luisca@cozybit.com> | 3 | * Authors: Luis Carlos Cobo <luisca@cozybit.com> |
4 | * Javier Cardona <javier@cozybit.com> | 4 | * Javier Cardona <javier@cozybit.com> |
5 | * | 5 | * |
@@ -14,18 +14,20 @@ | |||
14 | 14 | ||
15 | #define IEEE80211_MESH_PEER_INACTIVITY_LIMIT (1800 * HZ) | 15 | #define IEEE80211_MESH_PEER_INACTIVITY_LIMIT (1800 * HZ) |
16 | #define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ) | 16 | #define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ) |
17 | #define IEEE80211_MESH_RANN_INTERVAL (1 * HZ) | ||
17 | 18 | ||
18 | #define PP_OFFSET 1 /* Path Selection Protocol */ | 19 | #define MESHCONF_PP_OFFSET 0 /* Path Selection Protocol */ |
19 | #define PM_OFFSET 5 /* Path Selection Metric */ | 20 | #define MESHCONF_PM_OFFSET 1 /* Path Selection Metric */ |
20 | #define CC_OFFSET 9 /* Congestion Control Mode */ | 21 | #define MESHCONF_CC_OFFSET 2 /* Congestion Control Mode */ |
21 | #define SP_OFFSET 13 /* Synchronization Protocol */ | 22 | #define MESHCONF_SP_OFFSET 3 /* Synchronization Protocol */ |
22 | #define AUTH_OFFSET 17 /* Authentication Protocol */ | 23 | #define MESHCONF_AUTH_OFFSET 4 /* Authentication Protocol */ |
23 | #define CAPAB_OFFSET 22 | 24 | #define MESHCONF_CAPAB_OFFSET 6 |
24 | #define CAPAB_ACCEPT_PLINKS 0x80 | 25 | #define MESHCONF_CAPAB_ACCEPT_PLINKS 0x01 |
25 | #define CAPAB_FORWARDING 0x10 | 26 | #define MESHCONF_CAPAB_FORWARDING 0x08 |
26 | 27 | ||
27 | #define TMR_RUNNING_HK 0 | 28 | #define TMR_RUNNING_HK 0 |
28 | #define TMR_RUNNING_MP 1 | 29 | #define TMR_RUNNING_MP 1 |
30 | #define TMR_RUNNING_MPR 2 | ||
29 | 31 | ||
30 | int mesh_allocated; | 32 | int mesh_allocated; |
31 | static struct kmem_cache *rm_cache; | 33 | static struct kmem_cache *rm_cache; |
@@ -85,11 +87,12 @@ bool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_dat | |||
85 | */ | 87 | */ |
86 | if (ifmsh->mesh_id_len == ie->mesh_id_len && | 88 | if (ifmsh->mesh_id_len == ie->mesh_id_len && |
87 | memcmp(ifmsh->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 && | 89 | memcmp(ifmsh->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 && |
88 | memcmp(ifmsh->mesh_pp_id, ie->mesh_config + PP_OFFSET, 4) == 0 && | 90 | (ifmsh->mesh_pp_id == *(ie->mesh_config + MESHCONF_PP_OFFSET))&& |
89 | memcmp(ifmsh->mesh_pm_id, ie->mesh_config + PM_OFFSET, 4) == 0 && | 91 | (ifmsh->mesh_pm_id == *(ie->mesh_config + MESHCONF_PM_OFFSET))&& |
90 | memcmp(ifmsh->mesh_cc_id, ie->mesh_config + CC_OFFSET, 4) == 0 && | 92 | (ifmsh->mesh_cc_id == *(ie->mesh_config + MESHCONF_CC_OFFSET))&& |
91 | memcmp(ifmsh->mesh_sp_id, ie->mesh_config + SP_OFFSET, 4) == 0 && | 93 | (ifmsh->mesh_sp_id == *(ie->mesh_config + MESHCONF_SP_OFFSET))&& |
92 | memcmp(ifmsh->mesh_auth_id, ie->mesh_config + AUTH_OFFSET, 4) == 0) | 94 | (ifmsh->mesh_auth_id == *(ie->mesh_config + |
95 | MESHCONF_AUTH_OFFSET))) | ||
93 | return true; | 96 | return true; |
94 | 97 | ||
95 | return false; | 98 | return false; |
@@ -102,7 +105,8 @@ bool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_dat | |||
102 | */ | 105 | */ |
103 | bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie) | 106 | bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie) |
104 | { | 107 | { |
105 | return (*(ie->mesh_config + CAPAB_OFFSET) & CAPAB_ACCEPT_PLINKS) != 0; | 108 | return (*(ie->mesh_config + MESHCONF_CAPAB_OFFSET) & |
109 | MESHCONF_CAPAB_ACCEPT_PLINKS) != 0; | ||
106 | } | 110 | } |
107 | 111 | ||
108 | /** | 112 | /** |
@@ -128,18 +132,11 @@ void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata) | |||
128 | 132 | ||
129 | void mesh_ids_set_default(struct ieee80211_if_mesh *sta) | 133 | void mesh_ids_set_default(struct ieee80211_if_mesh *sta) |
130 | { | 134 | { |
131 | u8 oui[3] = {0x00, 0x0F, 0xAC}; | 135 | sta->mesh_pp_id = 0; /* HWMP */ |
132 | 136 | sta->mesh_pm_id = 0; /* Airtime */ | |
133 | memcpy(sta->mesh_pp_id, oui, sizeof(oui)); | 137 | sta->mesh_cc_id = 0; /* Disabled */ |
134 | memcpy(sta->mesh_pm_id, oui, sizeof(oui)); | 138 | sta->mesh_sp_id = 0; /* Neighbor Offset */ |
135 | memcpy(sta->mesh_cc_id, oui, sizeof(oui)); | 139 | sta->mesh_auth_id = 0; /* Disabled */ |
136 | memcpy(sta->mesh_sp_id, oui, sizeof(oui)); | ||
137 | memcpy(sta->mesh_auth_id, oui, sizeof(oui)); | ||
138 | sta->mesh_pp_id[sizeof(oui)] = 0; | ||
139 | sta->mesh_pm_id[sizeof(oui)] = 0; | ||
140 | sta->mesh_cc_id[sizeof(oui)] = 0xff; | ||
141 | sta->mesh_sp_id[sizeof(oui)] = 0xff; | ||
142 | sta->mesh_auth_id[sizeof(oui)] = 0x0; | ||
143 | } | 140 | } |
144 | 141 | ||
145 | int mesh_rmc_init(struct ieee80211_sub_if_data *sdata) | 142 | int mesh_rmc_init(struct ieee80211_sub_if_data *sdata) |
@@ -228,6 +225,7 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) | |||
228 | struct ieee80211_supported_band *sband; | 225 | struct ieee80211_supported_band *sband; |
229 | u8 *pos; | 226 | u8 *pos; |
230 | int len, i, rate; | 227 | int len, i, rate; |
228 | u8 neighbors; | ||
231 | 229 | ||
232 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 230 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
233 | len = sband->n_bitrates; | 231 | len = sband->n_bitrates; |
@@ -251,6 +249,13 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) | |||
251 | } | 249 | } |
252 | } | 250 | } |
253 | 251 | ||
252 | if (sband->band == IEEE80211_BAND_2GHZ) { | ||
253 | pos = skb_put(skb, 2 + 1); | ||
254 | *pos++ = WLAN_EID_DS_PARAMS; | ||
255 | *pos++ = 1; | ||
256 | *pos++ = ieee80211_frequency_to_channel(local->hw.conf.channel->center_freq); | ||
257 | } | ||
258 | |||
254 | pos = skb_put(skb, 2 + sdata->u.mesh.mesh_id_len); | 259 | pos = skb_put(skb, 2 + sdata->u.mesh.mesh_id_len); |
255 | *pos++ = WLAN_EID_MESH_ID; | 260 | *pos++ = WLAN_EID_MESH_ID; |
256 | *pos++ = sdata->u.mesh.mesh_id_len; | 261 | *pos++ = sdata->u.mesh.mesh_id_len; |
@@ -260,37 +265,33 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) | |||
260 | pos = skb_put(skb, 2 + IEEE80211_MESH_CONFIG_LEN); | 265 | pos = skb_put(skb, 2 + IEEE80211_MESH_CONFIG_LEN); |
261 | *pos++ = WLAN_EID_MESH_CONFIG; | 266 | *pos++ = WLAN_EID_MESH_CONFIG; |
262 | *pos++ = IEEE80211_MESH_CONFIG_LEN; | 267 | *pos++ = IEEE80211_MESH_CONFIG_LEN; |
263 | /* Version */ | ||
264 | *pos++ = 1; | ||
265 | 268 | ||
266 | /* Active path selection protocol ID */ | 269 | /* Active path selection protocol ID */ |
267 | memcpy(pos, sdata->u.mesh.mesh_pp_id, 4); | 270 | *pos++ = sdata->u.mesh.mesh_pp_id; |
268 | pos += 4; | ||
269 | 271 | ||
270 | /* Active path selection metric ID */ | 272 | /* Active path selection metric ID */ |
271 | memcpy(pos, sdata->u.mesh.mesh_pm_id, 4); | 273 | *pos++ = sdata->u.mesh.mesh_pm_id; |
272 | pos += 4; | ||
273 | 274 | ||
274 | /* Congestion control mode identifier */ | 275 | /* Congestion control mode identifier */ |
275 | memcpy(pos, sdata->u.mesh.mesh_cc_id, 4); | 276 | *pos++ = sdata->u.mesh.mesh_cc_id; |
276 | pos += 4; | ||
277 | 277 | ||
278 | /* Synchronization protocol identifier */ | 278 | /* Synchronization protocol identifier */ |
279 | memcpy(pos, sdata->u.mesh.mesh_sp_id, 4); | 279 | *pos++ = sdata->u.mesh.mesh_sp_id; |
280 | pos += 4; | ||
281 | 280 | ||
282 | /* Authentication Protocol identifier */ | 281 | /* Authentication Protocol identifier */ |
283 | memcpy(pos, sdata->u.mesh.mesh_auth_id, 4); | 282 | *pos++ = sdata->u.mesh.mesh_auth_id; |
284 | pos += 4; | ||
285 | 283 | ||
286 | /* Mesh Formation Info */ | 284 | /* Mesh Formation Info - number of neighbors */ |
287 | memset(pos, 0x00, 1); | 285 | neighbors = atomic_read(&sdata->u.mesh.mshstats.estab_plinks); |
288 | pos += 1; | 286 | /* Number of neighbor mesh STAs or 15 whichever is smaller */ |
287 | neighbors = (neighbors > 15) ? 15 : neighbors; | ||
288 | *pos++ = neighbors << 1; | ||
289 | 289 | ||
290 | /* Mesh capability */ | 290 | /* Mesh capability */ |
291 | sdata->u.mesh.accepting_plinks = mesh_plink_availables(sdata); | 291 | sdata->u.mesh.accepting_plinks = mesh_plink_availables(sdata); |
292 | *pos = CAPAB_FORWARDING; | 292 | *pos = MESHCONF_CAPAB_FORWARDING; |
293 | *pos++ |= sdata->u.mesh.accepting_plinks ? CAPAB_ACCEPT_PLINKS : 0x00; | 293 | *pos++ |= sdata->u.mesh.accepting_plinks ? |
294 | MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00; | ||
294 | *pos++ = 0x00; | 295 | *pos++ = 0x00; |
295 | 296 | ||
296 | return; | 297 | return; |
@@ -355,6 +356,34 @@ static void ieee80211_mesh_path_timer(unsigned long data) | |||
355 | ieee80211_queue_work(&local->hw, &ifmsh->work); | 356 | ieee80211_queue_work(&local->hw, &ifmsh->work); |
356 | } | 357 | } |
357 | 358 | ||
359 | static void ieee80211_mesh_path_root_timer(unsigned long data) | ||
360 | { | ||
361 | struct ieee80211_sub_if_data *sdata = | ||
362 | (struct ieee80211_sub_if_data *) data; | ||
363 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
364 | struct ieee80211_local *local = sdata->local; | ||
365 | |||
366 | set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags); | ||
367 | |||
368 | if (local->quiescing) { | ||
369 | set_bit(TMR_RUNNING_MPR, &ifmsh->timers_running); | ||
370 | return; | ||
371 | } | ||
372 | |||
373 | ieee80211_queue_work(&local->hw, &ifmsh->work); | ||
374 | } | ||
375 | |||
376 | void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh) | ||
377 | { | ||
378 | if (ifmsh->mshcfg.dot11MeshHWMPRootMode) | ||
379 | set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags); | ||
380 | else { | ||
381 | clear_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags); | ||
382 | /* stop running timer */ | ||
383 | del_timer_sync(&ifmsh->mesh_path_root_timer); | ||
384 | } | ||
385 | } | ||
386 | |||
358 | /** | 387 | /** |
359 | * ieee80211_fill_mesh_addresses - fill addresses of a locally originated mesh frame | 388 | * ieee80211_fill_mesh_addresses - fill addresses of a locally originated mesh frame |
360 | * @hdr: 802.11 frame header | 389 | * @hdr: 802.11 frame header |
@@ -448,6 +477,15 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata, | |||
448 | round_jiffies(jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL)); | 477 | round_jiffies(jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL)); |
449 | } | 478 | } |
450 | 479 | ||
480 | static void ieee80211_mesh_rootpath(struct ieee80211_sub_if_data *sdata) | ||
481 | { | ||
482 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
483 | |||
484 | mesh_path_tx_root_frame(sdata); | ||
485 | mod_timer(&ifmsh->mesh_path_root_timer, | ||
486 | round_jiffies(jiffies + IEEE80211_MESH_RANN_INTERVAL)); | ||
487 | } | ||
488 | |||
451 | #ifdef CONFIG_PM | 489 | #ifdef CONFIG_PM |
452 | void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata) | 490 | void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata) |
453 | { | 491 | { |
@@ -462,6 +500,8 @@ void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata) | |||
462 | set_bit(TMR_RUNNING_HK, &ifmsh->timers_running); | 500 | set_bit(TMR_RUNNING_HK, &ifmsh->timers_running); |
463 | if (del_timer_sync(&ifmsh->mesh_path_timer)) | 501 | if (del_timer_sync(&ifmsh->mesh_path_timer)) |
464 | set_bit(TMR_RUNNING_MP, &ifmsh->timers_running); | 502 | set_bit(TMR_RUNNING_MP, &ifmsh->timers_running); |
503 | if (del_timer_sync(&ifmsh->mesh_path_root_timer)) | ||
504 | set_bit(TMR_RUNNING_MPR, &ifmsh->timers_running); | ||
465 | } | 505 | } |
466 | 506 | ||
467 | void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata) | 507 | void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata) |
@@ -472,6 +512,9 @@ void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata) | |||
472 | add_timer(&ifmsh->housekeeping_timer); | 512 | add_timer(&ifmsh->housekeeping_timer); |
473 | if (test_and_clear_bit(TMR_RUNNING_MP, &ifmsh->timers_running)) | 513 | if (test_and_clear_bit(TMR_RUNNING_MP, &ifmsh->timers_running)) |
474 | add_timer(&ifmsh->mesh_path_timer); | 514 | add_timer(&ifmsh->mesh_path_timer); |
515 | if (test_and_clear_bit(TMR_RUNNING_MPR, &ifmsh->timers_running)) | ||
516 | add_timer(&ifmsh->mesh_path_root_timer); | ||
517 | ieee80211_mesh_root_setup(ifmsh); | ||
475 | } | 518 | } |
476 | #endif | 519 | #endif |
477 | 520 | ||
@@ -481,6 +524,7 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) | |||
481 | struct ieee80211_local *local = sdata->local; | 524 | struct ieee80211_local *local = sdata->local; |
482 | 525 | ||
483 | set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags); | 526 | set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags); |
527 | ieee80211_mesh_root_setup(ifmsh); | ||
484 | ieee80211_queue_work(&local->hw, &ifmsh->work); | 528 | ieee80211_queue_work(&local->hw, &ifmsh->work); |
485 | sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL; | 529 | sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL; |
486 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON | | 530 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON | |
@@ -491,6 +535,7 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) | |||
491 | void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) | 535 | void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) |
492 | { | 536 | { |
493 | del_timer_sync(&sdata->u.mesh.housekeeping_timer); | 537 | del_timer_sync(&sdata->u.mesh.housekeeping_timer); |
538 | del_timer_sync(&sdata->u.mesh.mesh_path_root_timer); | ||
494 | /* | 539 | /* |
495 | * If the timer fired while we waited for it, it will have | 540 | * If the timer fired while we waited for it, it will have |
496 | * requeued the work. Now the work will be running again | 541 | * requeued the work. Now the work will be running again |
@@ -561,7 +606,7 @@ static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata, | |||
561 | struct ieee80211_rx_status *rx_status) | 606 | struct ieee80211_rx_status *rx_status) |
562 | { | 607 | { |
563 | switch (mgmt->u.action.category) { | 608 | switch (mgmt->u.action.category) { |
564 | case PLINK_CATEGORY: | 609 | case MESH_PLINK_CATEGORY: |
565 | mesh_rx_plink_frame(sdata, mgmt, len, rx_status); | 610 | mesh_rx_plink_frame(sdata, mgmt, len, rx_status); |
566 | break; | 611 | break; |
567 | case MESH_PATH_SEL_CATEGORY: | 612 | case MESH_PATH_SEL_CATEGORY: |
@@ -628,6 +673,9 @@ static void ieee80211_mesh_work(struct work_struct *work) | |||
628 | 673 | ||
629 | if (test_and_clear_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags)) | 674 | if (test_and_clear_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags)) |
630 | ieee80211_mesh_housekeeping(sdata, ifmsh); | 675 | ieee80211_mesh_housekeeping(sdata, ifmsh); |
676 | |||
677 | if (test_and_clear_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags)) | ||
678 | ieee80211_mesh_rootpath(sdata); | ||
631 | } | 679 | } |
632 | 680 | ||
633 | void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) | 681 | void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) |
@@ -673,7 +721,7 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata) | |||
673 | MESH_MIN_DISCOVERY_TIMEOUT; | 721 | MESH_MIN_DISCOVERY_TIMEOUT; |
674 | ifmsh->accepting_plinks = true; | 722 | ifmsh->accepting_plinks = true; |
675 | ifmsh->preq_id = 0; | 723 | ifmsh->preq_id = 0; |
676 | ifmsh->dsn = 0; | 724 | ifmsh->sn = 0; |
677 | atomic_set(&ifmsh->mpaths, 0); | 725 | atomic_set(&ifmsh->mpaths, 0); |
678 | mesh_rmc_init(sdata); | 726 | mesh_rmc_init(sdata); |
679 | ifmsh->last_preq = jiffies; | 727 | ifmsh->last_preq = jiffies; |
@@ -684,6 +732,9 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata) | |||
684 | setup_timer(&ifmsh->mesh_path_timer, | 732 | setup_timer(&ifmsh->mesh_path_timer, |
685 | ieee80211_mesh_path_timer, | 733 | ieee80211_mesh_path_timer, |
686 | (unsigned long) sdata); | 734 | (unsigned long) sdata); |
735 | setup_timer(&ifmsh->mesh_path_root_timer, | ||
736 | ieee80211_mesh_path_root_timer, | ||
737 | (unsigned long) sdata); | ||
687 | INIT_LIST_HEAD(&ifmsh->preq_queue.list); | 738 | INIT_LIST_HEAD(&ifmsh->preq_queue.list); |
688 | spin_lock_init(&ifmsh->mesh_preq_queue_lock); | 739 | spin_lock_init(&ifmsh->mesh_preq_queue_lock); |
689 | } | 740 | } |
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index dd1c19319f0a..bd0e1cbb9a1e 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2008 open80211s Ltd. | 2 | * Copyright (c) 2008, 2009 open80211s Ltd. |
3 | * Authors: Luis Carlos Cobo <luisca@cozybit.com> | 3 | * Authors: Luis Carlos Cobo <luisca@cozybit.com> |
4 | * Javier Cardona <javier@cozybit.com> | 4 | * Javier Cardona <javier@cozybit.com> |
5 | * | 5 | * |
@@ -26,7 +26,7 @@ | |||
26 | * | 26 | * |
27 | * @MESH_PATH_ACTIVE: the mesh path can be used for forwarding | 27 | * @MESH_PATH_ACTIVE: the mesh path can be used for forwarding |
28 | * @MESH_PATH_RESOLVING: the discovery process is running for this mesh path | 28 | * @MESH_PATH_RESOLVING: the discovery process is running for this mesh path |
29 | * @MESH_PATH_DSN_VALID: the mesh path contains a valid destination sequence | 29 | * @MESH_PATH_SN_VALID: the mesh path contains a valid destination sequence |
30 | * number | 30 | * number |
31 | * @MESH_PATH_FIXED: the mesh path has been manually set and should not be | 31 | * @MESH_PATH_FIXED: the mesh path has been manually set and should not be |
32 | * modified | 32 | * modified |
@@ -38,7 +38,7 @@ | |||
38 | enum mesh_path_flags { | 38 | enum mesh_path_flags { |
39 | MESH_PATH_ACTIVE = BIT(0), | 39 | MESH_PATH_ACTIVE = BIT(0), |
40 | MESH_PATH_RESOLVING = BIT(1), | 40 | MESH_PATH_RESOLVING = BIT(1), |
41 | MESH_PATH_DSN_VALID = BIT(2), | 41 | MESH_PATH_SN_VALID = BIT(2), |
42 | MESH_PATH_FIXED = BIT(3), | 42 | MESH_PATH_FIXED = BIT(3), |
43 | MESH_PATH_RESOLVED = BIT(4), | 43 | MESH_PATH_RESOLVED = BIT(4), |
44 | }; | 44 | }; |
@@ -53,11 +53,13 @@ enum mesh_path_flags { | |||
53 | * to grow. | 53 | * to grow. |
54 | * @MESH_WORK_GROW_MPP_TABLE: the mesh portals table is full and needs to | 54 | * @MESH_WORK_GROW_MPP_TABLE: the mesh portals table is full and needs to |
55 | * grow | 55 | * grow |
56 | * @MESH_WORK_ROOT: the mesh root station needs to send a frame | ||
56 | */ | 57 | */ |
57 | enum mesh_deferred_task_flags { | 58 | enum mesh_deferred_task_flags { |
58 | MESH_WORK_HOUSEKEEPING, | 59 | MESH_WORK_HOUSEKEEPING, |
59 | MESH_WORK_GROW_MPATH_TABLE, | 60 | MESH_WORK_GROW_MPATH_TABLE, |
60 | MESH_WORK_GROW_MPP_TABLE, | 61 | MESH_WORK_GROW_MPP_TABLE, |
62 | MESH_WORK_ROOT, | ||
61 | }; | 63 | }; |
62 | 64 | ||
63 | /** | 65 | /** |
@@ -70,7 +72,7 @@ enum mesh_deferred_task_flags { | |||
70 | * @timer: mesh path discovery timer | 72 | * @timer: mesh path discovery timer |
71 | * @frame_queue: pending queue for frames sent to this destination while the | 73 | * @frame_queue: pending queue for frames sent to this destination while the |
72 | * path is unresolved | 74 | * path is unresolved |
73 | * @dsn: destination sequence number of the destination | 75 | * @sn: target sequence number |
74 | * @metric: current metric to this destination | 76 | * @metric: current metric to this destination |
75 | * @hop_count: hops to destination | 77 | * @hop_count: hops to destination |
76 | * @exp_time: in jiffies, when the path will expire or when it expired | 78 | * @exp_time: in jiffies, when the path will expire or when it expired |
@@ -94,7 +96,7 @@ struct mesh_path { | |||
94 | struct timer_list timer; | 96 | struct timer_list timer; |
95 | struct sk_buff_head frame_queue; | 97 | struct sk_buff_head frame_queue; |
96 | struct rcu_head rcu; | 98 | struct rcu_head rcu; |
97 | u32 dsn; | 99 | u32 sn; |
98 | u32 metric; | 100 | u32 metric; |
99 | u8 hop_count; | 101 | u8 hop_count; |
100 | unsigned long exp_time; | 102 | unsigned long exp_time; |
@@ -174,7 +176,7 @@ struct mesh_rmc { | |||
174 | #define MESH_CFG_CMP_LEN (IEEE80211_MESH_CONFIG_LEN - 2) | 176 | #define MESH_CFG_CMP_LEN (IEEE80211_MESH_CONFIG_LEN - 2) |
175 | 177 | ||
176 | /* Default values, timeouts in ms */ | 178 | /* Default values, timeouts in ms */ |
177 | #define MESH_TTL 5 | 179 | #define MESH_TTL 31 |
178 | #define MESH_MAX_RETR 3 | 180 | #define MESH_MAX_RETR 3 |
179 | #define MESH_RET_T 100 | 181 | #define MESH_RET_T 100 |
180 | #define MESH_CONF_T 100 | 182 | #define MESH_CONF_T 100 |
@@ -206,8 +208,14 @@ struct mesh_rmc { | |||
206 | #define MESH_MAX_MPATHS 1024 | 208 | #define MESH_MAX_MPATHS 1024 |
207 | 209 | ||
208 | /* Pending ANA approval */ | 210 | /* Pending ANA approval */ |
209 | #define PLINK_CATEGORY 30 | 211 | #define MESH_PLINK_CATEGORY 30 |
210 | #define MESH_PATH_SEL_CATEGORY 32 | 212 | #define MESH_PATH_SEL_CATEGORY 32 |
213 | #define MESH_PATH_SEL_ACTION 0 | ||
214 | |||
215 | /* PERR reason codes */ | ||
216 | #define PEER_RCODE_UNSPECIFIED 11 | ||
217 | #define PERR_RCODE_NO_ROUTE 12 | ||
218 | #define PERR_RCODE_DEST_UNREACH 13 | ||
211 | 219 | ||
212 | /* Public interfaces */ | 220 | /* Public interfaces */ |
213 | /* Various */ | 221 | /* Various */ |
@@ -234,6 +242,7 @@ ieee80211_rx_result | |||
234 | ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); | 242 | ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); |
235 | void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata); | 243 | void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata); |
236 | void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata); | 244 | void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata); |
245 | void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh); | ||
237 | 246 | ||
238 | /* Mesh paths */ | 247 | /* Mesh paths */ |
239 | int mesh_nexthop_lookup(struct sk_buff *skb, | 248 | int mesh_nexthop_lookup(struct sk_buff *skb, |
@@ -274,8 +283,8 @@ void mesh_mpp_table_grow(void); | |||
274 | u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata, | 283 | u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata, |
275 | struct mesh_table *tbl); | 284 | struct mesh_table *tbl); |
276 | /* Mesh paths */ | 285 | /* Mesh paths */ |
277 | int mesh_path_error_tx(u8 *dest, __le32 dest_dsn, u8 *ra, | 286 | int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn, __le16 target_rcode, |
278 | struct ieee80211_sub_if_data *sdata); | 287 | u8 *ra, struct ieee80211_sub_if_data *sdata); |
279 | void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta); | 288 | void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta); |
280 | void mesh_path_flush_pending(struct mesh_path *mpath); | 289 | void mesh_path_flush_pending(struct mesh_path *mpath); |
281 | void mesh_path_tx_pending(struct mesh_path *mpath); | 290 | void mesh_path_tx_pending(struct mesh_path *mpath); |
@@ -288,6 +297,7 @@ void mesh_path_discard_frame(struct sk_buff *skb, | |||
288 | struct ieee80211_sub_if_data *sdata); | 297 | struct ieee80211_sub_if_data *sdata); |
289 | void mesh_path_quiesce(struct ieee80211_sub_if_data *sdata); | 298 | void mesh_path_quiesce(struct ieee80211_sub_if_data *sdata); |
290 | void mesh_path_restart(struct ieee80211_sub_if_data *sdata); | 299 | void mesh_path_restart(struct ieee80211_sub_if_data *sdata); |
300 | void mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata); | ||
291 | 301 | ||
292 | extern int mesh_paths_generation; | 302 | extern int mesh_paths_generation; |
293 | 303 | ||
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 29b82e98effa..5c67e7b8790f 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2008 open80211s Ltd. | 2 | * Copyright (c) 2008, 2009 open80211s Ltd. |
3 | * Author: Luis Carlos Cobo <luisca@cozybit.com> | 3 | * Author: Luis Carlos Cobo <luisca@cozybit.com> |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
@@ -9,6 +9,12 @@ | |||
9 | 9 | ||
10 | #include "mesh.h" | 10 | #include "mesh.h" |
11 | 11 | ||
12 | #ifdef CONFIG_MAC80211_VERBOSE_MHWMP_DEBUG | ||
13 | #define mhwmp_dbg(fmt, args...) printk(KERN_DEBUG "Mesh HWMP: " fmt, ##args) | ||
14 | #else | ||
15 | #define mhwmp_dbg(fmt, args...) do { (void)(0); } while (0) | ||
16 | #endif | ||
17 | |||
12 | #define TEST_FRAME_LEN 8192 | 18 | #define TEST_FRAME_LEN 8192 |
13 | #define MAX_METRIC 0xffffffff | 19 | #define MAX_METRIC 0xffffffff |
14 | #define ARITH_SHIFT 8 | 20 | #define ARITH_SHIFT 8 |
@@ -21,6 +27,12 @@ | |||
21 | #define MP_F_DO 0x1 | 27 | #define MP_F_DO 0x1 |
22 | /* Reply and forward */ | 28 | /* Reply and forward */ |
23 | #define MP_F_RF 0x2 | 29 | #define MP_F_RF 0x2 |
30 | /* Unknown Sequence Number */ | ||
31 | #define MP_F_USN 0x01 | ||
32 | /* Reason code Present */ | ||
33 | #define MP_F_RCODE 0x02 | ||
34 | |||
35 | static void mesh_queue_preq(struct mesh_path *, u8); | ||
24 | 36 | ||
25 | static inline u32 u32_field_get(u8 *preq_elem, int offset, bool ae) | 37 | static inline u32 u32_field_get(u8 *preq_elem, int offset, bool ae) |
26 | { | 38 | { |
@@ -29,6 +41,13 @@ static inline u32 u32_field_get(u8 *preq_elem, int offset, bool ae) | |||
29 | return get_unaligned_le32(preq_elem + offset); | 41 | return get_unaligned_le32(preq_elem + offset); |
30 | } | 42 | } |
31 | 43 | ||
44 | static inline u32 u16_field_get(u8 *preq_elem, int offset, bool ae) | ||
45 | { | ||
46 | if (ae) | ||
47 | offset += 6; | ||
48 | return get_unaligned_le16(preq_elem + offset); | ||
49 | } | ||
50 | |||
32 | /* HWMP IE processing macros */ | 51 | /* HWMP IE processing macros */ |
33 | #define AE_F (1<<6) | 52 | #define AE_F (1<<6) |
34 | #define AE_F_SET(x) (*x & AE_F) | 53 | #define AE_F_SET(x) (*x & AE_F) |
@@ -37,30 +56,33 @@ static inline u32 u32_field_get(u8 *preq_elem, int offset, bool ae) | |||
37 | #define PREQ_IE_TTL(x) (*(x + 2)) | 56 | #define PREQ_IE_TTL(x) (*(x + 2)) |
38 | #define PREQ_IE_PREQ_ID(x) u32_field_get(x, 3, 0) | 57 | #define PREQ_IE_PREQ_ID(x) u32_field_get(x, 3, 0) |
39 | #define PREQ_IE_ORIG_ADDR(x) (x + 7) | 58 | #define PREQ_IE_ORIG_ADDR(x) (x + 7) |
40 | #define PREQ_IE_ORIG_DSN(x) u32_field_get(x, 13, 0); | 59 | #define PREQ_IE_ORIG_SN(x) u32_field_get(x, 13, 0); |
41 | #define PREQ_IE_LIFETIME(x) u32_field_get(x, 17, AE_F_SET(x)); | 60 | #define PREQ_IE_LIFETIME(x) u32_field_get(x, 17, AE_F_SET(x)); |
42 | #define PREQ_IE_METRIC(x) u32_field_get(x, 21, AE_F_SET(x)); | 61 | #define PREQ_IE_METRIC(x) u32_field_get(x, 21, AE_F_SET(x)); |
43 | #define PREQ_IE_DST_F(x) (*(AE_F_SET(x) ? x + 32 : x + 26)) | 62 | #define PREQ_IE_TARGET_F(x) (*(AE_F_SET(x) ? x + 32 : x + 26)) |
44 | #define PREQ_IE_DST_ADDR(x) (AE_F_SET(x) ? x + 33 : x + 27) | 63 | #define PREQ_IE_TARGET_ADDR(x) (AE_F_SET(x) ? x + 33 : x + 27) |
45 | #define PREQ_IE_DST_DSN(x) u32_field_get(x, 33, AE_F_SET(x)); | 64 | #define PREQ_IE_TARGET_SN(x) u32_field_get(x, 33, AE_F_SET(x)); |
46 | 65 | ||
47 | 66 | ||
48 | #define PREP_IE_FLAGS(x) PREQ_IE_FLAGS(x) | 67 | #define PREP_IE_FLAGS(x) PREQ_IE_FLAGS(x) |
49 | #define PREP_IE_HOPCOUNT(x) PREQ_IE_HOPCOUNT(x) | 68 | #define PREP_IE_HOPCOUNT(x) PREQ_IE_HOPCOUNT(x) |
50 | #define PREP_IE_TTL(x) PREQ_IE_TTL(x) | 69 | #define PREP_IE_TTL(x) PREQ_IE_TTL(x) |
51 | #define PREP_IE_ORIG_ADDR(x) (x + 3) | 70 | #define PREP_IE_ORIG_ADDR(x) (x + 3) |
52 | #define PREP_IE_ORIG_DSN(x) u32_field_get(x, 9, 0); | 71 | #define PREP_IE_ORIG_SN(x) u32_field_get(x, 9, 0); |
53 | #define PREP_IE_LIFETIME(x) u32_field_get(x, 13, AE_F_SET(x)); | 72 | #define PREP_IE_LIFETIME(x) u32_field_get(x, 13, AE_F_SET(x)); |
54 | #define PREP_IE_METRIC(x) u32_field_get(x, 17, AE_F_SET(x)); | 73 | #define PREP_IE_METRIC(x) u32_field_get(x, 17, AE_F_SET(x)); |
55 | #define PREP_IE_DST_ADDR(x) (AE_F_SET(x) ? x + 27 : x + 21) | 74 | #define PREP_IE_TARGET_ADDR(x) (AE_F_SET(x) ? x + 27 : x + 21) |
56 | #define PREP_IE_DST_DSN(x) u32_field_get(x, 27, AE_F_SET(x)); | 75 | #define PREP_IE_TARGET_SN(x) u32_field_get(x, 27, AE_F_SET(x)); |
57 | 76 | ||
58 | #define PERR_IE_DST_ADDR(x) (x + 2) | 77 | #define PERR_IE_TTL(x) (*(x)) |
59 | #define PERR_IE_DST_DSN(x) u32_field_get(x, 8, 0); | 78 | #define PERR_IE_TARGET_FLAGS(x) (*(x + 2)) |
79 | #define PERR_IE_TARGET_ADDR(x) (x + 3) | ||
80 | #define PERR_IE_TARGET_SN(x) u32_field_get(x, 9, 0); | ||
81 | #define PERR_IE_TARGET_RCODE(x) u16_field_get(x, 13, 0); | ||
60 | 82 | ||
61 | #define MSEC_TO_TU(x) (x*1000/1024) | 83 | #define MSEC_TO_TU(x) (x*1000/1024) |
62 | #define DSN_GT(x, y) ((long) (y) - (long) (x) < 0) | 84 | #define SN_GT(x, y) ((long) (y) - (long) (x) < 0) |
63 | #define DSN_LT(x, y) ((long) (x) - (long) (y) < 0) | 85 | #define SN_LT(x, y) ((long) (x) - (long) (y) < 0) |
64 | 86 | ||
65 | #define net_traversal_jiffies(s) \ | 87 | #define net_traversal_jiffies(s) \ |
66 | msecs_to_jiffies(s->u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime) | 88 | msecs_to_jiffies(s->u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime) |
@@ -75,13 +97,15 @@ static inline u32 u32_field_get(u8 *preq_elem, int offset, bool ae) | |||
75 | enum mpath_frame_type { | 97 | enum mpath_frame_type { |
76 | MPATH_PREQ = 0, | 98 | MPATH_PREQ = 0, |
77 | MPATH_PREP, | 99 | MPATH_PREP, |
78 | MPATH_PERR | 100 | MPATH_PERR, |
101 | MPATH_RANN | ||
79 | }; | 102 | }; |
80 | 103 | ||
81 | static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, | 104 | static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, |
82 | u8 *orig_addr, __le32 orig_dsn, u8 dst_flags, u8 *dst, | 105 | u8 *orig_addr, __le32 orig_sn, u8 target_flags, u8 *target, |
83 | __le32 dst_dsn, u8 *da, u8 hop_count, u8 ttl, __le32 lifetime, | 106 | __le32 target_sn, u8 *da, u8 hop_count, u8 ttl,__le32 lifetime, |
84 | __le32 metric, __le32 preq_id, struct ieee80211_sub_if_data *sdata) | 107 | __le32 metric, __le32 preq_id, |
108 | struct ieee80211_sub_if_data *sdata) | ||
85 | { | 109 | { |
86 | struct ieee80211_local *local = sdata->local; | 110 | struct ieee80211_local *local = sdata->local; |
87 | struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); | 111 | struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); |
@@ -103,21 +127,30 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, | |||
103 | 127 | ||
104 | memcpy(mgmt->da, da, ETH_ALEN); | 128 | memcpy(mgmt->da, da, ETH_ALEN); |
105 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 129 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); |
106 | /* BSSID is left zeroed, wildcard value */ | 130 | /* BSSID == SA */ |
131 | memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); | ||
107 | mgmt->u.action.category = MESH_PATH_SEL_CATEGORY; | 132 | mgmt->u.action.category = MESH_PATH_SEL_CATEGORY; |
108 | mgmt->u.action.u.mesh_action.action_code = action; | 133 | mgmt->u.action.u.mesh_action.action_code = MESH_PATH_SEL_ACTION; |
109 | 134 | ||
110 | switch (action) { | 135 | switch (action) { |
111 | case MPATH_PREQ: | 136 | case MPATH_PREQ: |
137 | mhwmp_dbg("sending PREQ to %pM\n", target); | ||
112 | ie_len = 37; | 138 | ie_len = 37; |
113 | pos = skb_put(skb, 2 + ie_len); | 139 | pos = skb_put(skb, 2 + ie_len); |
114 | *pos++ = WLAN_EID_PREQ; | 140 | *pos++ = WLAN_EID_PREQ; |
115 | break; | 141 | break; |
116 | case MPATH_PREP: | 142 | case MPATH_PREP: |
143 | mhwmp_dbg("sending PREP to %pM\n", target); | ||
117 | ie_len = 31; | 144 | ie_len = 31; |
118 | pos = skb_put(skb, 2 + ie_len); | 145 | pos = skb_put(skb, 2 + ie_len); |
119 | *pos++ = WLAN_EID_PREP; | 146 | *pos++ = WLAN_EID_PREP; |
120 | break; | 147 | break; |
148 | case MPATH_RANN: | ||
149 | mhwmp_dbg("sending RANN from %pM\n", orig_addr); | ||
150 | ie_len = sizeof(struct ieee80211_rann_ie); | ||
151 | pos = skb_put(skb, 2 + ie_len); | ||
152 | *pos++ = WLAN_EID_RANN; | ||
153 | break; | ||
121 | default: | 154 | default: |
122 | kfree_skb(skb); | 155 | kfree_skb(skb); |
123 | return -ENOTSUPP; | 156 | return -ENOTSUPP; |
@@ -133,20 +166,24 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, | |||
133 | } | 166 | } |
134 | memcpy(pos, orig_addr, ETH_ALEN); | 167 | memcpy(pos, orig_addr, ETH_ALEN); |
135 | pos += ETH_ALEN; | 168 | pos += ETH_ALEN; |
136 | memcpy(pos, &orig_dsn, 4); | 169 | memcpy(pos, &orig_sn, 4); |
137 | pos += 4; | ||
138 | memcpy(pos, &lifetime, 4); | ||
139 | pos += 4; | 170 | pos += 4; |
171 | if (action != MPATH_RANN) { | ||
172 | memcpy(pos, &lifetime, 4); | ||
173 | pos += 4; | ||
174 | } | ||
140 | memcpy(pos, &metric, 4); | 175 | memcpy(pos, &metric, 4); |
141 | pos += 4; | 176 | pos += 4; |
142 | if (action == MPATH_PREQ) { | 177 | if (action == MPATH_PREQ) { |
143 | /* destination count */ | 178 | /* destination count */ |
144 | *pos++ = 1; | 179 | *pos++ = 1; |
145 | *pos++ = dst_flags; | 180 | *pos++ = target_flags; |
181 | } | ||
182 | if (action != MPATH_RANN) { | ||
183 | memcpy(pos, target, ETH_ALEN); | ||
184 | pos += ETH_ALEN; | ||
185 | memcpy(pos, &target_sn, 4); | ||
146 | } | 186 | } |
147 | memcpy(pos, dst, ETH_ALEN); | ||
148 | pos += ETH_ALEN; | ||
149 | memcpy(pos, &dst_dsn, 4); | ||
150 | 187 | ||
151 | ieee80211_tx_skb(sdata, skb, 1); | 188 | ieee80211_tx_skb(sdata, skb, 1); |
152 | return 0; | 189 | return 0; |
@@ -155,11 +192,13 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, | |||
155 | /** | 192 | /** |
156 | * mesh_send_path error - Sends a PERR mesh management frame | 193 | * mesh_send_path error - Sends a PERR mesh management frame |
157 | * | 194 | * |
158 | * @dst: broken destination | 195 | * @target: broken destination |
159 | * @dst_dsn: dsn of the broken destination | 196 | * @target_sn: SN of the broken destination |
197 | * @target_rcode: reason code for this PERR | ||
160 | * @ra: node this frame is addressed to | 198 | * @ra: node this frame is addressed to |
161 | */ | 199 | */ |
162 | int mesh_path_error_tx(u8 *dst, __le32 dst_dsn, u8 *ra, | 200 | int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn, |
201 | __le16 target_rcode, u8 *ra, | ||
163 | struct ieee80211_sub_if_data *sdata) | 202 | struct ieee80211_sub_if_data *sdata) |
164 | { | 203 | { |
165 | struct ieee80211_local *local = sdata->local; | 204 | struct ieee80211_local *local = sdata->local; |
@@ -184,18 +223,30 @@ int mesh_path_error_tx(u8 *dst, __le32 dst_dsn, u8 *ra, | |||
184 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 223 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); |
185 | /* BSSID is left zeroed, wildcard value */ | 224 | /* BSSID is left zeroed, wildcard value */ |
186 | mgmt->u.action.category = MESH_PATH_SEL_CATEGORY; | 225 | mgmt->u.action.category = MESH_PATH_SEL_CATEGORY; |
187 | mgmt->u.action.u.mesh_action.action_code = MPATH_PERR; | 226 | mgmt->u.action.u.mesh_action.action_code = MESH_PATH_SEL_ACTION; |
188 | ie_len = 12; | 227 | ie_len = 15; |
189 | pos = skb_put(skb, 2 + ie_len); | 228 | pos = skb_put(skb, 2 + ie_len); |
190 | *pos++ = WLAN_EID_PERR; | 229 | *pos++ = WLAN_EID_PERR; |
191 | *pos++ = ie_len; | 230 | *pos++ = ie_len; |
192 | /* mode flags, reserved */ | 231 | /* ttl */ |
193 | *pos++ = 0; | 232 | *pos++ = MESH_TTL; |
194 | /* number of destinations */ | 233 | /* number of destinations */ |
195 | *pos++ = 1; | 234 | *pos++ = 1; |
196 | memcpy(pos, dst, ETH_ALEN); | 235 | /* |
236 | * flags bit, bit 1 is unset if we know the sequence number and | ||
237 | * bit 2 is set if we have a reason code | ||
238 | */ | ||
239 | *pos = 0; | ||
240 | if (!target_sn) | ||
241 | *pos |= MP_F_USN; | ||
242 | if (target_rcode) | ||
243 | *pos |= MP_F_RCODE; | ||
244 | pos++; | ||
245 | memcpy(pos, target, ETH_ALEN); | ||
197 | pos += ETH_ALEN; | 246 | pos += ETH_ALEN; |
198 | memcpy(pos, &dst_dsn, 4); | 247 | memcpy(pos, &target_sn, 4); |
248 | pos += 4; | ||
249 | memcpy(pos, &target_rcode, 2); | ||
199 | 250 | ||
200 | ieee80211_tx_skb(sdata, skb, 1); | 251 | ieee80211_tx_skb(sdata, skb, 1); |
201 | return 0; | 252 | return 0; |
@@ -269,18 +320,17 @@ static u32 airtime_link_metric_get(struct ieee80211_local *local, | |||
269 | */ | 320 | */ |
270 | static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, | 321 | static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, |
271 | struct ieee80211_mgmt *mgmt, | 322 | struct ieee80211_mgmt *mgmt, |
272 | u8 *hwmp_ie) | 323 | u8 *hwmp_ie, enum mpath_frame_type action) |
273 | { | 324 | { |
274 | struct ieee80211_local *local = sdata->local; | 325 | struct ieee80211_local *local = sdata->local; |
275 | struct mesh_path *mpath; | 326 | struct mesh_path *mpath; |
276 | struct sta_info *sta; | 327 | struct sta_info *sta; |
277 | bool fresh_info; | 328 | bool fresh_info; |
278 | u8 *orig_addr, *ta; | 329 | u8 *orig_addr, *ta; |
279 | u32 orig_dsn, orig_metric; | 330 | u32 orig_sn, orig_metric; |
280 | unsigned long orig_lifetime, exp_time; | 331 | unsigned long orig_lifetime, exp_time; |
281 | u32 last_hop_metric, new_metric; | 332 | u32 last_hop_metric, new_metric; |
282 | bool process = true; | 333 | bool process = true; |
283 | u8 action = mgmt->u.action.u.mesh_action.action_code; | ||
284 | 334 | ||
285 | rcu_read_lock(); | 335 | rcu_read_lock(); |
286 | sta = sta_info_get(local, mgmt->sa); | 336 | sta = sta_info_get(local, mgmt->sa); |
@@ -296,7 +346,7 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, | |||
296 | switch (action) { | 346 | switch (action) { |
297 | case MPATH_PREQ: | 347 | case MPATH_PREQ: |
298 | orig_addr = PREQ_IE_ORIG_ADDR(hwmp_ie); | 348 | orig_addr = PREQ_IE_ORIG_ADDR(hwmp_ie); |
299 | orig_dsn = PREQ_IE_ORIG_DSN(hwmp_ie); | 349 | orig_sn = PREQ_IE_ORIG_SN(hwmp_ie); |
300 | orig_lifetime = PREQ_IE_LIFETIME(hwmp_ie); | 350 | orig_lifetime = PREQ_IE_LIFETIME(hwmp_ie); |
301 | orig_metric = PREQ_IE_METRIC(hwmp_ie); | 351 | orig_metric = PREQ_IE_METRIC(hwmp_ie); |
302 | break; | 352 | break; |
@@ -309,7 +359,7 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, | |||
309 | * information from both PREQ and PREP frames. | 359 | * information from both PREQ and PREP frames. |
310 | */ | 360 | */ |
311 | orig_addr = PREP_IE_ORIG_ADDR(hwmp_ie); | 361 | orig_addr = PREP_IE_ORIG_ADDR(hwmp_ie); |
312 | orig_dsn = PREP_IE_ORIG_DSN(hwmp_ie); | 362 | orig_sn = PREP_IE_ORIG_SN(hwmp_ie); |
313 | orig_lifetime = PREP_IE_LIFETIME(hwmp_ie); | 363 | orig_lifetime = PREP_IE_LIFETIME(hwmp_ie); |
314 | orig_metric = PREP_IE_METRIC(hwmp_ie); | 364 | orig_metric = PREP_IE_METRIC(hwmp_ie); |
315 | break; | 365 | break; |
@@ -335,9 +385,9 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, | |||
335 | if (mpath->flags & MESH_PATH_FIXED) | 385 | if (mpath->flags & MESH_PATH_FIXED) |
336 | fresh_info = false; | 386 | fresh_info = false; |
337 | else if ((mpath->flags & MESH_PATH_ACTIVE) && | 387 | else if ((mpath->flags & MESH_PATH_ACTIVE) && |
338 | (mpath->flags & MESH_PATH_DSN_VALID)) { | 388 | (mpath->flags & MESH_PATH_SN_VALID)) { |
339 | if (DSN_GT(mpath->dsn, orig_dsn) || | 389 | if (SN_GT(mpath->sn, orig_sn) || |
340 | (mpath->dsn == orig_dsn && | 390 | (mpath->sn == orig_sn && |
341 | action == MPATH_PREQ && | 391 | action == MPATH_PREQ && |
342 | new_metric > mpath->metric)) { | 392 | new_metric > mpath->metric)) { |
343 | process = false; | 393 | process = false; |
@@ -356,9 +406,9 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, | |||
356 | 406 | ||
357 | if (fresh_info) { | 407 | if (fresh_info) { |
358 | mesh_path_assign_nexthop(mpath, sta); | 408 | mesh_path_assign_nexthop(mpath, sta); |
359 | mpath->flags |= MESH_PATH_DSN_VALID; | 409 | mpath->flags |= MESH_PATH_SN_VALID; |
360 | mpath->metric = new_metric; | 410 | mpath->metric = new_metric; |
361 | mpath->dsn = orig_dsn; | 411 | mpath->sn = orig_sn; |
362 | mpath->exp_time = time_after(mpath->exp_time, exp_time) | 412 | mpath->exp_time = time_after(mpath->exp_time, exp_time) |
363 | ? mpath->exp_time : exp_time; | 413 | ? mpath->exp_time : exp_time; |
364 | mesh_path_activate(mpath); | 414 | mesh_path_activate(mpath); |
@@ -397,7 +447,7 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, | |||
397 | 447 | ||
398 | if (fresh_info) { | 448 | if (fresh_info) { |
399 | mesh_path_assign_nexthop(mpath, sta); | 449 | mesh_path_assign_nexthop(mpath, sta); |
400 | mpath->flags &= ~MESH_PATH_DSN_VALID; | 450 | mpath->flags &= ~MESH_PATH_SN_VALID; |
401 | mpath->metric = last_hop_metric; | 451 | mpath->metric = last_hop_metric; |
402 | mpath->exp_time = time_after(mpath->exp_time, exp_time) | 452 | mpath->exp_time = time_after(mpath->exp_time, exp_time) |
403 | ? mpath->exp_time : exp_time; | 453 | ? mpath->exp_time : exp_time; |
@@ -419,44 +469,47 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, | |||
419 | { | 469 | { |
420 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 470 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
421 | struct mesh_path *mpath; | 471 | struct mesh_path *mpath; |
422 | u8 *dst_addr, *orig_addr; | 472 | u8 *target_addr, *orig_addr; |
423 | u8 dst_flags, ttl; | 473 | u8 target_flags, ttl; |
424 | u32 orig_dsn, dst_dsn, lifetime; | 474 | u32 orig_sn, target_sn, lifetime; |
425 | bool reply = false; | 475 | bool reply = false; |
426 | bool forward = true; | 476 | bool forward = true; |
427 | 477 | ||
428 | /* Update destination DSN, if present */ | 478 | /* Update target SN, if present */ |
429 | dst_addr = PREQ_IE_DST_ADDR(preq_elem); | 479 | target_addr = PREQ_IE_TARGET_ADDR(preq_elem); |
430 | orig_addr = PREQ_IE_ORIG_ADDR(preq_elem); | 480 | orig_addr = PREQ_IE_ORIG_ADDR(preq_elem); |
431 | dst_dsn = PREQ_IE_DST_DSN(preq_elem); | 481 | target_sn = PREQ_IE_TARGET_SN(preq_elem); |
432 | orig_dsn = PREQ_IE_ORIG_DSN(preq_elem); | 482 | orig_sn = PREQ_IE_ORIG_SN(preq_elem); |
433 | dst_flags = PREQ_IE_DST_F(preq_elem); | 483 | target_flags = PREQ_IE_TARGET_F(preq_elem); |
434 | 484 | ||
435 | if (memcmp(dst_addr, sdata->dev->dev_addr, ETH_ALEN) == 0) { | 485 | mhwmp_dbg("received PREQ from %pM\n", orig_addr); |
486 | |||
487 | if (memcmp(target_addr, sdata->dev->dev_addr, ETH_ALEN) == 0) { | ||
488 | mhwmp_dbg("PREQ is for us\n"); | ||
436 | forward = false; | 489 | forward = false; |
437 | reply = true; | 490 | reply = true; |
438 | metric = 0; | 491 | metric = 0; |
439 | if (time_after(jiffies, ifmsh->last_dsn_update + | 492 | if (time_after(jiffies, ifmsh->last_sn_update + |
440 | net_traversal_jiffies(sdata)) || | 493 | net_traversal_jiffies(sdata)) || |
441 | time_before(jiffies, ifmsh->last_dsn_update)) { | 494 | time_before(jiffies, ifmsh->last_sn_update)) { |
442 | dst_dsn = ++ifmsh->dsn; | 495 | target_sn = ++ifmsh->sn; |
443 | ifmsh->last_dsn_update = jiffies; | 496 | ifmsh->last_sn_update = jiffies; |
444 | } | 497 | } |
445 | } else { | 498 | } else { |
446 | rcu_read_lock(); | 499 | rcu_read_lock(); |
447 | mpath = mesh_path_lookup(dst_addr, sdata); | 500 | mpath = mesh_path_lookup(target_addr, sdata); |
448 | if (mpath) { | 501 | if (mpath) { |
449 | if ((!(mpath->flags & MESH_PATH_DSN_VALID)) || | 502 | if ((!(mpath->flags & MESH_PATH_SN_VALID)) || |
450 | DSN_LT(mpath->dsn, dst_dsn)) { | 503 | SN_LT(mpath->sn, target_sn)) { |
451 | mpath->dsn = dst_dsn; | 504 | mpath->sn = target_sn; |
452 | mpath->flags |= MESH_PATH_DSN_VALID; | 505 | mpath->flags |= MESH_PATH_SN_VALID; |
453 | } else if ((!(dst_flags & MP_F_DO)) && | 506 | } else if ((!(target_flags & MP_F_DO)) && |
454 | (mpath->flags & MESH_PATH_ACTIVE)) { | 507 | (mpath->flags & MESH_PATH_ACTIVE)) { |
455 | reply = true; | 508 | reply = true; |
456 | metric = mpath->metric; | 509 | metric = mpath->metric; |
457 | dst_dsn = mpath->dsn; | 510 | target_sn = mpath->sn; |
458 | if (dst_flags & MP_F_RF) | 511 | if (target_flags & MP_F_RF) |
459 | dst_flags |= MP_F_DO; | 512 | target_flags |= MP_F_DO; |
460 | else | 513 | else |
461 | forward = false; | 514 | forward = false; |
462 | } | 515 | } |
@@ -467,13 +520,14 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, | |||
467 | if (reply) { | 520 | if (reply) { |
468 | lifetime = PREQ_IE_LIFETIME(preq_elem); | 521 | lifetime = PREQ_IE_LIFETIME(preq_elem); |
469 | ttl = ifmsh->mshcfg.dot11MeshTTL; | 522 | ttl = ifmsh->mshcfg.dot11MeshTTL; |
470 | if (ttl != 0) | 523 | if (ttl != 0) { |
471 | mesh_path_sel_frame_tx(MPATH_PREP, 0, dst_addr, | 524 | mhwmp_dbg("replying to the PREQ\n"); |
472 | cpu_to_le32(dst_dsn), 0, orig_addr, | 525 | mesh_path_sel_frame_tx(MPATH_PREP, 0, target_addr, |
473 | cpu_to_le32(orig_dsn), mgmt->sa, 0, ttl, | 526 | cpu_to_le32(target_sn), 0, orig_addr, |
527 | cpu_to_le32(orig_sn), mgmt->sa, 0, ttl, | ||
474 | cpu_to_le32(lifetime), cpu_to_le32(metric), | 528 | cpu_to_le32(lifetime), cpu_to_le32(metric), |
475 | 0, sdata); | 529 | 0, sdata); |
476 | else | 530 | } else |
477 | ifmsh->mshstats.dropped_frames_ttl++; | 531 | ifmsh->mshstats.dropped_frames_ttl++; |
478 | } | 532 | } |
479 | 533 | ||
@@ -487,13 +541,14 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, | |||
487 | ifmsh->mshstats.dropped_frames_ttl++; | 541 | ifmsh->mshstats.dropped_frames_ttl++; |
488 | return; | 542 | return; |
489 | } | 543 | } |
544 | mhwmp_dbg("forwarding the PREQ from %pM\n", orig_addr); | ||
490 | --ttl; | 545 | --ttl; |
491 | flags = PREQ_IE_FLAGS(preq_elem); | 546 | flags = PREQ_IE_FLAGS(preq_elem); |
492 | preq_id = PREQ_IE_PREQ_ID(preq_elem); | 547 | preq_id = PREQ_IE_PREQ_ID(preq_elem); |
493 | hopcount = PREQ_IE_HOPCOUNT(preq_elem) + 1; | 548 | hopcount = PREQ_IE_HOPCOUNT(preq_elem) + 1; |
494 | mesh_path_sel_frame_tx(MPATH_PREQ, flags, orig_addr, | 549 | mesh_path_sel_frame_tx(MPATH_PREQ, flags, orig_addr, |
495 | cpu_to_le32(orig_dsn), dst_flags, dst_addr, | 550 | cpu_to_le32(orig_sn), target_flags, target_addr, |
496 | cpu_to_le32(dst_dsn), sdata->dev->broadcast, | 551 | cpu_to_le32(target_sn), sdata->dev->broadcast, |
497 | hopcount, ttl, cpu_to_le32(lifetime), | 552 | hopcount, ttl, cpu_to_le32(lifetime), |
498 | cpu_to_le32(metric), cpu_to_le32(preq_id), | 553 | cpu_to_le32(metric), cpu_to_le32(preq_id), |
499 | sdata); | 554 | sdata); |
@@ -508,10 +563,12 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, | |||
508 | u8 *prep_elem, u32 metric) | 563 | u8 *prep_elem, u32 metric) |
509 | { | 564 | { |
510 | struct mesh_path *mpath; | 565 | struct mesh_path *mpath; |
511 | u8 *dst_addr, *orig_addr; | 566 | u8 *target_addr, *orig_addr; |
512 | u8 ttl, hopcount, flags; | 567 | u8 ttl, hopcount, flags; |
513 | u8 next_hop[ETH_ALEN]; | 568 | u8 next_hop[ETH_ALEN]; |
514 | u32 dst_dsn, orig_dsn, lifetime; | 569 | u32 target_sn, orig_sn, lifetime; |
570 | |||
571 | mhwmp_dbg("received PREP from %pM\n", PREP_IE_ORIG_ADDR(prep_elem)); | ||
515 | 572 | ||
516 | /* Note that we divert from the draft nomenclature and denominate | 573 | /* Note that we divert from the draft nomenclature and denominate |
517 | * destination to what the draft refers to as origininator. So in this | 574 | * destination to what the draft refers to as origininator. So in this |
@@ -519,8 +576,8 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, | |||
519 | * which corresponds with the originator of the PREQ which this PREP | 576 | * which corresponds with the originator of the PREQ which this PREP |
520 | * replies | 577 | * replies |
521 | */ | 578 | */ |
522 | dst_addr = PREP_IE_DST_ADDR(prep_elem); | 579 | target_addr = PREP_IE_TARGET_ADDR(prep_elem); |
523 | if (memcmp(dst_addr, sdata->dev->dev_addr, ETH_ALEN) == 0) | 580 | if (memcmp(target_addr, sdata->dev->dev_addr, ETH_ALEN) == 0) |
524 | /* destination, no forwarding required */ | 581 | /* destination, no forwarding required */ |
525 | return; | 582 | return; |
526 | 583 | ||
@@ -531,7 +588,7 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, | |||
531 | } | 588 | } |
532 | 589 | ||
533 | rcu_read_lock(); | 590 | rcu_read_lock(); |
534 | mpath = mesh_path_lookup(dst_addr, sdata); | 591 | mpath = mesh_path_lookup(target_addr, sdata); |
535 | if (mpath) | 592 | if (mpath) |
536 | spin_lock_bh(&mpath->state_lock); | 593 | spin_lock_bh(&mpath->state_lock); |
537 | else | 594 | else |
@@ -547,13 +604,13 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, | |||
547 | lifetime = PREP_IE_LIFETIME(prep_elem); | 604 | lifetime = PREP_IE_LIFETIME(prep_elem); |
548 | hopcount = PREP_IE_HOPCOUNT(prep_elem) + 1; | 605 | hopcount = PREP_IE_HOPCOUNT(prep_elem) + 1; |
549 | orig_addr = PREP_IE_ORIG_ADDR(prep_elem); | 606 | orig_addr = PREP_IE_ORIG_ADDR(prep_elem); |
550 | dst_dsn = PREP_IE_DST_DSN(prep_elem); | 607 | target_sn = PREP_IE_TARGET_SN(prep_elem); |
551 | orig_dsn = PREP_IE_ORIG_DSN(prep_elem); | 608 | orig_sn = PREP_IE_ORIG_SN(prep_elem); |
552 | 609 | ||
553 | mesh_path_sel_frame_tx(MPATH_PREP, flags, orig_addr, | 610 | mesh_path_sel_frame_tx(MPATH_PREP, flags, orig_addr, |
554 | cpu_to_le32(orig_dsn), 0, dst_addr, | 611 | cpu_to_le32(orig_sn), 0, target_addr, |
555 | cpu_to_le32(dst_dsn), mpath->next_hop->sta.addr, hopcount, ttl, | 612 | cpu_to_le32(target_sn), mpath->next_hop->sta.addr, hopcount, |
556 | cpu_to_le32(lifetime), cpu_to_le32(metric), | 613 | ttl, cpu_to_le32(lifetime), cpu_to_le32(metric), |
557 | 0, sdata); | 614 | 0, sdata); |
558 | rcu_read_unlock(); | 615 | rcu_read_unlock(); |
559 | 616 | ||
@@ -570,25 +627,39 @@ fail: | |||
570 | static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata, | 627 | static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata, |
571 | struct ieee80211_mgmt *mgmt, u8 *perr_elem) | 628 | struct ieee80211_mgmt *mgmt, u8 *perr_elem) |
572 | { | 629 | { |
630 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
573 | struct mesh_path *mpath; | 631 | struct mesh_path *mpath; |
574 | u8 *ta, *dst_addr; | 632 | u8 ttl; |
575 | u32 dst_dsn; | 633 | u8 *ta, *target_addr; |
634 | u8 target_flags; | ||
635 | u32 target_sn; | ||
636 | u16 target_rcode; | ||
576 | 637 | ||
577 | ta = mgmt->sa; | 638 | ta = mgmt->sa; |
578 | dst_addr = PERR_IE_DST_ADDR(perr_elem); | 639 | ttl = PERR_IE_TTL(perr_elem); |
579 | dst_dsn = PERR_IE_DST_DSN(perr_elem); | 640 | if (ttl <= 1) { |
641 | ifmsh->mshstats.dropped_frames_ttl++; | ||
642 | return; | ||
643 | } | ||
644 | ttl--; | ||
645 | target_flags = PERR_IE_TARGET_FLAGS(perr_elem); | ||
646 | target_addr = PERR_IE_TARGET_ADDR(perr_elem); | ||
647 | target_sn = PERR_IE_TARGET_SN(perr_elem); | ||
648 | target_rcode = PERR_IE_TARGET_RCODE(perr_elem); | ||
649 | |||
580 | rcu_read_lock(); | 650 | rcu_read_lock(); |
581 | mpath = mesh_path_lookup(dst_addr, sdata); | 651 | mpath = mesh_path_lookup(target_addr, sdata); |
582 | if (mpath) { | 652 | if (mpath) { |
583 | spin_lock_bh(&mpath->state_lock); | 653 | spin_lock_bh(&mpath->state_lock); |
584 | if (mpath->flags & MESH_PATH_ACTIVE && | 654 | if (mpath->flags & MESH_PATH_ACTIVE && |
585 | memcmp(ta, mpath->next_hop->sta.addr, ETH_ALEN) == 0 && | 655 | memcmp(ta, mpath->next_hop->sta.addr, ETH_ALEN) == 0 && |
586 | (!(mpath->flags & MESH_PATH_DSN_VALID) || | 656 | (!(mpath->flags & MESH_PATH_SN_VALID) || |
587 | DSN_GT(dst_dsn, mpath->dsn))) { | 657 | SN_GT(target_sn, mpath->sn))) { |
588 | mpath->flags &= ~MESH_PATH_ACTIVE; | 658 | mpath->flags &= ~MESH_PATH_ACTIVE; |
589 | mpath->dsn = dst_dsn; | 659 | mpath->sn = target_sn; |
590 | spin_unlock_bh(&mpath->state_lock); | 660 | spin_unlock_bh(&mpath->state_lock); |
591 | mesh_path_error_tx(dst_addr, cpu_to_le32(dst_dsn), | 661 | mesh_path_error_tx(ttl, target_addr, cpu_to_le32(target_sn), |
662 | cpu_to_le16(target_rcode), | ||
592 | sdata->dev->broadcast, sdata); | 663 | sdata->dev->broadcast, sdata); |
593 | } else | 664 | } else |
594 | spin_unlock_bh(&mpath->state_lock); | 665 | spin_unlock_bh(&mpath->state_lock); |
@@ -596,6 +667,56 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata, | |||
596 | rcu_read_unlock(); | 667 | rcu_read_unlock(); |
597 | } | 668 | } |
598 | 669 | ||
670 | static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, | ||
671 | struct ieee80211_mgmt *mgmt, | ||
672 | struct ieee80211_rann_ie *rann) | ||
673 | { | ||
674 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
675 | struct mesh_path *mpath; | ||
676 | u8 *ta; | ||
677 | u8 ttl, flags, hopcount; | ||
678 | u8 *orig_addr; | ||
679 | u32 orig_sn, metric; | ||
680 | |||
681 | ta = mgmt->sa; | ||
682 | ttl = rann->rann_ttl; | ||
683 | if (ttl <= 1) { | ||
684 | ifmsh->mshstats.dropped_frames_ttl++; | ||
685 | return; | ||
686 | } | ||
687 | ttl--; | ||
688 | flags = rann->rann_flags; | ||
689 | orig_addr = rann->rann_addr; | ||
690 | orig_sn = rann->rann_seq; | ||
691 | hopcount = rann->rann_hopcount; | ||
692 | hopcount++; | ||
693 | metric = rann->rann_metric; | ||
694 | mhwmp_dbg("received RANN from %pM\n", orig_addr); | ||
695 | |||
696 | rcu_read_lock(); | ||
697 | mpath = mesh_path_lookup(orig_addr, sdata); | ||
698 | if (!mpath) { | ||
699 | mesh_path_add(orig_addr, sdata); | ||
700 | mpath = mesh_path_lookup(orig_addr, sdata); | ||
701 | if (!mpath) { | ||
702 | rcu_read_unlock(); | ||
703 | sdata->u.mesh.mshstats.dropped_frames_no_route++; | ||
704 | return; | ||
705 | } | ||
706 | mesh_queue_preq(mpath, | ||
707 | PREQ_Q_F_START | PREQ_Q_F_REFRESH); | ||
708 | } | ||
709 | if (mpath->sn < orig_sn) { | ||
710 | mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr, | ||
711 | cpu_to_le32(orig_sn), | ||
712 | 0, NULL, 0, sdata->dev->broadcast, | ||
713 | hopcount, ttl, 0, | ||
714 | cpu_to_le32(metric + mpath->metric), | ||
715 | 0, sdata); | ||
716 | mpath->sn = orig_sn; | ||
717 | } | ||
718 | rcu_read_unlock(); | ||
719 | } | ||
599 | 720 | ||
600 | 721 | ||
601 | void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, | 722 | void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, |
@@ -614,34 +735,34 @@ void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, | |||
614 | ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable, | 735 | ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable, |
615 | len - baselen, &elems); | 736 | len - baselen, &elems); |
616 | 737 | ||
617 | switch (mgmt->u.action.u.mesh_action.action_code) { | 738 | if (elems.preq) { |
618 | case MPATH_PREQ: | 739 | if (elems.preq_len != 37) |
619 | if (!elems.preq || elems.preq_len != 37) | ||
620 | /* Right now we support just 1 destination and no AE */ | 740 | /* Right now we support just 1 destination and no AE */ |
621 | return; | 741 | return; |
622 | last_hop_metric = hwmp_route_info_get(sdata, mgmt, elems.preq); | 742 | last_hop_metric = hwmp_route_info_get(sdata, mgmt, elems.preq, |
623 | if (!last_hop_metric) | 743 | MPATH_PREQ); |
624 | return; | 744 | if (last_hop_metric) |
625 | hwmp_preq_frame_process(sdata, mgmt, elems.preq, last_hop_metric); | 745 | hwmp_preq_frame_process(sdata, mgmt, elems.preq, |
626 | break; | 746 | last_hop_metric); |
627 | case MPATH_PREP: | 747 | } |
628 | if (!elems.prep || elems.prep_len != 31) | 748 | if (elems.prep) { |
749 | if (elems.prep_len != 31) | ||
629 | /* Right now we support no AE */ | 750 | /* Right now we support no AE */ |
630 | return; | 751 | return; |
631 | last_hop_metric = hwmp_route_info_get(sdata, mgmt, elems.prep); | 752 | last_hop_metric = hwmp_route_info_get(sdata, mgmt, elems.prep, |
632 | if (!last_hop_metric) | 753 | MPATH_PREP); |
633 | return; | 754 | if (last_hop_metric) |
634 | hwmp_prep_frame_process(sdata, mgmt, elems.prep, last_hop_metric); | 755 | hwmp_prep_frame_process(sdata, mgmt, elems.prep, |
635 | break; | 756 | last_hop_metric); |
636 | case MPATH_PERR: | 757 | } |
637 | if (!elems.perr || elems.perr_len != 12) | 758 | if (elems.perr) { |
759 | if (elems.perr_len != 15) | ||
638 | /* Right now we support only one destination per PERR */ | 760 | /* Right now we support only one destination per PERR */ |
639 | return; | 761 | return; |
640 | hwmp_perr_frame_process(sdata, mgmt, elems.perr); | 762 | hwmp_perr_frame_process(sdata, mgmt, elems.perr); |
641 | default: | ||
642 | return; | ||
643 | } | 763 | } |
644 | 764 | if (elems.rann) | |
765 | hwmp_rann_frame_process(sdata, mgmt, elems.rann); | ||
645 | } | 766 | } |
646 | 767 | ||
647 | /** | 768 | /** |
@@ -661,7 +782,7 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags) | |||
661 | 782 | ||
662 | preq_node = kmalloc(sizeof(struct mesh_preq_queue), GFP_ATOMIC); | 783 | preq_node = kmalloc(sizeof(struct mesh_preq_queue), GFP_ATOMIC); |
663 | if (!preq_node) { | 784 | if (!preq_node) { |
664 | printk(KERN_DEBUG "Mesh HWMP: could not allocate PREQ node\n"); | 785 | mhwmp_dbg("could not allocate PREQ node\n"); |
665 | return; | 786 | return; |
666 | } | 787 | } |
667 | 788 | ||
@@ -670,7 +791,7 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags) | |||
670 | spin_unlock(&ifmsh->mesh_preq_queue_lock); | 791 | spin_unlock(&ifmsh->mesh_preq_queue_lock); |
671 | kfree(preq_node); | 792 | kfree(preq_node); |
672 | if (printk_ratelimit()) | 793 | if (printk_ratelimit()) |
673 | printk(KERN_DEBUG "Mesh HWMP: PREQ node queue full\n"); | 794 | mhwmp_dbg("PREQ node queue full\n"); |
674 | return; | 795 | return; |
675 | } | 796 | } |
676 | 797 | ||
@@ -705,7 +826,7 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata) | |||
705 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 826 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
706 | struct mesh_preq_queue *preq_node; | 827 | struct mesh_preq_queue *preq_node; |
707 | struct mesh_path *mpath; | 828 | struct mesh_path *mpath; |
708 | u8 ttl, dst_flags; | 829 | u8 ttl, target_flags; |
709 | u32 lifetime; | 830 | u32 lifetime; |
710 | 831 | ||
711 | spin_lock_bh(&ifmsh->mesh_preq_queue_lock); | 832 | spin_lock_bh(&ifmsh->mesh_preq_queue_lock); |
@@ -747,11 +868,11 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata) | |||
747 | 868 | ||
748 | ifmsh->last_preq = jiffies; | 869 | ifmsh->last_preq = jiffies; |
749 | 870 | ||
750 | if (time_after(jiffies, ifmsh->last_dsn_update + | 871 | if (time_after(jiffies, ifmsh->last_sn_update + |
751 | net_traversal_jiffies(sdata)) || | 872 | net_traversal_jiffies(sdata)) || |
752 | time_before(jiffies, ifmsh->last_dsn_update)) { | 873 | time_before(jiffies, ifmsh->last_sn_update)) { |
753 | ++ifmsh->dsn; | 874 | ++ifmsh->sn; |
754 | sdata->u.mesh.last_dsn_update = jiffies; | 875 | sdata->u.mesh.last_sn_update = jiffies; |
755 | } | 876 | } |
756 | lifetime = default_lifetime(sdata); | 877 | lifetime = default_lifetime(sdata); |
757 | ttl = sdata->u.mesh.mshcfg.dot11MeshTTL; | 878 | ttl = sdata->u.mesh.mshcfg.dot11MeshTTL; |
@@ -762,14 +883,14 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata) | |||
762 | } | 883 | } |
763 | 884 | ||
764 | if (preq_node->flags & PREQ_Q_F_REFRESH) | 885 | if (preq_node->flags & PREQ_Q_F_REFRESH) |
765 | dst_flags = MP_F_DO; | 886 | target_flags = MP_F_DO; |
766 | else | 887 | else |
767 | dst_flags = MP_F_RF; | 888 | target_flags = MP_F_RF; |
768 | 889 | ||
769 | spin_unlock_bh(&mpath->state_lock); | 890 | spin_unlock_bh(&mpath->state_lock); |
770 | mesh_path_sel_frame_tx(MPATH_PREQ, 0, sdata->dev->dev_addr, | 891 | mesh_path_sel_frame_tx(MPATH_PREQ, 0, sdata->dev->dev_addr, |
771 | cpu_to_le32(ifmsh->dsn), dst_flags, mpath->dst, | 892 | cpu_to_le32(ifmsh->sn), target_flags, mpath->dst, |
772 | cpu_to_le32(mpath->dsn), sdata->dev->broadcast, 0, | 893 | cpu_to_le32(mpath->sn), sdata->dev->broadcast, 0, |
773 | ttl, cpu_to_le32(lifetime), 0, | 894 | ttl, cpu_to_le32(lifetime), 0, |
774 | cpu_to_le32(ifmsh->preq_id++), sdata); | 895 | cpu_to_le32(ifmsh->preq_id++), sdata); |
775 | mod_timer(&mpath->timer, jiffies + mpath->discovery_timeout); | 896 | mod_timer(&mpath->timer, jiffies + mpath->discovery_timeout); |
@@ -796,15 +917,15 @@ int mesh_nexthop_lookup(struct sk_buff *skb, | |||
796 | struct sk_buff *skb_to_free = NULL; | 917 | struct sk_buff *skb_to_free = NULL; |
797 | struct mesh_path *mpath; | 918 | struct mesh_path *mpath; |
798 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 919 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
799 | u8 *dst_addr = hdr->addr3; | 920 | u8 *target_addr = hdr->addr3; |
800 | int err = 0; | 921 | int err = 0; |
801 | 922 | ||
802 | rcu_read_lock(); | 923 | rcu_read_lock(); |
803 | mpath = mesh_path_lookup(dst_addr, sdata); | 924 | mpath = mesh_path_lookup(target_addr, sdata); |
804 | 925 | ||
805 | if (!mpath) { | 926 | if (!mpath) { |
806 | mesh_path_add(dst_addr, sdata); | 927 | mesh_path_add(target_addr, sdata); |
807 | mpath = mesh_path_lookup(dst_addr, sdata); | 928 | mpath = mesh_path_lookup(target_addr, sdata); |
808 | if (!mpath) { | 929 | if (!mpath) { |
809 | sdata->u.mesh.mshstats.dropped_frames_no_route++; | 930 | sdata->u.mesh.mshstats.dropped_frames_no_route++; |
810 | err = -ENOSPC; | 931 | err = -ENOSPC; |
@@ -882,3 +1003,14 @@ void mesh_path_timer(unsigned long data) | |||
882 | endmpathtimer: | 1003 | endmpathtimer: |
883 | rcu_read_unlock(); | 1004 | rcu_read_unlock(); |
884 | } | 1005 | } |
1006 | |||
1007 | void | ||
1008 | mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata) | ||
1009 | { | ||
1010 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
1011 | |||
1012 | mesh_path_sel_frame_tx(MPATH_RANN, 0, sdata->dev->dev_addr, | ||
1013 | cpu_to_le32(++ifmsh->sn), | ||
1014 | 0, NULL, 0, sdata->dev->broadcast, | ||
1015 | 0, MESH_TTL, 0, 0, 0, sdata); | ||
1016 | } | ||
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 751c4d0e2b36..5399e7a9ec6e 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2008 open80211s Ltd. | 2 | * Copyright (c) 2008, 2009 open80211s Ltd. |
3 | * Author: Luis Carlos Cobo <luisca@cozybit.com> | 3 | * Author: Luis Carlos Cobo <luisca@cozybit.com> |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
@@ -463,10 +463,11 @@ void mesh_plink_broken(struct sta_info *sta) | |||
463 | mpath->flags & MESH_PATH_ACTIVE && | 463 | mpath->flags & MESH_PATH_ACTIVE && |
464 | !(mpath->flags & MESH_PATH_FIXED)) { | 464 | !(mpath->flags & MESH_PATH_FIXED)) { |
465 | mpath->flags &= ~MESH_PATH_ACTIVE; | 465 | mpath->flags &= ~MESH_PATH_ACTIVE; |
466 | ++mpath->dsn; | 466 | ++mpath->sn; |
467 | spin_unlock_bh(&mpath->state_lock); | 467 | spin_unlock_bh(&mpath->state_lock); |
468 | mesh_path_error_tx(mpath->dst, | 468 | mesh_path_error_tx(MESH_TTL, mpath->dst, |
469 | cpu_to_le32(mpath->dsn), | 469 | cpu_to_le32(mpath->sn), |
470 | PERR_RCODE_DEST_UNREACH, | ||
470 | sdata->dev->broadcast, sdata); | 471 | sdata->dev->broadcast, sdata); |
471 | } else | 472 | } else |
472 | spin_unlock_bh(&mpath->state_lock); | 473 | spin_unlock_bh(&mpath->state_lock); |
@@ -601,7 +602,7 @@ void mesh_path_discard_frame(struct sk_buff *skb, | |||
601 | { | 602 | { |
602 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 603 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
603 | struct mesh_path *mpath; | 604 | struct mesh_path *mpath; |
604 | u32 dsn = 0; | 605 | u32 sn = 0; |
605 | 606 | ||
606 | if (memcmp(hdr->addr4, sdata->dev->dev_addr, ETH_ALEN) != 0) { | 607 | if (memcmp(hdr->addr4, sdata->dev->dev_addr, ETH_ALEN) != 0) { |
607 | u8 *ra, *da; | 608 | u8 *ra, *da; |
@@ -610,8 +611,9 @@ void mesh_path_discard_frame(struct sk_buff *skb, | |||
610 | ra = hdr->addr1; | 611 | ra = hdr->addr1; |
611 | mpath = mesh_path_lookup(da, sdata); | 612 | mpath = mesh_path_lookup(da, sdata); |
612 | if (mpath) | 613 | if (mpath) |
613 | dsn = ++mpath->dsn; | 614 | sn = ++mpath->sn; |
614 | mesh_path_error_tx(skb->data, cpu_to_le32(dsn), ra, sdata); | 615 | mesh_path_error_tx(MESH_TTL, skb->data, cpu_to_le32(sn), |
616 | PERR_RCODE_NO_ROUTE, ra, sdata); | ||
615 | } | 617 | } |
616 | 618 | ||
617 | kfree_skb(skb); | 619 | kfree_skb(skb); |
@@ -646,7 +648,7 @@ void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop) | |||
646 | { | 648 | { |
647 | spin_lock_bh(&mpath->state_lock); | 649 | spin_lock_bh(&mpath->state_lock); |
648 | mesh_path_assign_nexthop(mpath, next_hop); | 650 | mesh_path_assign_nexthop(mpath, next_hop); |
649 | mpath->dsn = 0xffff; | 651 | mpath->sn = 0xffff; |
650 | mpath->metric = 0; | 652 | mpath->metric = 0; |
651 | mpath->hop_count = 0; | 653 | mpath->hop_count = 0; |
652 | mpath->exp_time = 0; | 654 | mpath->exp_time = 0; |
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index ffcbad75e09b..f21329afdae3 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2008 open80211s Ltd. | 2 | * Copyright (c) 2008, 2009 open80211s Ltd. |
3 | * Author: Luis Carlos Cobo <luisca@cozybit.com> | 3 | * Author: Luis Carlos Cobo <luisca@cozybit.com> |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
@@ -18,9 +18,8 @@ | |||
18 | #define mpl_dbg(fmt, args...) do { (void)(0); } while (0) | 18 | #define mpl_dbg(fmt, args...) do { (void)(0); } while (0) |
19 | #endif | 19 | #endif |
20 | 20 | ||
21 | #define PLINK_GET_FRAME_SUBTYPE(p) (p) | 21 | #define PLINK_GET_LLID(p) (p + 4) |
22 | #define PLINK_GET_LLID(p) (p + 1) | 22 | #define PLINK_GET_PLID(p) (p + 6) |
23 | #define PLINK_GET_PLID(p) (p + 3) | ||
24 | 23 | ||
25 | #define mod_plink_timer(s, t) (mod_timer(&s->plink_timer, \ | 24 | #define mod_plink_timer(s, t) (mod_timer(&s->plink_timer, \ |
26 | jiffies + HZ * t / 1000)) | 25 | jiffies + HZ * t / 1000)) |
@@ -65,6 +64,7 @@ void mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata) | |||
65 | { | 64 | { |
66 | atomic_inc(&sdata->u.mesh.mshstats.estab_plinks); | 65 | atomic_inc(&sdata->u.mesh.mshstats.estab_plinks); |
67 | mesh_accept_plinks_update(sdata); | 66 | mesh_accept_plinks_update(sdata); |
67 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); | ||
68 | } | 68 | } |
69 | 69 | ||
70 | static inline | 70 | static inline |
@@ -72,12 +72,13 @@ void mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata) | |||
72 | { | 72 | { |
73 | atomic_dec(&sdata->u.mesh.mshstats.estab_plinks); | 73 | atomic_dec(&sdata->u.mesh.mshstats.estab_plinks); |
74 | mesh_accept_plinks_update(sdata); | 74 | mesh_accept_plinks_update(sdata); |
75 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); | ||
75 | } | 76 | } |
76 | 77 | ||
77 | /** | 78 | /** |
78 | * mesh_plink_fsm_restart - restart a mesh peer link finite state machine | 79 | * mesh_plink_fsm_restart - restart a mesh peer link finite state machine |
79 | * | 80 | * |
80 | * @sta: mes peer link to restart | 81 | * @sta: mesh peer link to restart |
81 | * | 82 | * |
82 | * Locking: this function must be called holding sta->lock | 83 | * Locking: this function must be called holding sta->lock |
83 | */ | 84 | */ |
@@ -152,6 +153,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
152 | struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); | 153 | struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); |
153 | struct ieee80211_mgmt *mgmt; | 154 | struct ieee80211_mgmt *mgmt; |
154 | bool include_plid = false; | 155 | bool include_plid = false; |
156 | static const u8 meshpeeringproto[] = { 0x00, 0x0F, 0xAC, 0x2A }; | ||
155 | u8 *pos; | 157 | u8 *pos; |
156 | int ie_len; | 158 | int ie_len; |
157 | 159 | ||
@@ -169,7 +171,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
169 | memcpy(mgmt->da, da, ETH_ALEN); | 171 | memcpy(mgmt->da, da, ETH_ALEN); |
170 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 172 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); |
171 | /* BSSID is left zeroed, wildcard value */ | 173 | /* BSSID is left zeroed, wildcard value */ |
172 | mgmt->u.action.category = PLINK_CATEGORY; | 174 | mgmt->u.action.category = MESH_PLINK_CATEGORY; |
173 | mgmt->u.action.u.plink_action.action_code = action; | 175 | mgmt->u.action.u.plink_action.action_code = action; |
174 | 176 | ||
175 | if (action == PLINK_CLOSE) | 177 | if (action == PLINK_CLOSE) |
@@ -179,7 +181,8 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
179 | if (action == PLINK_CONFIRM) { | 181 | if (action == PLINK_CONFIRM) { |
180 | pos = skb_put(skb, 4); | 182 | pos = skb_put(skb, 4); |
181 | /* two-byte status code followed by two-byte AID */ | 183 | /* two-byte status code followed by two-byte AID */ |
182 | memset(pos, 0, 4); | 184 | memset(pos, 0, 2); |
185 | memcpy(pos + 2, &plid, 2); | ||
183 | } | 186 | } |
184 | mesh_mgmt_ies_add(skb, sdata); | 187 | mesh_mgmt_ies_add(skb, sdata); |
185 | } | 188 | } |
@@ -187,18 +190,18 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
187 | /* Add Peer Link Management element */ | 190 | /* Add Peer Link Management element */ |
188 | switch (action) { | 191 | switch (action) { |
189 | case PLINK_OPEN: | 192 | case PLINK_OPEN: |
190 | ie_len = 3; | 193 | ie_len = 6; |
191 | break; | 194 | break; |
192 | case PLINK_CONFIRM: | 195 | case PLINK_CONFIRM: |
193 | ie_len = 5; | 196 | ie_len = 8; |
194 | include_plid = true; | 197 | include_plid = true; |
195 | break; | 198 | break; |
196 | case PLINK_CLOSE: | 199 | case PLINK_CLOSE: |
197 | default: | 200 | default: |
198 | if (!plid) | 201 | if (!plid) |
199 | ie_len = 5; | 202 | ie_len = 8; |
200 | else { | 203 | else { |
201 | ie_len = 7; | 204 | ie_len = 10; |
202 | include_plid = true; | 205 | include_plid = true; |
203 | } | 206 | } |
204 | break; | 207 | break; |
@@ -207,7 +210,8 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
207 | pos = skb_put(skb, 2 + ie_len); | 210 | pos = skb_put(skb, 2 + ie_len); |
208 | *pos++ = WLAN_EID_PEER_LINK; | 211 | *pos++ = WLAN_EID_PEER_LINK; |
209 | *pos++ = ie_len; | 212 | *pos++ = ie_len; |
210 | *pos++ = action; | 213 | memcpy(pos, meshpeeringproto, sizeof(meshpeeringproto)); |
214 | pos += 4; | ||
211 | memcpy(pos, &llid, 2); | 215 | memcpy(pos, &llid, 2); |
212 | if (include_plid) { | 216 | if (include_plid) { |
213 | pos += 2; | 217 | pos += 2; |
@@ -395,6 +399,17 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
395 | u8 ie_len; | 399 | u8 ie_len; |
396 | u8 *baseaddr; | 400 | u8 *baseaddr; |
397 | __le16 plid, llid, reason; | 401 | __le16 plid, llid, reason; |
402 | #ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG | ||
403 | static const char *mplstates[] = { | ||
404 | [PLINK_LISTEN] = "LISTEN", | ||
405 | [PLINK_OPN_SNT] = "OPN-SNT", | ||
406 | [PLINK_OPN_RCVD] = "OPN-RCVD", | ||
407 | [PLINK_CNF_RCVD] = "CNF_RCVD", | ||
408 | [PLINK_ESTAB] = "ESTAB", | ||
409 | [PLINK_HOLDING] = "HOLDING", | ||
410 | [PLINK_BLOCKED] = "BLOCKED" | ||
411 | }; | ||
412 | #endif | ||
398 | 413 | ||
399 | /* need action_code, aux */ | 414 | /* need action_code, aux */ |
400 | if (len < IEEE80211_MIN_ACTION_SIZE + 3) | 415 | if (len < IEEE80211_MIN_ACTION_SIZE + 3) |
@@ -417,12 +432,13 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
417 | return; | 432 | return; |
418 | } | 433 | } |
419 | 434 | ||
420 | ftype = *((u8 *)PLINK_GET_FRAME_SUBTYPE(elems.peer_link)); | 435 | ftype = mgmt->u.action.u.plink_action.action_code; |
421 | ie_len = elems.peer_link_len; | 436 | ie_len = elems.peer_link_len; |
422 | if ((ftype == PLINK_OPEN && ie_len != 3) || | 437 | if ((ftype == PLINK_OPEN && ie_len != 6) || |
423 | (ftype == PLINK_CONFIRM && ie_len != 5) || | 438 | (ftype == PLINK_CONFIRM && ie_len != 8) || |
424 | (ftype == PLINK_CLOSE && ie_len != 5 && ie_len != 7)) { | 439 | (ftype == PLINK_CLOSE && ie_len != 8 && ie_len != 10)) { |
425 | mpl_dbg("Mesh plink: incorrect plink ie length\n"); | 440 | mpl_dbg("Mesh plink: incorrect plink ie length %d %d\n", |
441 | ftype, ie_len); | ||
426 | return; | 442 | return; |
427 | } | 443 | } |
428 | 444 | ||
@@ -434,7 +450,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
434 | * from the point of view of this host. | 450 | * from the point of view of this host. |
435 | */ | 451 | */ |
436 | memcpy(&plid, PLINK_GET_LLID(elems.peer_link), 2); | 452 | memcpy(&plid, PLINK_GET_LLID(elems.peer_link), 2); |
437 | if (ftype == PLINK_CONFIRM || (ftype == PLINK_CLOSE && ie_len == 7)) | 453 | if (ftype == PLINK_CONFIRM || (ftype == PLINK_CLOSE && ie_len == 10)) |
438 | memcpy(&llid, PLINK_GET_PLID(elems.peer_link), 2); | 454 | memcpy(&llid, PLINK_GET_PLID(elems.peer_link), 2); |
439 | 455 | ||
440 | rcu_read_lock(); | 456 | rcu_read_lock(); |
@@ -532,8 +548,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
532 | } | 548 | } |
533 | } | 549 | } |
534 | 550 | ||
535 | mpl_dbg("Mesh plink (peer, state, llid, plid, event): %pM %d %d %d %d\n", | 551 | mpl_dbg("Mesh plink (peer, state, llid, plid, event): %pM %s %d %d %d\n", |
536 | mgmt->sa, sta->plink_state, | 552 | mgmt->sa, mplstates[sta->plink_state], |
537 | le16_to_cpu(sta->llid), le16_to_cpu(sta->plid), | 553 | le16_to_cpu(sta->llid), le16_to_cpu(sta->plid), |
538 | event); | 554 | event); |
539 | reason = 0; | 555 | reason = 0; |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index dcc14e99227c..2af306f67d78 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -1898,7 +1898,6 @@ ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, | |||
1898 | fc = le16_to_cpu(mgmt->frame_control); | 1898 | fc = le16_to_cpu(mgmt->frame_control); |
1899 | 1899 | ||
1900 | switch (fc & IEEE80211_FCTL_STYPE) { | 1900 | switch (fc & IEEE80211_FCTL_STYPE) { |
1901 | case IEEE80211_STYPE_PROBE_REQ: | ||
1902 | case IEEE80211_STYPE_PROBE_RESP: | 1901 | case IEEE80211_STYPE_PROBE_RESP: |
1903 | case IEEE80211_STYPE_BEACON: | 1902 | case IEEE80211_STYPE_BEACON: |
1904 | case IEEE80211_STYPE_AUTH: | 1903 | case IEEE80211_STYPE_AUTH: |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 28316b2a585f..6bce97ee2534 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -507,7 +507,7 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) | |||
507 | 507 | ||
508 | if (ieee80211_is_action(hdr->frame_control)) { | 508 | if (ieee80211_is_action(hdr->frame_control)) { |
509 | mgmt = (struct ieee80211_mgmt *)hdr; | 509 | mgmt = (struct ieee80211_mgmt *)hdr; |
510 | if (mgmt->u.action.category != PLINK_CATEGORY) | 510 | if (mgmt->u.action.category != MESH_PLINK_CATEGORY) |
511 | return RX_DROP_MONITOR; | 511 | return RX_DROP_MONITOR; |
512 | return RX_CONTINUE; | 512 | return RX_CONTINUE; |
513 | } | 513 | } |
@@ -1181,6 +1181,13 @@ __ieee80211_data_to_8023(struct ieee80211_rx_data *rx) | |||
1181 | { | 1181 | { |
1182 | struct net_device *dev = rx->dev; | 1182 | struct net_device *dev = rx->dev; |
1183 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1183 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
1184 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; | ||
1185 | |||
1186 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN && !sdata->use_4addr && | ||
1187 | ieee80211_has_a4(hdr->frame_control)) | ||
1188 | return -1; | ||
1189 | if (sdata->use_4addr && is_multicast_ether_addr(hdr->addr1)) | ||
1190 | return -1; | ||
1184 | 1191 | ||
1185 | return ieee80211_data_to_8023(rx->skb, dev->dev_addr, sdata->vif.type); | 1192 | return ieee80211_data_to_8023(rx->skb, dev->dev_addr, sdata->vif.type); |
1186 | } | 1193 | } |
@@ -1229,7 +1236,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) | |||
1229 | if ((sdata->vif.type == NL80211_IFTYPE_AP || | 1236 | if ((sdata->vif.type == NL80211_IFTYPE_AP || |
1230 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) && | 1237 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) && |
1231 | !(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) && | 1238 | !(sdata->flags & IEEE80211_SDATA_DONT_BRIDGE_PACKETS) && |
1232 | (rx->flags & IEEE80211_RX_RA_MATCH)) { | 1239 | (rx->flags & IEEE80211_RX_RA_MATCH) && !rx->sdata->use_4addr) { |
1233 | if (is_multicast_ether_addr(ehdr->h_dest)) { | 1240 | if (is_multicast_ether_addr(ehdr->h_dest)) { |
1234 | /* | 1241 | /* |
1235 | * send multicast frames both to higher layers in | 1242 | * send multicast frames both to higher layers in |
@@ -1534,6 +1541,7 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx) | |||
1534 | { | 1541 | { |
1535 | struct net_device *dev = rx->dev; | 1542 | struct net_device *dev = rx->dev; |
1536 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; | 1543 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; |
1544 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1537 | __le16 fc = hdr->frame_control; | 1545 | __le16 fc = hdr->frame_control; |
1538 | int err; | 1546 | int err; |
1539 | 1547 | ||
@@ -1543,6 +1551,14 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx) | |||
1543 | if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) | 1551 | if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) |
1544 | return RX_DROP_MONITOR; | 1552 | return RX_DROP_MONITOR; |
1545 | 1553 | ||
1554 | /* | ||
1555 | * Allow the cooked monitor interface of an AP to see 4-addr frames so | ||
1556 | * that a 4-addr station can be detected and moved into a separate VLAN | ||
1557 | */ | ||
1558 | if (ieee80211_has_a4(hdr->frame_control) && | ||
1559 | sdata->vif.type == NL80211_IFTYPE_AP) | ||
1560 | return RX_DROP_MONITOR; | ||
1561 | |||
1546 | err = __ieee80211_data_to_8023(rx); | 1562 | err = __ieee80211_data_to_8023(rx); |
1547 | if (unlikely(err)) | 1563 | if (unlikely(err)) |
1548 | return RX_DROP_UNUSABLE; | 1564 | return RX_DROP_UNUSABLE; |
@@ -1983,7 +1999,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, | |||
1983 | 1999 | ||
1984 | switch (sdata->vif.type) { | 2000 | switch (sdata->vif.type) { |
1985 | case NL80211_IFTYPE_STATION: | 2001 | case NL80211_IFTYPE_STATION: |
1986 | if (!bssid) | 2002 | if (!bssid && !sdata->use_4addr) |
1987 | return 0; | 2003 | return 0; |
1988 | if (!multicast && | 2004 | if (!multicast && |
1989 | compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) { | 2005 | compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) { |
@@ -2425,9 +2441,21 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
2425 | goto drop; | 2441 | goto drop; |
2426 | 2442 | ||
2427 | if (status->flag & RX_FLAG_HT) { | 2443 | if (status->flag & RX_FLAG_HT) { |
2428 | /* rate_idx is MCS index */ | 2444 | /* |
2429 | if (WARN_ON(status->rate_idx < 0 || | 2445 | * rate_idx is MCS index, which can be [0-76] as documented on: |
2430 | status->rate_idx >= 76)) | 2446 | * |
2447 | * http://wireless.kernel.org/en/developers/Documentation/ieee80211/802.11n | ||
2448 | * | ||
2449 | * Anything else would be some sort of driver or hardware error. | ||
2450 | * The driver should catch hardware errors. | ||
2451 | */ | ||
2452 | if (WARN((status->rate_idx < 0 || | ||
2453 | status->rate_idx > 76), | ||
2454 | "Rate marked as an HT rate but passed " | ||
2455 | "status->rate_idx is not " | ||
2456 | "an MCS index [0-76]: %d (0x%02x)\n", | ||
2457 | status->rate_idx, | ||
2458 | status->rate_idx)) | ||
2431 | goto drop; | 2459 | goto drop; |
2432 | /* HT rates are not in the table - use the highest legacy rate | 2460 | /* HT rates are not in the table - use the highest legacy rate |
2433 | * for now since other parts of mac80211 may not yet be fully | 2461 | * for now since other parts of mac80211 may not yet be fully |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index be59456e8a42..396a94806de9 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -509,6 +509,9 @@ static void __sta_info_unlink(struct sta_info **sta) | |||
509 | local->num_sta--; | 509 | local->num_sta--; |
510 | local->sta_generation++; | 510 | local->sta_generation++; |
511 | 511 | ||
512 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
513 | rcu_assign_pointer(sdata->u.vlan.sta, NULL); | ||
514 | |||
512 | if (local->ops->sta_notify) { | 515 | if (local->ops->sta_notify) { |
513 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 516 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
514 | sdata = container_of(sdata->bss, | 517 | sdata = container_of(sdata->bss, |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index bfaa43e096d2..3ad053f6de12 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -1051,7 +1051,10 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, | |||
1051 | 1051 | ||
1052 | hdr = (struct ieee80211_hdr *) skb->data; | 1052 | hdr = (struct ieee80211_hdr *) skb->data; |
1053 | 1053 | ||
1054 | tx->sta = sta_info_get(local, hdr->addr1); | 1054 | if ((sdata->vif.type == NL80211_IFTYPE_AP_VLAN) && sdata->use_4addr) |
1055 | tx->sta = rcu_dereference(sdata->u.vlan.sta); | ||
1056 | if (!tx->sta) | ||
1057 | tx->sta = sta_info_get(local, hdr->addr1); | ||
1055 | 1058 | ||
1056 | if (tx->sta && ieee80211_is_data_qos(hdr->frame_control) && | 1059 | if (tx->sta && ieee80211_is_data_qos(hdr->frame_control) && |
1057 | (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION)) { | 1060 | (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION)) { |
@@ -1613,7 +1616,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1613 | const u8 *encaps_data; | 1616 | const u8 *encaps_data; |
1614 | int encaps_len, skip_header_bytes; | 1617 | int encaps_len, skip_header_bytes; |
1615 | int nh_pos, h_pos; | 1618 | int nh_pos, h_pos; |
1616 | struct sta_info *sta; | 1619 | struct sta_info *sta = NULL; |
1617 | u32 sta_flags = 0; | 1620 | u32 sta_flags = 0; |
1618 | 1621 | ||
1619 | if (unlikely(skb->len < ETH_HLEN)) { | 1622 | if (unlikely(skb->len < ETH_HLEN)) { |
@@ -1630,8 +1633,25 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1630 | fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA); | 1633 | fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA); |
1631 | 1634 | ||
1632 | switch (sdata->vif.type) { | 1635 | switch (sdata->vif.type) { |
1633 | case NL80211_IFTYPE_AP: | ||
1634 | case NL80211_IFTYPE_AP_VLAN: | 1636 | case NL80211_IFTYPE_AP_VLAN: |
1637 | rcu_read_lock(); | ||
1638 | if (sdata->use_4addr) | ||
1639 | sta = rcu_dereference(sdata->u.vlan.sta); | ||
1640 | if (sta) { | ||
1641 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); | ||
1642 | /* RA TA DA SA */ | ||
1643 | memcpy(hdr.addr1, sta->sta.addr, ETH_ALEN); | ||
1644 | memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); | ||
1645 | memcpy(hdr.addr3, skb->data, ETH_ALEN); | ||
1646 | memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); | ||
1647 | hdrlen = 30; | ||
1648 | sta_flags = get_sta_flags(sta); | ||
1649 | } | ||
1650 | rcu_read_unlock(); | ||
1651 | if (sta) | ||
1652 | break; | ||
1653 | /* fall through */ | ||
1654 | case NL80211_IFTYPE_AP: | ||
1635 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); | 1655 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); |
1636 | /* DA BSSID SA */ | 1656 | /* DA BSSID SA */ |
1637 | memcpy(hdr.addr1, skb->data, ETH_ALEN); | 1657 | memcpy(hdr.addr1, skb->data, ETH_ALEN); |
@@ -1705,12 +1725,21 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1705 | break; | 1725 | break; |
1706 | #endif | 1726 | #endif |
1707 | case NL80211_IFTYPE_STATION: | 1727 | case NL80211_IFTYPE_STATION: |
1708 | fc |= cpu_to_le16(IEEE80211_FCTL_TODS); | ||
1709 | /* BSSID SA DA */ | ||
1710 | memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN); | 1728 | memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN); |
1711 | memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); | 1729 | if (sdata->use_4addr && ethertype != ETH_P_PAE) { |
1712 | memcpy(hdr.addr3, skb->data, ETH_ALEN); | 1730 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS); |
1713 | hdrlen = 24; | 1731 | /* RA TA DA SA */ |
1732 | memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); | ||
1733 | memcpy(hdr.addr3, skb->data, ETH_ALEN); | ||
1734 | memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); | ||
1735 | hdrlen = 30; | ||
1736 | } else { | ||
1737 | fc |= cpu_to_le16(IEEE80211_FCTL_TODS); | ||
1738 | /* BSSID SA DA */ | ||
1739 | memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); | ||
1740 | memcpy(hdr.addr3, skb->data, ETH_ALEN); | ||
1741 | hdrlen = 24; | ||
1742 | } | ||
1714 | break; | 1743 | break; |
1715 | case NL80211_IFTYPE_ADHOC: | 1744 | case NL80211_IFTYPE_ADHOC: |
1716 | /* DA SA BSSID */ | 1745 | /* DA SA BSSID */ |
@@ -2119,7 +2148,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
2119 | cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON); | 2148 | cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON); |
2120 | memset(mgmt->da, 0xff, ETH_ALEN); | 2149 | memset(mgmt->da, 0xff, ETH_ALEN); |
2121 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 2150 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); |
2122 | /* BSSID is left zeroed, wildcard value */ | 2151 | memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); |
2123 | mgmt->u.beacon.beacon_int = | 2152 | mgmt->u.beacon.beacon_int = |
2124 | cpu_to_le16(sdata->vif.bss_conf.beacon_int); | 2153 | cpu_to_le16(sdata->vif.bss_conf.beacon_int); |
2125 | mgmt->u.beacon.capab_info = 0x0; /* 0x0 for MPs */ | 2154 | mgmt->u.beacon.capab_info = 0x0; /* 0x0 for MPs */ |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index aedbaaa067e6..da86e1592f8c 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -685,6 +685,10 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, | |||
685 | elems->perr = pos; | 685 | elems->perr = pos; |
686 | elems->perr_len = elen; | 686 | elems->perr_len = elen; |
687 | break; | 687 | break; |
688 | case WLAN_EID_RANN: | ||
689 | if (elen >= sizeof(struct ieee80211_rann_ie)) | ||
690 | elems->rann = (void *)pos; | ||
691 | break; | ||
688 | case WLAN_EID_CHANNEL_SWITCH: | 692 | case WLAN_EID_CHANNEL_SWITCH: |
689 | elems->ch_switch_elem = pos; | 693 | elems->ch_switch_elem = pos; |
690 | elems->ch_switch_elem_len = elen; | 694 | elems->ch_switch_elem_len = elen; |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 8ed62b6c172b..37264d56bace 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -138,6 +138,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { | |||
138 | [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 }, | 138 | [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 }, |
139 | [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 }, | 139 | [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 }, |
140 | [NL80211_ATTR_PID] = { .type = NLA_U32 }, | 140 | [NL80211_ATTR_PID] = { .type = NLA_U32 }, |
141 | [NL80211_ATTR_4ADDR] = { .type = NLA_U8 }, | ||
141 | }; | 142 | }; |
142 | 143 | ||
143 | /* policy for the attributes */ | 144 | /* policy for the attributes */ |
@@ -151,6 +152,26 @@ nl80211_key_policy[NL80211_KEY_MAX + 1] __read_mostly = { | |||
151 | [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG }, | 152 | [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG }, |
152 | }; | 153 | }; |
153 | 154 | ||
155 | /* ifidx get helper */ | ||
156 | static int nl80211_get_ifidx(struct netlink_callback *cb) | ||
157 | { | ||
158 | int res; | ||
159 | |||
160 | res = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, | ||
161 | nl80211_fam.attrbuf, nl80211_fam.maxattr, | ||
162 | nl80211_policy); | ||
163 | if (res) | ||
164 | return res; | ||
165 | |||
166 | if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]) | ||
167 | return -EINVAL; | ||
168 | |||
169 | res = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]); | ||
170 | if (!res) | ||
171 | return -EINVAL; | ||
172 | return res; | ||
173 | } | ||
174 | |||
154 | /* IE validation */ | 175 | /* IE validation */ |
155 | static bool is_valid_ie_attr(const struct nlattr *attr) | 176 | static bool is_valid_ie_attr(const struct nlattr *attr) |
156 | { | 177 | { |
@@ -987,6 +1008,13 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | |||
987 | change = true; | 1008 | change = true; |
988 | } | 1009 | } |
989 | 1010 | ||
1011 | if (info->attrs[NL80211_ATTR_4ADDR]) { | ||
1012 | params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]); | ||
1013 | change = true; | ||
1014 | } else { | ||
1015 | params.use_4addr = -1; | ||
1016 | } | ||
1017 | |||
990 | if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) { | 1018 | if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) { |
991 | if (ntype != NL80211_IFTYPE_MONITOR) { | 1019 | if (ntype != NL80211_IFTYPE_MONITOR) { |
992 | err = -EINVAL; | 1020 | err = -EINVAL; |
@@ -1053,6 +1081,9 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
1053 | params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); | 1081 | params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); |
1054 | } | 1082 | } |
1055 | 1083 | ||
1084 | if (info->attrs[NL80211_ATTR_4ADDR]) | ||
1085 | params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]); | ||
1086 | |||
1056 | err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? | 1087 | err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? |
1057 | info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, | 1088 | info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, |
1058 | &flags); | 1089 | &flags); |
@@ -1682,20 +1713,10 @@ static int nl80211_dump_station(struct sk_buff *skb, | |||
1682 | int sta_idx = cb->args[1]; | 1713 | int sta_idx = cb->args[1]; |
1683 | int err; | 1714 | int err; |
1684 | 1715 | ||
1685 | if (!ifidx) { | 1716 | if (!ifidx) |
1686 | err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, | 1717 | ifidx = nl80211_get_ifidx(cb); |
1687 | nl80211_fam.attrbuf, nl80211_fam.maxattr, | 1718 | if (ifidx < 0) |
1688 | nl80211_policy); | 1719 | return ifidx; |
1689 | if (err) | ||
1690 | return err; | ||
1691 | |||
1692 | if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]) | ||
1693 | return -EINVAL; | ||
1694 | |||
1695 | ifidx = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]); | ||
1696 | if (!ifidx) | ||
1697 | return -EINVAL; | ||
1698 | } | ||
1699 | 1720 | ||
1700 | rtnl_lock(); | 1721 | rtnl_lock(); |
1701 | 1722 | ||
@@ -1800,7 +1821,7 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) | |||
1800 | } | 1821 | } |
1801 | 1822 | ||
1802 | /* | 1823 | /* |
1803 | * Get vlan interface making sure it is on the right wiphy. | 1824 | * Get vlan interface making sure it is running and on the right wiphy. |
1804 | */ | 1825 | */ |
1805 | static int get_vlan(struct genl_info *info, | 1826 | static int get_vlan(struct genl_info *info, |
1806 | struct cfg80211_registered_device *rdev, | 1827 | struct cfg80211_registered_device *rdev, |
@@ -1818,6 +1839,8 @@ static int get_vlan(struct genl_info *info, | |||
1818 | return -EINVAL; | 1839 | return -EINVAL; |
1819 | if ((*vlan)->ieee80211_ptr->wiphy != &rdev->wiphy) | 1840 | if ((*vlan)->ieee80211_ptr->wiphy != &rdev->wiphy) |
1820 | return -EINVAL; | 1841 | return -EINVAL; |
1842 | if (!netif_running(*vlan)) | ||
1843 | return -ENETDOWN; | ||
1821 | } | 1844 | } |
1822 | return 0; | 1845 | return 0; |
1823 | } | 1846 | } |
@@ -2105,9 +2128,9 @@ static int nl80211_send_mpath(struct sk_buff *msg, u32 pid, u32 seq, | |||
2105 | if (pinfo->filled & MPATH_INFO_FRAME_QLEN) | 2128 | if (pinfo->filled & MPATH_INFO_FRAME_QLEN) |
2106 | NLA_PUT_U32(msg, NL80211_MPATH_INFO_FRAME_QLEN, | 2129 | NLA_PUT_U32(msg, NL80211_MPATH_INFO_FRAME_QLEN, |
2107 | pinfo->frame_qlen); | 2130 | pinfo->frame_qlen); |
2108 | if (pinfo->filled & MPATH_INFO_DSN) | 2131 | if (pinfo->filled & MPATH_INFO_SN) |
2109 | NLA_PUT_U32(msg, NL80211_MPATH_INFO_DSN, | 2132 | NLA_PUT_U32(msg, NL80211_MPATH_INFO_SN, |
2110 | pinfo->dsn); | 2133 | pinfo->sn); |
2111 | if (pinfo->filled & MPATH_INFO_METRIC) | 2134 | if (pinfo->filled & MPATH_INFO_METRIC) |
2112 | NLA_PUT_U32(msg, NL80211_MPATH_INFO_METRIC, | 2135 | NLA_PUT_U32(msg, NL80211_MPATH_INFO_METRIC, |
2113 | pinfo->metric); | 2136 | pinfo->metric); |
@@ -2145,20 +2168,10 @@ static int nl80211_dump_mpath(struct sk_buff *skb, | |||
2145 | int path_idx = cb->args[1]; | 2168 | int path_idx = cb->args[1]; |
2146 | int err; | 2169 | int err; |
2147 | 2170 | ||
2148 | if (!ifidx) { | 2171 | if (!ifidx) |
2149 | err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, | 2172 | ifidx = nl80211_get_ifidx(cb); |
2150 | nl80211_fam.attrbuf, nl80211_fam.maxattr, | 2173 | if (ifidx < 0) |
2151 | nl80211_policy); | 2174 | return ifidx; |
2152 | if (err) | ||
2153 | return err; | ||
2154 | |||
2155 | if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]) | ||
2156 | return -EINVAL; | ||
2157 | |||
2158 | ifidx = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]); | ||
2159 | if (!ifidx) | ||
2160 | return -EINVAL; | ||
2161 | } | ||
2162 | 2175 | ||
2163 | rtnl_lock(); | 2176 | rtnl_lock(); |
2164 | 2177 | ||
@@ -2605,6 +2618,8 @@ static int nl80211_get_mesh_params(struct sk_buff *skb, | |||
2605 | cur_params.dot11MeshHWMPpreqMinInterval); | 2618 | cur_params.dot11MeshHWMPpreqMinInterval); |
2606 | NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, | 2619 | NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, |
2607 | cur_params.dot11MeshHWMPnetDiameterTraversalTime); | 2620 | cur_params.dot11MeshHWMPnetDiameterTraversalTime); |
2621 | NLA_PUT_U8(msg, NL80211_MESHCONF_HWMP_ROOTMODE, | ||
2622 | cur_params.dot11MeshHWMPRootMode); | ||
2608 | nla_nest_end(msg, pinfoattr); | 2623 | nla_nest_end(msg, pinfoattr); |
2609 | genlmsg_end(msg, hdr); | 2624 | genlmsg_end(msg, hdr); |
2610 | err = genlmsg_reply(msg, info); | 2625 | err = genlmsg_reply(msg, info); |
@@ -2715,6 +2730,10 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) | |||
2715 | dot11MeshHWMPnetDiameterTraversalTime, | 2730 | dot11MeshHWMPnetDiameterTraversalTime, |
2716 | mask, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, | 2731 | mask, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, |
2717 | nla_get_u16); | 2732 | nla_get_u16); |
2733 | FILL_IN_MESH_PARAM_IF_SET(tb, cfg, | ||
2734 | dot11MeshHWMPRootMode, mask, | ||
2735 | NL80211_MESHCONF_HWMP_ROOTMODE, | ||
2736 | nla_get_u8); | ||
2718 | 2737 | ||
2719 | /* Apply changes */ | 2738 | /* Apply changes */ |
2720 | err = rdev->ops->set_mesh_params(&rdev->wiphy, dev, &cfg, mask); | 2739 | err = rdev->ops->set_mesh_params(&rdev->wiphy, dev, &cfg, mask); |
@@ -3181,21 +3200,11 @@ static int nl80211_dump_scan(struct sk_buff *skb, | |||
3181 | int start = cb->args[1], idx = 0; | 3200 | int start = cb->args[1], idx = 0; |
3182 | int err; | 3201 | int err; |
3183 | 3202 | ||
3184 | if (!ifidx) { | 3203 | if (!ifidx) |
3185 | err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize, | 3204 | ifidx = nl80211_get_ifidx(cb); |
3186 | nl80211_fam.attrbuf, nl80211_fam.maxattr, | 3205 | if (ifidx < 0) |
3187 | nl80211_policy); | 3206 | return ifidx; |
3188 | if (err) | 3207 | cb->args[0] = ifidx; |
3189 | return err; | ||
3190 | |||
3191 | if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]) | ||
3192 | return -EINVAL; | ||
3193 | |||
3194 | ifidx = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]); | ||
3195 | if (!ifidx) | ||
3196 | return -EINVAL; | ||
3197 | cb->args[0] = ifidx; | ||
3198 | } | ||
3199 | 3208 | ||
3200 | dev = dev_get_by_index(sock_net(skb->sk), ifidx); | 3209 | dev = dev_get_by_index(sock_net(skb->sk), ifidx); |
3201 | if (!dev) | 3210 | if (!dev) |
@@ -3238,6 +3247,106 @@ static int nl80211_dump_scan(struct sk_buff *skb, | |||
3238 | return err; | 3247 | return err; |
3239 | } | 3248 | } |
3240 | 3249 | ||
3250 | static int nl80211_send_survey(struct sk_buff *msg, u32 pid, u32 seq, | ||
3251 | int flags, struct net_device *dev, | ||
3252 | struct survey_info *survey) | ||
3253 | { | ||
3254 | void *hdr; | ||
3255 | struct nlattr *infoattr; | ||
3256 | |||
3257 | /* Survey without a channel doesn't make sense */ | ||
3258 | if (!survey->channel) | ||
3259 | return -EINVAL; | ||
3260 | |||
3261 | hdr = nl80211hdr_put(msg, pid, seq, flags, | ||
3262 | NL80211_CMD_NEW_SURVEY_RESULTS); | ||
3263 | if (!hdr) | ||
3264 | return -ENOMEM; | ||
3265 | |||
3266 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); | ||
3267 | |||
3268 | infoattr = nla_nest_start(msg, NL80211_ATTR_SURVEY_INFO); | ||
3269 | if (!infoattr) | ||
3270 | goto nla_put_failure; | ||
3271 | |||
3272 | NLA_PUT_U32(msg, NL80211_SURVEY_INFO_FREQUENCY, | ||
3273 | survey->channel->center_freq); | ||
3274 | if (survey->filled & SURVEY_INFO_NOISE_DBM) | ||
3275 | NLA_PUT_U8(msg, NL80211_SURVEY_INFO_NOISE, | ||
3276 | survey->noise); | ||
3277 | |||
3278 | nla_nest_end(msg, infoattr); | ||
3279 | |||
3280 | return genlmsg_end(msg, hdr); | ||
3281 | |||
3282 | nla_put_failure: | ||
3283 | genlmsg_cancel(msg, hdr); | ||
3284 | return -EMSGSIZE; | ||
3285 | } | ||
3286 | |||
3287 | static int nl80211_dump_survey(struct sk_buff *skb, | ||
3288 | struct netlink_callback *cb) | ||
3289 | { | ||
3290 | struct survey_info survey; | ||
3291 | struct cfg80211_registered_device *dev; | ||
3292 | struct net_device *netdev; | ||
3293 | int ifidx = cb->args[0]; | ||
3294 | int survey_idx = cb->args[1]; | ||
3295 | int res; | ||
3296 | |||
3297 | if (!ifidx) | ||
3298 | ifidx = nl80211_get_ifidx(cb); | ||
3299 | if (ifidx < 0) | ||
3300 | return ifidx; | ||
3301 | cb->args[0] = ifidx; | ||
3302 | |||
3303 | rtnl_lock(); | ||
3304 | |||
3305 | netdev = __dev_get_by_index(sock_net(skb->sk), ifidx); | ||
3306 | if (!netdev) { | ||
3307 | res = -ENODEV; | ||
3308 | goto out_rtnl; | ||
3309 | } | ||
3310 | |||
3311 | dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx); | ||
3312 | if (IS_ERR(dev)) { | ||
3313 | res = PTR_ERR(dev); | ||
3314 | goto out_rtnl; | ||
3315 | } | ||
3316 | |||
3317 | if (!dev->ops->dump_survey) { | ||
3318 | res = -EOPNOTSUPP; | ||
3319 | goto out_err; | ||
3320 | } | ||
3321 | |||
3322 | while (1) { | ||
3323 | res = dev->ops->dump_survey(&dev->wiphy, netdev, survey_idx, | ||
3324 | &survey); | ||
3325 | if (res == -ENOENT) | ||
3326 | break; | ||
3327 | if (res) | ||
3328 | goto out_err; | ||
3329 | |||
3330 | if (nl80211_send_survey(skb, | ||
3331 | NETLINK_CB(cb->skb).pid, | ||
3332 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | ||
3333 | netdev, | ||
3334 | &survey) < 0) | ||
3335 | goto out; | ||
3336 | survey_idx++; | ||
3337 | } | ||
3338 | |||
3339 | out: | ||
3340 | cb->args[1] = survey_idx; | ||
3341 | res = skb->len; | ||
3342 | out_err: | ||
3343 | cfg80211_unlock_rdev(dev); | ||
3344 | out_rtnl: | ||
3345 | rtnl_unlock(); | ||
3346 | |||
3347 | return res; | ||
3348 | } | ||
3349 | |||
3241 | static bool nl80211_valid_auth_type(enum nl80211_auth_type auth_type) | 3350 | static bool nl80211_valid_auth_type(enum nl80211_auth_type auth_type) |
3242 | { | 3351 | { |
3243 | return auth_type <= NL80211_AUTHTYPE_MAX; | 3352 | return auth_type <= NL80211_AUTHTYPE_MAX; |
@@ -4315,6 +4424,11 @@ static struct genl_ops nl80211_ops[] = { | |||
4315 | .policy = nl80211_policy, | 4424 | .policy = nl80211_policy, |
4316 | .flags = GENL_ADMIN_PERM, | 4425 | .flags = GENL_ADMIN_PERM, |
4317 | }, | 4426 | }, |
4427 | { | ||
4428 | .cmd = NL80211_CMD_GET_SURVEY, | ||
4429 | .policy = nl80211_policy, | ||
4430 | .dumpit = nl80211_dump_survey, | ||
4431 | }, | ||
4318 | }; | 4432 | }; |
4319 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 4433 | static struct genl_multicast_group nl80211_mlme_mcgrp = { |
4320 | .name = "mlme", | 4434 | .name = "mlme", |
diff --git a/net/wireless/util.c b/net/wireless/util.c index 3fc2df86278f..5aa39f7cf9b9 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -320,7 +320,9 @@ int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr, | |||
320 | break; | 320 | break; |
321 | case cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS): | 321 | case cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS): |
322 | if (unlikely(iftype != NL80211_IFTYPE_WDS && | 322 | if (unlikely(iftype != NL80211_IFTYPE_WDS && |
323 | iftype != NL80211_IFTYPE_MESH_POINT)) | 323 | iftype != NL80211_IFTYPE_MESH_POINT && |
324 | iftype != NL80211_IFTYPE_AP_VLAN && | ||
325 | iftype != NL80211_IFTYPE_STATION)) | ||
324 | return -1; | 326 | return -1; |
325 | if (iftype == NL80211_IFTYPE_MESH_POINT) { | 327 | if (iftype == NL80211_IFTYPE_MESH_POINT) { |
326 | struct ieee80211s_hdr *meshdr = | 328 | struct ieee80211s_hdr *meshdr = |