Commit 095de01325962e7574d5793193c6f3ae9a175aab
Committed by
John W. Linville
1 parent
0938393f02
Exists in
master
and in
7 other branches
mac80211: update the format of path selection frames
Update the format of path selection frames according to latest draft (3.03). Signed-off-by: Rui Paulo <rpaulo@gmail.com> Signed-off-by: Javier Cardona <javier@cozybit.com> Reviewed-by: Andrey Yurovsky <andrey@cozybit.com> Tested-by: Brian Cavagnolo <brian@cozybit.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Showing 2 changed files with 2 additions and 1 deletions Inline Diff
net/mac80211/mesh.h
1 | /* | 1 | /* |
2 | * Copyright (c) 2008 open80211s Ltd. | 2 | * Copyright (c) 2008 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 | * |
6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License version 2 as | 7 | * it under the terms of the GNU General Public License version 2 as |
8 | * published by the Free Software Foundation. | 8 | * published by the Free Software Foundation. |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #ifndef IEEE80211S_H | 11 | #ifndef IEEE80211S_H |
12 | #define IEEE80211S_H | 12 | #define IEEE80211S_H |
13 | 13 | ||
14 | #include <linux/types.h> | 14 | #include <linux/types.h> |
15 | #include <linux/jhash.h> | 15 | #include <linux/jhash.h> |
16 | #include <asm/unaligned.h> | 16 | #include <asm/unaligned.h> |
17 | #include "ieee80211_i.h" | 17 | #include "ieee80211_i.h" |
18 | 18 | ||
19 | 19 | ||
20 | /* Data structures */ | 20 | /* Data structures */ |
21 | 21 | ||
22 | /** | 22 | /** |
23 | * enum mesh_path_flags - mac80211 mesh path flags | 23 | * enum mesh_path_flags - mac80211 mesh path flags |
24 | * | 24 | * |
25 | * | 25 | * |
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_DSN_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 |
33 | * @MESH_PATH_RESOLVED: the mesh path can has been resolved | 33 | * @MESH_PATH_RESOLVED: the mesh path can has been resolved |
34 | * | 34 | * |
35 | * MESH_PATH_RESOLVED is used by the mesh path timer to | 35 | * MESH_PATH_RESOLVED is used by the mesh path timer to |
36 | * decide when to stop or cancel the mesh path discovery. | 36 | * decide when to stop or cancel the mesh path discovery. |
37 | */ | 37 | */ |
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_DSN_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 | }; |
45 | 45 | ||
46 | /** | 46 | /** |
47 | * enum mesh_deferred_task_flags - mac80211 mesh deferred tasks | 47 | * enum mesh_deferred_task_flags - mac80211 mesh deferred tasks |
48 | * | 48 | * |
49 | * | 49 | * |
50 | * | 50 | * |
51 | * @MESH_WORK_HOUSEKEEPING: run the periodic mesh housekeeping tasks | 51 | * @MESH_WORK_HOUSEKEEPING: run the periodic mesh housekeeping tasks |
52 | * @MESH_WORK_GROW_MPATH_TABLE: the mesh path table is full and needs | 52 | * @MESH_WORK_GROW_MPATH_TABLE: the mesh path table is full and needs |
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 | */ | 56 | */ |
57 | enum mesh_deferred_task_flags { | 57 | enum mesh_deferred_task_flags { |
58 | MESH_WORK_HOUSEKEEPING, | 58 | MESH_WORK_HOUSEKEEPING, |
59 | MESH_WORK_GROW_MPATH_TABLE, | 59 | MESH_WORK_GROW_MPATH_TABLE, |
60 | MESH_WORK_GROW_MPP_TABLE, | 60 | MESH_WORK_GROW_MPP_TABLE, |
61 | }; | 61 | }; |
62 | 62 | ||
63 | /** | 63 | /** |
64 | * struct mesh_path - mac80211 mesh path structure | 64 | * struct mesh_path - mac80211 mesh path structure |
65 | * | 65 | * |
66 | * @dst: mesh path destination mac address | 66 | * @dst: mesh path destination mac address |
67 | * @sdata: mesh subif | 67 | * @sdata: mesh subif |
68 | * @next_hop: mesh neighbor to which frames for this destination will be | 68 | * @next_hop: mesh neighbor to which frames for this destination will be |
69 | * forwarded | 69 | * forwarded |
70 | * @timer: mesh path discovery timer | 70 | * @timer: mesh path discovery timer |
71 | * @frame_queue: pending queue for frames sent to this destination while the | 71 | * @frame_queue: pending queue for frames sent to this destination while the |
72 | * path is unresolved | 72 | * path is unresolved |
73 | * @dsn: destination sequence number of the destination | 73 | * @dsn: destination sequence number of the destination |
74 | * @metric: current metric to this destination | 74 | * @metric: current metric to this destination |
75 | * @hop_count: hops to destination | 75 | * @hop_count: hops to destination |
76 | * @exp_time: in jiffies, when the path will expire or when it expired | 76 | * @exp_time: in jiffies, when the path will expire or when it expired |
77 | * @discovery_timeout: timeout (lapse in jiffies) used for the last discovery | 77 | * @discovery_timeout: timeout (lapse in jiffies) used for the last discovery |
78 | * retry | 78 | * retry |
79 | * @discovery_retries: number of discovery retries | 79 | * @discovery_retries: number of discovery retries |
80 | * @flags: mesh path flags, as specified on &enum mesh_path_flags | 80 | * @flags: mesh path flags, as specified on &enum mesh_path_flags |
81 | * @state_lock: mesh path state lock | 81 | * @state_lock: mesh path state lock |
82 | * | 82 | * |
83 | * | 83 | * |
84 | * The combination of dst and sdata is unique in the mesh path table. Since the | 84 | * The combination of dst and sdata is unique in the mesh path table. Since the |
85 | * next_hop STA is only protected by RCU as well, deleting the STA must also | 85 | * next_hop STA is only protected by RCU as well, deleting the STA must also |
86 | * remove/substitute the mesh_path structure and wait until that is no longer | 86 | * remove/substitute the mesh_path structure and wait until that is no longer |
87 | * reachable before destroying the STA completely. | 87 | * reachable before destroying the STA completely. |
88 | */ | 88 | */ |
89 | struct mesh_path { | 89 | struct mesh_path { |
90 | u8 dst[ETH_ALEN]; | 90 | u8 dst[ETH_ALEN]; |
91 | u8 mpp[ETH_ALEN]; /* used for MPP or MAP */ | 91 | u8 mpp[ETH_ALEN]; /* used for MPP or MAP */ |
92 | struct ieee80211_sub_if_data *sdata; | 92 | struct ieee80211_sub_if_data *sdata; |
93 | struct sta_info *next_hop; | 93 | struct sta_info *next_hop; |
94 | struct timer_list timer; | 94 | struct timer_list timer; |
95 | struct sk_buff_head frame_queue; | 95 | struct sk_buff_head frame_queue; |
96 | struct rcu_head rcu; | 96 | struct rcu_head rcu; |
97 | u32 dsn; | 97 | u32 dsn; |
98 | u32 metric; | 98 | u32 metric; |
99 | u8 hop_count; | 99 | u8 hop_count; |
100 | unsigned long exp_time; | 100 | unsigned long exp_time; |
101 | u32 discovery_timeout; | 101 | u32 discovery_timeout; |
102 | u8 discovery_retries; | 102 | u8 discovery_retries; |
103 | enum mesh_path_flags flags; | 103 | enum mesh_path_flags flags; |
104 | spinlock_t state_lock; | 104 | spinlock_t state_lock; |
105 | }; | 105 | }; |
106 | 106 | ||
107 | /** | 107 | /** |
108 | * struct mesh_table | 108 | * struct mesh_table |
109 | * | 109 | * |
110 | * @hash_buckets: array of hash buckets of the table | 110 | * @hash_buckets: array of hash buckets of the table |
111 | * @hashwlock: array of locks to protect write operations, one per bucket | 111 | * @hashwlock: array of locks to protect write operations, one per bucket |
112 | * @hash_mask: 2^size_order - 1, used to compute hash idx | 112 | * @hash_mask: 2^size_order - 1, used to compute hash idx |
113 | * @hash_rnd: random value used for hash computations | 113 | * @hash_rnd: random value used for hash computations |
114 | * @entries: number of entries in the table | 114 | * @entries: number of entries in the table |
115 | * @free_node: function to free nodes of the table | 115 | * @free_node: function to free nodes of the table |
116 | * @copy_node: fuction to copy nodes of the table | 116 | * @copy_node: fuction to copy nodes of the table |
117 | * @size_order: determines size of the table, there will be 2^size_order hash | 117 | * @size_order: determines size of the table, there will be 2^size_order hash |
118 | * buckets | 118 | * buckets |
119 | * @mean_chain_len: maximum average length for the hash buckets' list, if it is | 119 | * @mean_chain_len: maximum average length for the hash buckets' list, if it is |
120 | * reached, the table will grow | 120 | * reached, the table will grow |
121 | */ | 121 | */ |
122 | struct mesh_table { | 122 | struct mesh_table { |
123 | /* Number of buckets will be 2^N */ | 123 | /* Number of buckets will be 2^N */ |
124 | struct hlist_head *hash_buckets; | 124 | struct hlist_head *hash_buckets; |
125 | spinlock_t *hashwlock; /* One per bucket, for add/del */ | 125 | spinlock_t *hashwlock; /* One per bucket, for add/del */ |
126 | unsigned int hash_mask; /* (2^size_order) - 1 */ | 126 | unsigned int hash_mask; /* (2^size_order) - 1 */ |
127 | __u32 hash_rnd; /* Used for hash generation */ | 127 | __u32 hash_rnd; /* Used for hash generation */ |
128 | atomic_t entries; /* Up to MAX_MESH_NEIGHBOURS */ | 128 | atomic_t entries; /* Up to MAX_MESH_NEIGHBOURS */ |
129 | void (*free_node) (struct hlist_node *p, bool free_leafs); | 129 | void (*free_node) (struct hlist_node *p, bool free_leafs); |
130 | int (*copy_node) (struct hlist_node *p, struct mesh_table *newtbl); | 130 | int (*copy_node) (struct hlist_node *p, struct mesh_table *newtbl); |
131 | int size_order; | 131 | int size_order; |
132 | int mean_chain_len; | 132 | int mean_chain_len; |
133 | }; | 133 | }; |
134 | 134 | ||
135 | /* Recent multicast cache */ | 135 | /* Recent multicast cache */ |
136 | /* RMC_BUCKETS must be a power of 2, maximum 256 */ | 136 | /* RMC_BUCKETS must be a power of 2, maximum 256 */ |
137 | #define RMC_BUCKETS 256 | 137 | #define RMC_BUCKETS 256 |
138 | #define RMC_QUEUE_MAX_LEN 4 | 138 | #define RMC_QUEUE_MAX_LEN 4 |
139 | #define RMC_TIMEOUT (3 * HZ) | 139 | #define RMC_TIMEOUT (3 * HZ) |
140 | 140 | ||
141 | /** | 141 | /** |
142 | * struct rmc_entry - entry in the Recent Multicast Cache | 142 | * struct rmc_entry - entry in the Recent Multicast Cache |
143 | * | 143 | * |
144 | * @seqnum: mesh sequence number of the frame | 144 | * @seqnum: mesh sequence number of the frame |
145 | * @exp_time: expiration time of the entry, in jiffies | 145 | * @exp_time: expiration time of the entry, in jiffies |
146 | * @sa: source address of the frame | 146 | * @sa: source address of the frame |
147 | * | 147 | * |
148 | * The Recent Multicast Cache keeps track of the latest multicast frames that | 148 | * The Recent Multicast Cache keeps track of the latest multicast frames that |
149 | * have been received by a mesh interface and discards received multicast frames | 149 | * have been received by a mesh interface and discards received multicast frames |
150 | * that are found in the cache. | 150 | * that are found in the cache. |
151 | */ | 151 | */ |
152 | struct rmc_entry { | 152 | struct rmc_entry { |
153 | struct list_head list; | 153 | struct list_head list; |
154 | u32 seqnum; | 154 | u32 seqnum; |
155 | unsigned long exp_time; | 155 | unsigned long exp_time; |
156 | u8 sa[ETH_ALEN]; | 156 | u8 sa[ETH_ALEN]; |
157 | }; | 157 | }; |
158 | 158 | ||
159 | struct mesh_rmc { | 159 | struct mesh_rmc { |
160 | struct rmc_entry bucket[RMC_BUCKETS]; | 160 | struct rmc_entry bucket[RMC_BUCKETS]; |
161 | u32 idx_mask; | 161 | u32 idx_mask; |
162 | }; | 162 | }; |
163 | 163 | ||
164 | 164 | ||
165 | /* | 165 | /* |
166 | * MESH_CFG_COMP_LEN Includes: | 166 | * MESH_CFG_COMP_LEN Includes: |
167 | * - Active path selection protocol ID. | 167 | * - Active path selection protocol ID. |
168 | * - Active path selection metric ID. | 168 | * - Active path selection metric ID. |
169 | * - Congestion control mode identifier. | 169 | * - Congestion control mode identifier. |
170 | * - Channel precedence. | 170 | * - Channel precedence. |
171 | * Does not include mesh capabilities, which may vary across nodes in the same | 171 | * Does not include mesh capabilities, which may vary across nodes in the same |
172 | * mesh | 172 | * mesh |
173 | */ | 173 | */ |
174 | #define MESH_CFG_CMP_LEN (IEEE80211_MESH_CONFIG_LEN - 2) | 174 | #define MESH_CFG_CMP_LEN (IEEE80211_MESH_CONFIG_LEN - 2) |
175 | 175 | ||
176 | /* Default values, timeouts in ms */ | 176 | /* Default values, timeouts in ms */ |
177 | #define MESH_TTL 31 | 177 | #define MESH_TTL 31 |
178 | #define MESH_MAX_RETR 3 | 178 | #define MESH_MAX_RETR 3 |
179 | #define MESH_RET_T 100 | 179 | #define MESH_RET_T 100 |
180 | #define MESH_CONF_T 100 | 180 | #define MESH_CONF_T 100 |
181 | #define MESH_HOLD_T 100 | 181 | #define MESH_HOLD_T 100 |
182 | 182 | ||
183 | #define MESH_PATH_TIMEOUT 5000 | 183 | #define MESH_PATH_TIMEOUT 5000 |
184 | /* Minimum interval between two consecutive PREQs originated by the same | 184 | /* Minimum interval between two consecutive PREQs originated by the same |
185 | * interface | 185 | * interface |
186 | */ | 186 | */ |
187 | #define MESH_PREQ_MIN_INT 10 | 187 | #define MESH_PREQ_MIN_INT 10 |
188 | #define MESH_DIAM_TRAVERSAL_TIME 50 | 188 | #define MESH_DIAM_TRAVERSAL_TIME 50 |
189 | /* Paths will be refreshed if they are closer than PATH_REFRESH_TIME to their | 189 | /* Paths will be refreshed if they are closer than PATH_REFRESH_TIME to their |
190 | * expiration | 190 | * expiration |
191 | */ | 191 | */ |
192 | #define MESH_PATH_REFRESH_TIME 1000 | 192 | #define MESH_PATH_REFRESH_TIME 1000 |
193 | #define MESH_MIN_DISCOVERY_TIMEOUT (2 * MESH_DIAM_TRAVERSAL_TIME) | 193 | #define MESH_MIN_DISCOVERY_TIMEOUT (2 * MESH_DIAM_TRAVERSAL_TIME) |
194 | #define MESH_DEFAULT_BEACON_INTERVAL 1000 /* in 1024 us units */ | 194 | #define MESH_DEFAULT_BEACON_INTERVAL 1000 /* in 1024 us units */ |
195 | 195 | ||
196 | #define MESH_MAX_PREQ_RETRIES 4 | 196 | #define MESH_MAX_PREQ_RETRIES 4 |
197 | #define MESH_PATH_EXPIRE (600 * HZ) | 197 | #define MESH_PATH_EXPIRE (600 * HZ) |
198 | 198 | ||
199 | /* Default maximum number of established plinks per interface */ | 199 | /* Default maximum number of established plinks per interface */ |
200 | #define MESH_MAX_ESTAB_PLINKS 32 | 200 | #define MESH_MAX_ESTAB_PLINKS 32 |
201 | 201 | ||
202 | /* Default maximum number of plinks per interface */ | 202 | /* Default maximum number of plinks per interface */ |
203 | #define MESH_MAX_PLINKS 256 | 203 | #define MESH_MAX_PLINKS 256 |
204 | 204 | ||
205 | /* Maximum number of paths per interface */ | 205 | /* Maximum number of paths per interface */ |
206 | #define MESH_MAX_MPATHS 1024 | 206 | #define MESH_MAX_MPATHS 1024 |
207 | 207 | ||
208 | /* Pending ANA approval */ | 208 | /* Pending ANA approval */ |
209 | #define MESH_PLINK_CATEGORY 30 | 209 | #define MESH_PLINK_CATEGORY 30 |
210 | #define MESH_PATH_SEL_CATEGORY 32 | 210 | #define MESH_PATH_SEL_CATEGORY 32 |
211 | #define MESH_PATH_SEL_ACTION 0 | ||
211 | 212 | ||
212 | /* Public interfaces */ | 213 | /* Public interfaces */ |
213 | /* Various */ | 214 | /* Various */ |
214 | int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc, | 215 | int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc, |
215 | char *da, char *sa); | 216 | char *da, char *sa); |
216 | int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr, | 217 | int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr, |
217 | struct ieee80211_sub_if_data *sdata, char *addr4, | 218 | struct ieee80211_sub_if_data *sdata, char *addr4, |
218 | char *addr5, char *addr6); | 219 | char *addr5, char *addr6); |
219 | int mesh_rmc_check(u8 *addr, struct ieee80211s_hdr *mesh_hdr, | 220 | int mesh_rmc_check(u8 *addr, struct ieee80211s_hdr *mesh_hdr, |
220 | struct ieee80211_sub_if_data *sdata); | 221 | struct ieee80211_sub_if_data *sdata); |
221 | bool mesh_matches_local(struct ieee802_11_elems *ie, | 222 | bool mesh_matches_local(struct ieee802_11_elems *ie, |
222 | struct ieee80211_sub_if_data *sdata); | 223 | struct ieee80211_sub_if_data *sdata); |
223 | void mesh_ids_set_default(struct ieee80211_if_mesh *mesh); | 224 | void mesh_ids_set_default(struct ieee80211_if_mesh *mesh); |
224 | void mesh_mgmt_ies_add(struct sk_buff *skb, | 225 | void mesh_mgmt_ies_add(struct sk_buff *skb, |
225 | struct ieee80211_sub_if_data *sdata); | 226 | struct ieee80211_sub_if_data *sdata); |
226 | void mesh_rmc_free(struct ieee80211_sub_if_data *sdata); | 227 | void mesh_rmc_free(struct ieee80211_sub_if_data *sdata); |
227 | int mesh_rmc_init(struct ieee80211_sub_if_data *sdata); | 228 | int mesh_rmc_init(struct ieee80211_sub_if_data *sdata); |
228 | void ieee80211s_init(void); | 229 | void ieee80211s_init(void); |
229 | void ieee80211s_update_metric(struct ieee80211_local *local, | 230 | void ieee80211s_update_metric(struct ieee80211_local *local, |
230 | struct sta_info *stainfo, struct sk_buff *skb); | 231 | struct sta_info *stainfo, struct sk_buff *skb); |
231 | void ieee80211s_stop(void); | 232 | void ieee80211s_stop(void); |
232 | void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata); | 233 | void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata); |
233 | ieee80211_rx_result | 234 | ieee80211_rx_result |
234 | ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); | 235 | 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); | 236 | void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata); |
236 | void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata); | 237 | void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata); |
237 | 238 | ||
238 | /* Mesh paths */ | 239 | /* Mesh paths */ |
239 | int mesh_nexthop_lookup(struct sk_buff *skb, | 240 | int mesh_nexthop_lookup(struct sk_buff *skb, |
240 | struct ieee80211_sub_if_data *sdata); | 241 | struct ieee80211_sub_if_data *sdata); |
241 | void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata); | 242 | void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata); |
242 | struct mesh_path *mesh_path_lookup(u8 *dst, | 243 | struct mesh_path *mesh_path_lookup(u8 *dst, |
243 | struct ieee80211_sub_if_data *sdata); | 244 | struct ieee80211_sub_if_data *sdata); |
244 | struct mesh_path *mpp_path_lookup(u8 *dst, | 245 | struct mesh_path *mpp_path_lookup(u8 *dst, |
245 | struct ieee80211_sub_if_data *sdata); | 246 | struct ieee80211_sub_if_data *sdata); |
246 | int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata); | 247 | int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata); |
247 | struct mesh_path *mesh_path_lookup_by_idx(int idx, | 248 | struct mesh_path *mesh_path_lookup_by_idx(int idx, |
248 | struct ieee80211_sub_if_data *sdata); | 249 | struct ieee80211_sub_if_data *sdata); |
249 | void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop); | 250 | void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop); |
250 | void mesh_path_expire(struct ieee80211_sub_if_data *sdata); | 251 | void mesh_path_expire(struct ieee80211_sub_if_data *sdata); |
251 | void mesh_path_flush(struct ieee80211_sub_if_data *sdata); | 252 | void mesh_path_flush(struct ieee80211_sub_if_data *sdata); |
252 | void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, | 253 | void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, |
253 | struct ieee80211_mgmt *mgmt, size_t len); | 254 | struct ieee80211_mgmt *mgmt, size_t len); |
254 | int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata); | 255 | int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata); |
255 | /* Mesh plinks */ | 256 | /* Mesh plinks */ |
256 | void mesh_neighbour_update(u8 *hw_addr, u32 rates, | 257 | void mesh_neighbour_update(u8 *hw_addr, u32 rates, |
257 | struct ieee80211_sub_if_data *sdata, bool add); | 258 | struct ieee80211_sub_if_data *sdata, bool add); |
258 | bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie); | 259 | bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie); |
259 | void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata); | 260 | void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata); |
260 | void mesh_plink_broken(struct sta_info *sta); | 261 | void mesh_plink_broken(struct sta_info *sta); |
261 | void mesh_plink_deactivate(struct sta_info *sta); | 262 | void mesh_plink_deactivate(struct sta_info *sta); |
262 | int mesh_plink_open(struct sta_info *sta); | 263 | int mesh_plink_open(struct sta_info *sta); |
263 | void mesh_plink_block(struct sta_info *sta); | 264 | void mesh_plink_block(struct sta_info *sta); |
264 | void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, | 265 | void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, |
265 | struct ieee80211_mgmt *mgmt, size_t len, | 266 | struct ieee80211_mgmt *mgmt, size_t len, |
266 | struct ieee80211_rx_status *rx_status); | 267 | struct ieee80211_rx_status *rx_status); |
267 | 268 | ||
268 | /* Private interfaces */ | 269 | /* Private interfaces */ |
269 | /* Mesh tables */ | 270 | /* Mesh tables */ |
270 | struct mesh_table *mesh_table_alloc(int size_order); | 271 | struct mesh_table *mesh_table_alloc(int size_order); |
271 | void mesh_table_free(struct mesh_table *tbl, bool free_leafs); | 272 | void mesh_table_free(struct mesh_table *tbl, bool free_leafs); |
272 | void mesh_mpath_table_grow(void); | 273 | void mesh_mpath_table_grow(void); |
273 | void mesh_mpp_table_grow(void); | 274 | void mesh_mpp_table_grow(void); |
274 | u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata, | 275 | u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata, |
275 | struct mesh_table *tbl); | 276 | struct mesh_table *tbl); |
276 | /* Mesh paths */ | 277 | /* Mesh paths */ |
277 | int mesh_path_error_tx(u8 *dest, __le32 dest_dsn, u8 *ra, | 278 | int mesh_path_error_tx(u8 *dest, __le32 dest_dsn, u8 *ra, |
278 | struct ieee80211_sub_if_data *sdata); | 279 | struct ieee80211_sub_if_data *sdata); |
279 | void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta); | 280 | void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta); |
280 | void mesh_path_flush_pending(struct mesh_path *mpath); | 281 | void mesh_path_flush_pending(struct mesh_path *mpath); |
281 | void mesh_path_tx_pending(struct mesh_path *mpath); | 282 | void mesh_path_tx_pending(struct mesh_path *mpath); |
282 | int mesh_pathtbl_init(void); | 283 | int mesh_pathtbl_init(void); |
283 | void mesh_pathtbl_unregister(void); | 284 | void mesh_pathtbl_unregister(void); |
284 | int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata); | 285 | int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata); |
285 | void mesh_path_timer(unsigned long data); | 286 | void mesh_path_timer(unsigned long data); |
286 | void mesh_path_flush_by_nexthop(struct sta_info *sta); | 287 | void mesh_path_flush_by_nexthop(struct sta_info *sta); |
287 | void mesh_path_discard_frame(struct sk_buff *skb, | 288 | void mesh_path_discard_frame(struct sk_buff *skb, |
288 | struct ieee80211_sub_if_data *sdata); | 289 | struct ieee80211_sub_if_data *sdata); |
289 | void mesh_path_quiesce(struct ieee80211_sub_if_data *sdata); | 290 | void mesh_path_quiesce(struct ieee80211_sub_if_data *sdata); |
290 | void mesh_path_restart(struct ieee80211_sub_if_data *sdata); | 291 | void mesh_path_restart(struct ieee80211_sub_if_data *sdata); |
291 | 292 | ||
292 | extern int mesh_paths_generation; | 293 | extern int mesh_paths_generation; |
293 | 294 | ||
294 | #ifdef CONFIG_MAC80211_MESH | 295 | #ifdef CONFIG_MAC80211_MESH |
295 | extern int mesh_allocated; | 296 | extern int mesh_allocated; |
296 | 297 | ||
297 | static inline int mesh_plink_free_count(struct ieee80211_sub_if_data *sdata) | 298 | static inline int mesh_plink_free_count(struct ieee80211_sub_if_data *sdata) |
298 | { | 299 | { |
299 | return sdata->u.mesh.mshcfg.dot11MeshMaxPeerLinks - | 300 | return sdata->u.mesh.mshcfg.dot11MeshMaxPeerLinks - |
300 | atomic_read(&sdata->u.mesh.mshstats.estab_plinks); | 301 | atomic_read(&sdata->u.mesh.mshstats.estab_plinks); |
301 | } | 302 | } |
302 | 303 | ||
303 | static inline bool mesh_plink_availables(struct ieee80211_sub_if_data *sdata) | 304 | static inline bool mesh_plink_availables(struct ieee80211_sub_if_data *sdata) |
304 | { | 305 | { |
305 | return (min_t(long, mesh_plink_free_count(sdata), | 306 | return (min_t(long, mesh_plink_free_count(sdata), |
306 | MESH_MAX_PLINKS - sdata->local->num_sta)) > 0; | 307 | MESH_MAX_PLINKS - sdata->local->num_sta)) > 0; |
307 | } | 308 | } |
308 | 309 | ||
309 | static inline void mesh_path_activate(struct mesh_path *mpath) | 310 | static inline void mesh_path_activate(struct mesh_path *mpath) |
310 | { | 311 | { |
311 | mpath->flags |= MESH_PATH_ACTIVE | MESH_PATH_RESOLVED; | 312 | mpath->flags |= MESH_PATH_ACTIVE | MESH_PATH_RESOLVED; |
312 | } | 313 | } |
313 | 314 | ||
314 | #define for_each_mesh_entry(x, p, node, i) \ | 315 | #define for_each_mesh_entry(x, p, node, i) \ |
315 | for (i = 0; i <= x->hash_mask; i++) \ | 316 | for (i = 0; i <= x->hash_mask; i++) \ |
316 | hlist_for_each_entry_rcu(node, p, &x->hash_buckets[i], list) | 317 | hlist_for_each_entry_rcu(node, p, &x->hash_buckets[i], list) |
317 | 318 | ||
318 | void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local); | 319 | void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local); |
319 | 320 | ||
320 | void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata); | 321 | void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata); |
321 | void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata); | 322 | void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata); |
322 | void mesh_plink_quiesce(struct sta_info *sta); | 323 | void mesh_plink_quiesce(struct sta_info *sta); |
323 | void mesh_plink_restart(struct sta_info *sta); | 324 | void mesh_plink_restart(struct sta_info *sta); |
324 | #else | 325 | #else |
325 | #define mesh_allocated 0 | 326 | #define mesh_allocated 0 |
326 | static inline void | 327 | static inline void |
327 | ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) {} | 328 | ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) {} |
328 | static inline void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata) | 329 | static inline void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata) |
329 | {} | 330 | {} |
330 | static inline void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata) | 331 | static inline void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata) |
331 | {} | 332 | {} |
332 | static inline void mesh_plink_quiesce(struct sta_info *sta) {} | 333 | static inline void mesh_plink_quiesce(struct sta_info *sta) {} |
333 | static inline void mesh_plink_restart(struct sta_info *sta) {} | 334 | static inline void mesh_plink_restart(struct sta_info *sta) {} |
334 | #endif | 335 | #endif |
335 | 336 | ||
336 | #endif /* IEEE80211S_H */ | 337 | #endif /* IEEE80211S_H */ |
337 | 338 |
net/mac80211/mesh_hwmp.c
1 | /* | 1 | /* |
2 | * Copyright (c) 2008 open80211s Ltd. | 2 | * Copyright (c) 2008 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 |
6 | * it under the terms of the GNU General Public License version 2 as | 6 | * it under the terms of the GNU General Public License version 2 as |
7 | * published by the Free Software Foundation. | 7 | * published by the Free Software Foundation. |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include "mesh.h" | 10 | #include "mesh.h" |
11 | 11 | ||
12 | #define TEST_FRAME_LEN 8192 | 12 | #define TEST_FRAME_LEN 8192 |
13 | #define MAX_METRIC 0xffffffff | 13 | #define MAX_METRIC 0xffffffff |
14 | #define ARITH_SHIFT 8 | 14 | #define ARITH_SHIFT 8 |
15 | 15 | ||
16 | /* Number of frames buffered per destination for unresolved destinations */ | 16 | /* Number of frames buffered per destination for unresolved destinations */ |
17 | #define MESH_FRAME_QUEUE_LEN 10 | 17 | #define MESH_FRAME_QUEUE_LEN 10 |
18 | #define MAX_PREQ_QUEUE_LEN 64 | 18 | #define MAX_PREQ_QUEUE_LEN 64 |
19 | 19 | ||
20 | /* Destination only */ | 20 | /* Destination only */ |
21 | #define MP_F_DO 0x1 | 21 | #define MP_F_DO 0x1 |
22 | /* Reply and forward */ | 22 | /* Reply and forward */ |
23 | #define MP_F_RF 0x2 | 23 | #define MP_F_RF 0x2 |
24 | 24 | ||
25 | static inline u32 u32_field_get(u8 *preq_elem, int offset, bool ae) | 25 | static inline u32 u32_field_get(u8 *preq_elem, int offset, bool ae) |
26 | { | 26 | { |
27 | if (ae) | 27 | if (ae) |
28 | offset += 6; | 28 | offset += 6; |
29 | return get_unaligned_le32(preq_elem + offset); | 29 | return get_unaligned_le32(preq_elem + offset); |
30 | } | 30 | } |
31 | 31 | ||
32 | /* HWMP IE processing macros */ | 32 | /* HWMP IE processing macros */ |
33 | #define AE_F (1<<6) | 33 | #define AE_F (1<<6) |
34 | #define AE_F_SET(x) (*x & AE_F) | 34 | #define AE_F_SET(x) (*x & AE_F) |
35 | #define PREQ_IE_FLAGS(x) (*(x)) | 35 | #define PREQ_IE_FLAGS(x) (*(x)) |
36 | #define PREQ_IE_HOPCOUNT(x) (*(x + 1)) | 36 | #define PREQ_IE_HOPCOUNT(x) (*(x + 1)) |
37 | #define PREQ_IE_TTL(x) (*(x + 2)) | 37 | #define PREQ_IE_TTL(x) (*(x + 2)) |
38 | #define PREQ_IE_PREQ_ID(x) u32_field_get(x, 3, 0) | 38 | #define PREQ_IE_PREQ_ID(x) u32_field_get(x, 3, 0) |
39 | #define PREQ_IE_ORIG_ADDR(x) (x + 7) | 39 | #define PREQ_IE_ORIG_ADDR(x) (x + 7) |
40 | #define PREQ_IE_ORIG_DSN(x) u32_field_get(x, 13, 0); | 40 | #define PREQ_IE_ORIG_DSN(x) u32_field_get(x, 13, 0); |
41 | #define PREQ_IE_LIFETIME(x) u32_field_get(x, 17, AE_F_SET(x)); | 41 | #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)); | 42 | #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)) | 43 | #define PREQ_IE_DST_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) | 44 | #define PREQ_IE_DST_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)); | 45 | #define PREQ_IE_DST_DSN(x) u32_field_get(x, 33, AE_F_SET(x)); |
46 | 46 | ||
47 | 47 | ||
48 | #define PREP_IE_FLAGS(x) PREQ_IE_FLAGS(x) | 48 | #define PREP_IE_FLAGS(x) PREQ_IE_FLAGS(x) |
49 | #define PREP_IE_HOPCOUNT(x) PREQ_IE_HOPCOUNT(x) | 49 | #define PREP_IE_HOPCOUNT(x) PREQ_IE_HOPCOUNT(x) |
50 | #define PREP_IE_TTL(x) PREQ_IE_TTL(x) | 50 | #define PREP_IE_TTL(x) PREQ_IE_TTL(x) |
51 | #define PREP_IE_ORIG_ADDR(x) (x + 3) | 51 | #define PREP_IE_ORIG_ADDR(x) (x + 3) |
52 | #define PREP_IE_ORIG_DSN(x) u32_field_get(x, 9, 0); | 52 | #define PREP_IE_ORIG_DSN(x) u32_field_get(x, 9, 0); |
53 | #define PREP_IE_LIFETIME(x) u32_field_get(x, 13, AE_F_SET(x)); | 53 | #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)); | 54 | #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) | 55 | #define PREP_IE_DST_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)); | 56 | #define PREP_IE_DST_DSN(x) u32_field_get(x, 27, AE_F_SET(x)); |
57 | 57 | ||
58 | #define PERR_IE_DST_ADDR(x) (x + 2) | 58 | #define PERR_IE_DST_ADDR(x) (x + 2) |
59 | #define PERR_IE_DST_DSN(x) u32_field_get(x, 8, 0); | 59 | #define PERR_IE_DST_DSN(x) u32_field_get(x, 8, 0); |
60 | 60 | ||
61 | #define MSEC_TO_TU(x) (x*1000/1024) | 61 | #define MSEC_TO_TU(x) (x*1000/1024) |
62 | #define DSN_GT(x, y) ((long) (y) - (long) (x) < 0) | 62 | #define DSN_GT(x, y) ((long) (y) - (long) (x) < 0) |
63 | #define DSN_LT(x, y) ((long) (x) - (long) (y) < 0) | 63 | #define DSN_LT(x, y) ((long) (x) - (long) (y) < 0) |
64 | 64 | ||
65 | #define net_traversal_jiffies(s) \ | 65 | #define net_traversal_jiffies(s) \ |
66 | msecs_to_jiffies(s->u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime) | 66 | msecs_to_jiffies(s->u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime) |
67 | #define default_lifetime(s) \ | 67 | #define default_lifetime(s) \ |
68 | MSEC_TO_TU(s->u.mesh.mshcfg.dot11MeshHWMPactivePathTimeout) | 68 | MSEC_TO_TU(s->u.mesh.mshcfg.dot11MeshHWMPactivePathTimeout) |
69 | #define min_preq_int_jiff(s) \ | 69 | #define min_preq_int_jiff(s) \ |
70 | (msecs_to_jiffies(s->u.mesh.mshcfg.dot11MeshHWMPpreqMinInterval)) | 70 | (msecs_to_jiffies(s->u.mesh.mshcfg.dot11MeshHWMPpreqMinInterval)) |
71 | #define max_preq_retries(s) (s->u.mesh.mshcfg.dot11MeshHWMPmaxPREQretries) | 71 | #define max_preq_retries(s) (s->u.mesh.mshcfg.dot11MeshHWMPmaxPREQretries) |
72 | #define disc_timeout_jiff(s) \ | 72 | #define disc_timeout_jiff(s) \ |
73 | msecs_to_jiffies(sdata->u.mesh.mshcfg.min_discovery_timeout) | 73 | msecs_to_jiffies(sdata->u.mesh.mshcfg.min_discovery_timeout) |
74 | 74 | ||
75 | enum mpath_frame_type { | 75 | enum mpath_frame_type { |
76 | MPATH_PREQ = 0, | 76 | MPATH_PREQ = 0, |
77 | MPATH_PREP, | 77 | MPATH_PREP, |
78 | MPATH_PERR | 78 | MPATH_PERR |
79 | }; | 79 | }; |
80 | 80 | ||
81 | static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, | 81 | 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, | 82 | u8 *orig_addr, __le32 orig_dsn, u8 dst_flags, u8 *dst, |
83 | __le32 dst_dsn, u8 *da, u8 hop_count, u8 ttl, __le32 lifetime, | 83 | __le32 dst_dsn, u8 *da, u8 hop_count, u8 ttl, __le32 lifetime, |
84 | __le32 metric, __le32 preq_id, struct ieee80211_sub_if_data *sdata) | 84 | __le32 metric, __le32 preq_id, struct ieee80211_sub_if_data *sdata) |
85 | { | 85 | { |
86 | struct ieee80211_local *local = sdata->local; | 86 | struct ieee80211_local *local = sdata->local; |
87 | struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); | 87 | struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); |
88 | struct ieee80211_mgmt *mgmt; | 88 | struct ieee80211_mgmt *mgmt; |
89 | u8 *pos; | 89 | u8 *pos; |
90 | int ie_len; | 90 | int ie_len; |
91 | 91 | ||
92 | if (!skb) | 92 | if (!skb) |
93 | return -1; | 93 | return -1; |
94 | skb_reserve(skb, local->hw.extra_tx_headroom); | 94 | skb_reserve(skb, local->hw.extra_tx_headroom); |
95 | /* 25 is the size of the common mgmt part (24) plus the size of the | 95 | /* 25 is the size of the common mgmt part (24) plus the size of the |
96 | * common action part (1) | 96 | * common action part (1) |
97 | */ | 97 | */ |
98 | mgmt = (struct ieee80211_mgmt *) | 98 | mgmt = (struct ieee80211_mgmt *) |
99 | skb_put(skb, 25 + sizeof(mgmt->u.action.u.mesh_action)); | 99 | skb_put(skb, 25 + sizeof(mgmt->u.action.u.mesh_action)); |
100 | memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.mesh_action)); | 100 | memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.mesh_action)); |
101 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 101 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
102 | IEEE80211_STYPE_ACTION); | 102 | IEEE80211_STYPE_ACTION); |
103 | 103 | ||
104 | memcpy(mgmt->da, da, ETH_ALEN); | 104 | memcpy(mgmt->da, da, ETH_ALEN); |
105 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 105 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); |
106 | /* BSSID is left zeroed, wildcard value */ | 106 | /* BSSID is left zeroed, wildcard value */ |
107 | mgmt->u.action.category = MESH_PATH_SEL_CATEGORY; | 107 | mgmt->u.action.category = MESH_PATH_SEL_CATEGORY; |
108 | mgmt->u.action.u.mesh_action.action_code = action; | 108 | mgmt->u.action.u.mesh_action.action_code = MESH_PATH_SEL_ACTION; |
109 | 109 | ||
110 | switch (action) { | 110 | switch (action) { |
111 | case MPATH_PREQ: | 111 | case MPATH_PREQ: |
112 | ie_len = 37; | 112 | ie_len = 37; |
113 | pos = skb_put(skb, 2 + ie_len); | 113 | pos = skb_put(skb, 2 + ie_len); |
114 | *pos++ = WLAN_EID_PREQ; | 114 | *pos++ = WLAN_EID_PREQ; |
115 | break; | 115 | break; |
116 | case MPATH_PREP: | 116 | case MPATH_PREP: |
117 | ie_len = 31; | 117 | ie_len = 31; |
118 | pos = skb_put(skb, 2 + ie_len); | 118 | pos = skb_put(skb, 2 + ie_len); |
119 | *pos++ = WLAN_EID_PREP; | 119 | *pos++ = WLAN_EID_PREP; |
120 | break; | 120 | break; |
121 | default: | 121 | default: |
122 | kfree_skb(skb); | 122 | kfree_skb(skb); |
123 | return -ENOTSUPP; | 123 | return -ENOTSUPP; |
124 | break; | 124 | break; |
125 | } | 125 | } |
126 | *pos++ = ie_len; | 126 | *pos++ = ie_len; |
127 | *pos++ = flags; | 127 | *pos++ = flags; |
128 | *pos++ = hop_count; | 128 | *pos++ = hop_count; |
129 | *pos++ = ttl; | 129 | *pos++ = ttl; |
130 | if (action == MPATH_PREQ) { | 130 | if (action == MPATH_PREQ) { |
131 | memcpy(pos, &preq_id, 4); | 131 | memcpy(pos, &preq_id, 4); |
132 | pos += 4; | 132 | pos += 4; |
133 | } | 133 | } |
134 | memcpy(pos, orig_addr, ETH_ALEN); | 134 | memcpy(pos, orig_addr, ETH_ALEN); |
135 | pos += ETH_ALEN; | 135 | pos += ETH_ALEN; |
136 | memcpy(pos, &orig_dsn, 4); | 136 | memcpy(pos, &orig_dsn, 4); |
137 | pos += 4; | 137 | pos += 4; |
138 | memcpy(pos, &lifetime, 4); | 138 | memcpy(pos, &lifetime, 4); |
139 | pos += 4; | 139 | pos += 4; |
140 | memcpy(pos, &metric, 4); | 140 | memcpy(pos, &metric, 4); |
141 | pos += 4; | 141 | pos += 4; |
142 | if (action == MPATH_PREQ) { | 142 | if (action == MPATH_PREQ) { |
143 | /* destination count */ | 143 | /* destination count */ |
144 | *pos++ = 1; | 144 | *pos++ = 1; |
145 | *pos++ = dst_flags; | 145 | *pos++ = dst_flags; |
146 | } | 146 | } |
147 | memcpy(pos, dst, ETH_ALEN); | 147 | memcpy(pos, dst, ETH_ALEN); |
148 | pos += ETH_ALEN; | 148 | pos += ETH_ALEN; |
149 | memcpy(pos, &dst_dsn, 4); | 149 | memcpy(pos, &dst_dsn, 4); |
150 | 150 | ||
151 | ieee80211_tx_skb(sdata, skb, 1); | 151 | ieee80211_tx_skb(sdata, skb, 1); |
152 | return 0; | 152 | return 0; |
153 | } | 153 | } |
154 | 154 | ||
155 | /** | 155 | /** |
156 | * mesh_send_path error - Sends a PERR mesh management frame | 156 | * mesh_send_path error - Sends a PERR mesh management frame |
157 | * | 157 | * |
158 | * @dst: broken destination | 158 | * @dst: broken destination |
159 | * @dst_dsn: dsn of the broken destination | 159 | * @dst_dsn: dsn of the broken destination |
160 | * @ra: node this frame is addressed to | 160 | * @ra: node this frame is addressed to |
161 | */ | 161 | */ |
162 | int mesh_path_error_tx(u8 *dst, __le32 dst_dsn, u8 *ra, | 162 | int mesh_path_error_tx(u8 *dst, __le32 dst_dsn, u8 *ra, |
163 | struct ieee80211_sub_if_data *sdata) | 163 | struct ieee80211_sub_if_data *sdata) |
164 | { | 164 | { |
165 | struct ieee80211_local *local = sdata->local; | 165 | struct ieee80211_local *local = sdata->local; |
166 | struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); | 166 | struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); |
167 | struct ieee80211_mgmt *mgmt; | 167 | struct ieee80211_mgmt *mgmt; |
168 | u8 *pos; | 168 | u8 *pos; |
169 | int ie_len; | 169 | int ie_len; |
170 | 170 | ||
171 | if (!skb) | 171 | if (!skb) |
172 | return -1; | 172 | return -1; |
173 | skb_reserve(skb, local->hw.extra_tx_headroom); | 173 | skb_reserve(skb, local->hw.extra_tx_headroom); |
174 | /* 25 is the size of the common mgmt part (24) plus the size of the | 174 | /* 25 is the size of the common mgmt part (24) plus the size of the |
175 | * common action part (1) | 175 | * common action part (1) |
176 | */ | 176 | */ |
177 | mgmt = (struct ieee80211_mgmt *) | 177 | mgmt = (struct ieee80211_mgmt *) |
178 | skb_put(skb, 25 + sizeof(mgmt->u.action.u.mesh_action)); | 178 | skb_put(skb, 25 + sizeof(mgmt->u.action.u.mesh_action)); |
179 | memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.mesh_action)); | 179 | memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.mesh_action)); |
180 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 180 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
181 | IEEE80211_STYPE_ACTION); | 181 | IEEE80211_STYPE_ACTION); |
182 | 182 | ||
183 | memcpy(mgmt->da, ra, ETH_ALEN); | 183 | memcpy(mgmt->da, ra, ETH_ALEN); |
184 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 184 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); |
185 | /* BSSID is left zeroed, wildcard value */ | 185 | /* BSSID is left zeroed, wildcard value */ |
186 | mgmt->u.action.category = MESH_PATH_SEL_CATEGORY; | 186 | mgmt->u.action.category = MESH_PATH_SEL_CATEGORY; |
187 | mgmt->u.action.u.mesh_action.action_code = MPATH_PERR; | 187 | mgmt->u.action.u.mesh_action.action_code = MPATH_PERR; |
188 | ie_len = 12; | 188 | ie_len = 12; |
189 | pos = skb_put(skb, 2 + ie_len); | 189 | pos = skb_put(skb, 2 + ie_len); |
190 | *pos++ = WLAN_EID_PERR; | 190 | *pos++ = WLAN_EID_PERR; |
191 | *pos++ = ie_len; | 191 | *pos++ = ie_len; |
192 | /* mode flags, reserved */ | 192 | /* mode flags, reserved */ |
193 | *pos++ = 0; | 193 | *pos++ = 0; |
194 | /* number of destinations */ | 194 | /* number of destinations */ |
195 | *pos++ = 1; | 195 | *pos++ = 1; |
196 | memcpy(pos, dst, ETH_ALEN); | 196 | memcpy(pos, dst, ETH_ALEN); |
197 | pos += ETH_ALEN; | 197 | pos += ETH_ALEN; |
198 | memcpy(pos, &dst_dsn, 4); | 198 | memcpy(pos, &dst_dsn, 4); |
199 | 199 | ||
200 | ieee80211_tx_skb(sdata, skb, 1); | 200 | ieee80211_tx_skb(sdata, skb, 1); |
201 | return 0; | 201 | return 0; |
202 | } | 202 | } |
203 | 203 | ||
204 | void ieee80211s_update_metric(struct ieee80211_local *local, | 204 | void ieee80211s_update_metric(struct ieee80211_local *local, |
205 | struct sta_info *stainfo, struct sk_buff *skb) | 205 | struct sta_info *stainfo, struct sk_buff *skb) |
206 | { | 206 | { |
207 | struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb); | 207 | struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb); |
208 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 208 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
209 | int failed; | 209 | int failed; |
210 | 210 | ||
211 | if (!ieee80211_is_data(hdr->frame_control)) | 211 | if (!ieee80211_is_data(hdr->frame_control)) |
212 | return; | 212 | return; |
213 | 213 | ||
214 | failed = !(txinfo->flags & IEEE80211_TX_STAT_ACK); | 214 | failed = !(txinfo->flags & IEEE80211_TX_STAT_ACK); |
215 | 215 | ||
216 | /* moving average, scaled to 100 */ | 216 | /* moving average, scaled to 100 */ |
217 | stainfo->fail_avg = ((80 * stainfo->fail_avg + 5) / 100 + 20 * failed); | 217 | stainfo->fail_avg = ((80 * stainfo->fail_avg + 5) / 100 + 20 * failed); |
218 | if (stainfo->fail_avg > 95) | 218 | if (stainfo->fail_avg > 95) |
219 | mesh_plink_broken(stainfo); | 219 | mesh_plink_broken(stainfo); |
220 | } | 220 | } |
221 | 221 | ||
222 | static u32 airtime_link_metric_get(struct ieee80211_local *local, | 222 | static u32 airtime_link_metric_get(struct ieee80211_local *local, |
223 | struct sta_info *sta) | 223 | struct sta_info *sta) |
224 | { | 224 | { |
225 | struct ieee80211_supported_band *sband; | 225 | struct ieee80211_supported_band *sband; |
226 | /* This should be adjusted for each device */ | 226 | /* This should be adjusted for each device */ |
227 | int device_constant = 1 << ARITH_SHIFT; | 227 | int device_constant = 1 << ARITH_SHIFT; |
228 | int test_frame_len = TEST_FRAME_LEN << ARITH_SHIFT; | 228 | int test_frame_len = TEST_FRAME_LEN << ARITH_SHIFT; |
229 | int s_unit = 1 << ARITH_SHIFT; | 229 | int s_unit = 1 << ARITH_SHIFT; |
230 | int rate, err; | 230 | int rate, err; |
231 | u32 tx_time, estimated_retx; | 231 | u32 tx_time, estimated_retx; |
232 | u64 result; | 232 | u64 result; |
233 | 233 | ||
234 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 234 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
235 | 235 | ||
236 | if (sta->fail_avg >= 100) | 236 | if (sta->fail_avg >= 100) |
237 | return MAX_METRIC; | 237 | return MAX_METRIC; |
238 | 238 | ||
239 | if (sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS) | 239 | if (sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS) |
240 | return MAX_METRIC; | 240 | return MAX_METRIC; |
241 | 241 | ||
242 | err = (sta->fail_avg << ARITH_SHIFT) / 100; | 242 | err = (sta->fail_avg << ARITH_SHIFT) / 100; |
243 | 243 | ||
244 | /* bitrate is in units of 100 Kbps, while we need rate in units of | 244 | /* bitrate is in units of 100 Kbps, while we need rate in units of |
245 | * 1Mbps. This will be corrected on tx_time computation. | 245 | * 1Mbps. This will be corrected on tx_time computation. |
246 | */ | 246 | */ |
247 | rate = sband->bitrates[sta->last_tx_rate.idx].bitrate; | 247 | rate = sband->bitrates[sta->last_tx_rate.idx].bitrate; |
248 | tx_time = (device_constant + 10 * test_frame_len / rate); | 248 | tx_time = (device_constant + 10 * test_frame_len / rate); |
249 | estimated_retx = ((1 << (2 * ARITH_SHIFT)) / (s_unit - err)); | 249 | estimated_retx = ((1 << (2 * ARITH_SHIFT)) / (s_unit - err)); |
250 | result = (tx_time * estimated_retx) >> (2 * ARITH_SHIFT) ; | 250 | result = (tx_time * estimated_retx) >> (2 * ARITH_SHIFT) ; |
251 | return (u32)result; | 251 | return (u32)result; |
252 | } | 252 | } |
253 | 253 | ||
254 | /** | 254 | /** |
255 | * hwmp_route_info_get - Update routing info to originator and transmitter | 255 | * hwmp_route_info_get - Update routing info to originator and transmitter |
256 | * | 256 | * |
257 | * @sdata: local mesh subif | 257 | * @sdata: local mesh subif |
258 | * @mgmt: mesh management frame | 258 | * @mgmt: mesh management frame |
259 | * @hwmp_ie: hwmp information element (PREP or PREQ) | 259 | * @hwmp_ie: hwmp information element (PREP or PREQ) |
260 | * | 260 | * |
261 | * This function updates the path routing information to the originator and the | 261 | * This function updates the path routing information to the originator and the |
262 | * transmitter of a HWMP PREQ or PREP frame. | 262 | * transmitter of a HWMP PREQ or PREP frame. |
263 | * | 263 | * |
264 | * Returns: metric to frame originator or 0 if the frame should not be further | 264 | * Returns: metric to frame originator or 0 if the frame should not be further |
265 | * processed | 265 | * processed |
266 | * | 266 | * |
267 | * Notes: this function is the only place (besides user-provided info) where | 267 | * Notes: this function is the only place (besides user-provided info) where |
268 | * path routing information is updated. | 268 | * path routing information is updated. |
269 | */ | 269 | */ |
270 | static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, | 270 | static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, |
271 | struct ieee80211_mgmt *mgmt, | 271 | struct ieee80211_mgmt *mgmt, |
272 | u8 *hwmp_ie) | 272 | u8 *hwmp_ie) |
273 | { | 273 | { |
274 | struct ieee80211_local *local = sdata->local; | 274 | struct ieee80211_local *local = sdata->local; |
275 | struct mesh_path *mpath; | 275 | struct mesh_path *mpath; |
276 | struct sta_info *sta; | 276 | struct sta_info *sta; |
277 | bool fresh_info; | 277 | bool fresh_info; |
278 | u8 *orig_addr, *ta; | 278 | u8 *orig_addr, *ta; |
279 | u32 orig_dsn, orig_metric; | 279 | u32 orig_dsn, orig_metric; |
280 | unsigned long orig_lifetime, exp_time; | 280 | unsigned long orig_lifetime, exp_time; |
281 | u32 last_hop_metric, new_metric; | 281 | u32 last_hop_metric, new_metric; |
282 | bool process = true; | 282 | bool process = true; |
283 | u8 action = mgmt->u.action.u.mesh_action.action_code; | 283 | u8 action = mgmt->u.action.u.mesh_action.action_code; |
284 | 284 | ||
285 | rcu_read_lock(); | 285 | rcu_read_lock(); |
286 | sta = sta_info_get(local, mgmt->sa); | 286 | sta = sta_info_get(local, mgmt->sa); |
287 | if (!sta) { | 287 | if (!sta) { |
288 | rcu_read_unlock(); | 288 | rcu_read_unlock(); |
289 | return 0; | 289 | return 0; |
290 | } | 290 | } |
291 | 291 | ||
292 | last_hop_metric = airtime_link_metric_get(local, sta); | 292 | last_hop_metric = airtime_link_metric_get(local, sta); |
293 | /* Update and check originator routing info */ | 293 | /* Update and check originator routing info */ |
294 | fresh_info = true; | 294 | fresh_info = true; |
295 | 295 | ||
296 | switch (action) { | 296 | switch (action) { |
297 | case MPATH_PREQ: | 297 | case MPATH_PREQ: |
298 | orig_addr = PREQ_IE_ORIG_ADDR(hwmp_ie); | 298 | orig_addr = PREQ_IE_ORIG_ADDR(hwmp_ie); |
299 | orig_dsn = PREQ_IE_ORIG_DSN(hwmp_ie); | 299 | orig_dsn = PREQ_IE_ORIG_DSN(hwmp_ie); |
300 | orig_lifetime = PREQ_IE_LIFETIME(hwmp_ie); | 300 | orig_lifetime = PREQ_IE_LIFETIME(hwmp_ie); |
301 | orig_metric = PREQ_IE_METRIC(hwmp_ie); | 301 | orig_metric = PREQ_IE_METRIC(hwmp_ie); |
302 | break; | 302 | break; |
303 | case MPATH_PREP: | 303 | case MPATH_PREP: |
304 | /* Originator here refers to the MP that was the destination in | 304 | /* Originator here refers to the MP that was the destination in |
305 | * the Path Request. The draft refers to that MP as the | 305 | * the Path Request. The draft refers to that MP as the |
306 | * destination address, even though usually it is the origin of | 306 | * destination address, even though usually it is the origin of |
307 | * the PREP frame. We divert from the nomenclature in the draft | 307 | * the PREP frame. We divert from the nomenclature in the draft |
308 | * so that we can easily use a single function to gather path | 308 | * so that we can easily use a single function to gather path |
309 | * information from both PREQ and PREP frames. | 309 | * information from both PREQ and PREP frames. |
310 | */ | 310 | */ |
311 | orig_addr = PREP_IE_ORIG_ADDR(hwmp_ie); | 311 | orig_addr = PREP_IE_ORIG_ADDR(hwmp_ie); |
312 | orig_dsn = PREP_IE_ORIG_DSN(hwmp_ie); | 312 | orig_dsn = PREP_IE_ORIG_DSN(hwmp_ie); |
313 | orig_lifetime = PREP_IE_LIFETIME(hwmp_ie); | 313 | orig_lifetime = PREP_IE_LIFETIME(hwmp_ie); |
314 | orig_metric = PREP_IE_METRIC(hwmp_ie); | 314 | orig_metric = PREP_IE_METRIC(hwmp_ie); |
315 | break; | 315 | break; |
316 | default: | 316 | default: |
317 | rcu_read_unlock(); | 317 | rcu_read_unlock(); |
318 | return 0; | 318 | return 0; |
319 | } | 319 | } |
320 | new_metric = orig_metric + last_hop_metric; | 320 | new_metric = orig_metric + last_hop_metric; |
321 | if (new_metric < orig_metric) | 321 | if (new_metric < orig_metric) |
322 | new_metric = MAX_METRIC; | 322 | new_metric = MAX_METRIC; |
323 | exp_time = TU_TO_EXP_TIME(orig_lifetime); | 323 | exp_time = TU_TO_EXP_TIME(orig_lifetime); |
324 | 324 | ||
325 | if (memcmp(orig_addr, sdata->dev->dev_addr, ETH_ALEN) == 0) { | 325 | if (memcmp(orig_addr, sdata->dev->dev_addr, ETH_ALEN) == 0) { |
326 | /* This MP is the originator, we are not interested in this | 326 | /* This MP is the originator, we are not interested in this |
327 | * frame, except for updating transmitter's path info. | 327 | * frame, except for updating transmitter's path info. |
328 | */ | 328 | */ |
329 | process = false; | 329 | process = false; |
330 | fresh_info = false; | 330 | fresh_info = false; |
331 | } else { | 331 | } else { |
332 | mpath = mesh_path_lookup(orig_addr, sdata); | 332 | mpath = mesh_path_lookup(orig_addr, sdata); |
333 | if (mpath) { | 333 | if (mpath) { |
334 | spin_lock_bh(&mpath->state_lock); | 334 | spin_lock_bh(&mpath->state_lock); |
335 | if (mpath->flags & MESH_PATH_FIXED) | 335 | if (mpath->flags & MESH_PATH_FIXED) |
336 | fresh_info = false; | 336 | fresh_info = false; |
337 | else if ((mpath->flags & MESH_PATH_ACTIVE) && | 337 | else if ((mpath->flags & MESH_PATH_ACTIVE) && |
338 | (mpath->flags & MESH_PATH_DSN_VALID)) { | 338 | (mpath->flags & MESH_PATH_DSN_VALID)) { |
339 | if (DSN_GT(mpath->dsn, orig_dsn) || | 339 | if (DSN_GT(mpath->dsn, orig_dsn) || |
340 | (mpath->dsn == orig_dsn && | 340 | (mpath->dsn == orig_dsn && |
341 | action == MPATH_PREQ && | 341 | action == MPATH_PREQ && |
342 | new_metric > mpath->metric)) { | 342 | new_metric > mpath->metric)) { |
343 | process = false; | 343 | process = false; |
344 | fresh_info = false; | 344 | fresh_info = false; |
345 | } | 345 | } |
346 | } | 346 | } |
347 | } else { | 347 | } else { |
348 | mesh_path_add(orig_addr, sdata); | 348 | mesh_path_add(orig_addr, sdata); |
349 | mpath = mesh_path_lookup(orig_addr, sdata); | 349 | mpath = mesh_path_lookup(orig_addr, sdata); |
350 | if (!mpath) { | 350 | if (!mpath) { |
351 | rcu_read_unlock(); | 351 | rcu_read_unlock(); |
352 | return 0; | 352 | return 0; |
353 | } | 353 | } |
354 | spin_lock_bh(&mpath->state_lock); | 354 | spin_lock_bh(&mpath->state_lock); |
355 | } | 355 | } |
356 | 356 | ||
357 | if (fresh_info) { | 357 | if (fresh_info) { |
358 | mesh_path_assign_nexthop(mpath, sta); | 358 | mesh_path_assign_nexthop(mpath, sta); |
359 | mpath->flags |= MESH_PATH_DSN_VALID; | 359 | mpath->flags |= MESH_PATH_DSN_VALID; |
360 | mpath->metric = new_metric; | 360 | mpath->metric = new_metric; |
361 | mpath->dsn = orig_dsn; | 361 | mpath->dsn = orig_dsn; |
362 | mpath->exp_time = time_after(mpath->exp_time, exp_time) | 362 | mpath->exp_time = time_after(mpath->exp_time, exp_time) |
363 | ? mpath->exp_time : exp_time; | 363 | ? mpath->exp_time : exp_time; |
364 | mesh_path_activate(mpath); | 364 | mesh_path_activate(mpath); |
365 | spin_unlock_bh(&mpath->state_lock); | 365 | spin_unlock_bh(&mpath->state_lock); |
366 | mesh_path_tx_pending(mpath); | 366 | mesh_path_tx_pending(mpath); |
367 | /* draft says preq_id should be saved to, but there does | 367 | /* draft says preq_id should be saved to, but there does |
368 | * not seem to be any use for it, skipping by now | 368 | * not seem to be any use for it, skipping by now |
369 | */ | 369 | */ |
370 | } else | 370 | } else |
371 | spin_unlock_bh(&mpath->state_lock); | 371 | spin_unlock_bh(&mpath->state_lock); |
372 | } | 372 | } |
373 | 373 | ||
374 | /* Update and check transmitter routing info */ | 374 | /* Update and check transmitter routing info */ |
375 | ta = mgmt->sa; | 375 | ta = mgmt->sa; |
376 | if (memcmp(orig_addr, ta, ETH_ALEN) == 0) | 376 | if (memcmp(orig_addr, ta, ETH_ALEN) == 0) |
377 | fresh_info = false; | 377 | fresh_info = false; |
378 | else { | 378 | else { |
379 | fresh_info = true; | 379 | fresh_info = true; |
380 | 380 | ||
381 | mpath = mesh_path_lookup(ta, sdata); | 381 | mpath = mesh_path_lookup(ta, sdata); |
382 | if (mpath) { | 382 | if (mpath) { |
383 | spin_lock_bh(&mpath->state_lock); | 383 | spin_lock_bh(&mpath->state_lock); |
384 | if ((mpath->flags & MESH_PATH_FIXED) || | 384 | if ((mpath->flags & MESH_PATH_FIXED) || |
385 | ((mpath->flags & MESH_PATH_ACTIVE) && | 385 | ((mpath->flags & MESH_PATH_ACTIVE) && |
386 | (last_hop_metric > mpath->metric))) | 386 | (last_hop_metric > mpath->metric))) |
387 | fresh_info = false; | 387 | fresh_info = false; |
388 | } else { | 388 | } else { |
389 | mesh_path_add(ta, sdata); | 389 | mesh_path_add(ta, sdata); |
390 | mpath = mesh_path_lookup(ta, sdata); | 390 | mpath = mesh_path_lookup(ta, sdata); |
391 | if (!mpath) { | 391 | if (!mpath) { |
392 | rcu_read_unlock(); | 392 | rcu_read_unlock(); |
393 | return 0; | 393 | return 0; |
394 | } | 394 | } |
395 | spin_lock_bh(&mpath->state_lock); | 395 | spin_lock_bh(&mpath->state_lock); |
396 | } | 396 | } |
397 | 397 | ||
398 | if (fresh_info) { | 398 | if (fresh_info) { |
399 | mesh_path_assign_nexthop(mpath, sta); | 399 | mesh_path_assign_nexthop(mpath, sta); |
400 | mpath->flags &= ~MESH_PATH_DSN_VALID; | 400 | mpath->flags &= ~MESH_PATH_DSN_VALID; |
401 | mpath->metric = last_hop_metric; | 401 | mpath->metric = last_hop_metric; |
402 | mpath->exp_time = time_after(mpath->exp_time, exp_time) | 402 | mpath->exp_time = time_after(mpath->exp_time, exp_time) |
403 | ? mpath->exp_time : exp_time; | 403 | ? mpath->exp_time : exp_time; |
404 | mesh_path_activate(mpath); | 404 | mesh_path_activate(mpath); |
405 | spin_unlock_bh(&mpath->state_lock); | 405 | spin_unlock_bh(&mpath->state_lock); |
406 | mesh_path_tx_pending(mpath); | 406 | mesh_path_tx_pending(mpath); |
407 | } else | 407 | } else |
408 | spin_unlock_bh(&mpath->state_lock); | 408 | spin_unlock_bh(&mpath->state_lock); |
409 | } | 409 | } |
410 | 410 | ||
411 | rcu_read_unlock(); | 411 | rcu_read_unlock(); |
412 | 412 | ||
413 | return process ? new_metric : 0; | 413 | return process ? new_metric : 0; |
414 | } | 414 | } |
415 | 415 | ||
416 | static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, | 416 | static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, |
417 | struct ieee80211_mgmt *mgmt, | 417 | struct ieee80211_mgmt *mgmt, |
418 | u8 *preq_elem, u32 metric) | 418 | u8 *preq_elem, u32 metric) |
419 | { | 419 | { |
420 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 420 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
421 | struct mesh_path *mpath; | 421 | struct mesh_path *mpath; |
422 | u8 *dst_addr, *orig_addr; | 422 | u8 *dst_addr, *orig_addr; |
423 | u8 dst_flags, ttl; | 423 | u8 dst_flags, ttl; |
424 | u32 orig_dsn, dst_dsn, lifetime; | 424 | u32 orig_dsn, dst_dsn, lifetime; |
425 | bool reply = false; | 425 | bool reply = false; |
426 | bool forward = true; | 426 | bool forward = true; |
427 | 427 | ||
428 | /* Update destination DSN, if present */ | 428 | /* Update destination DSN, if present */ |
429 | dst_addr = PREQ_IE_DST_ADDR(preq_elem); | 429 | dst_addr = PREQ_IE_DST_ADDR(preq_elem); |
430 | orig_addr = PREQ_IE_ORIG_ADDR(preq_elem); | 430 | orig_addr = PREQ_IE_ORIG_ADDR(preq_elem); |
431 | dst_dsn = PREQ_IE_DST_DSN(preq_elem); | 431 | dst_dsn = PREQ_IE_DST_DSN(preq_elem); |
432 | orig_dsn = PREQ_IE_ORIG_DSN(preq_elem); | 432 | orig_dsn = PREQ_IE_ORIG_DSN(preq_elem); |
433 | dst_flags = PREQ_IE_DST_F(preq_elem); | 433 | dst_flags = PREQ_IE_DST_F(preq_elem); |
434 | 434 | ||
435 | if (memcmp(dst_addr, sdata->dev->dev_addr, ETH_ALEN) == 0) { | 435 | if (memcmp(dst_addr, sdata->dev->dev_addr, ETH_ALEN) == 0) { |
436 | forward = false; | 436 | forward = false; |
437 | reply = true; | 437 | reply = true; |
438 | metric = 0; | 438 | metric = 0; |
439 | if (time_after(jiffies, ifmsh->last_dsn_update + | 439 | if (time_after(jiffies, ifmsh->last_dsn_update + |
440 | net_traversal_jiffies(sdata)) || | 440 | net_traversal_jiffies(sdata)) || |
441 | time_before(jiffies, ifmsh->last_dsn_update)) { | 441 | time_before(jiffies, ifmsh->last_dsn_update)) { |
442 | dst_dsn = ++ifmsh->dsn; | 442 | dst_dsn = ++ifmsh->dsn; |
443 | ifmsh->last_dsn_update = jiffies; | 443 | ifmsh->last_dsn_update = jiffies; |
444 | } | 444 | } |
445 | } else { | 445 | } else { |
446 | rcu_read_lock(); | 446 | rcu_read_lock(); |
447 | mpath = mesh_path_lookup(dst_addr, sdata); | 447 | mpath = mesh_path_lookup(dst_addr, sdata); |
448 | if (mpath) { | 448 | if (mpath) { |
449 | if ((!(mpath->flags & MESH_PATH_DSN_VALID)) || | 449 | if ((!(mpath->flags & MESH_PATH_DSN_VALID)) || |
450 | DSN_LT(mpath->dsn, dst_dsn)) { | 450 | DSN_LT(mpath->dsn, dst_dsn)) { |
451 | mpath->dsn = dst_dsn; | 451 | mpath->dsn = dst_dsn; |
452 | mpath->flags |= MESH_PATH_DSN_VALID; | 452 | mpath->flags |= MESH_PATH_DSN_VALID; |
453 | } else if ((!(dst_flags & MP_F_DO)) && | 453 | } else if ((!(dst_flags & MP_F_DO)) && |
454 | (mpath->flags & MESH_PATH_ACTIVE)) { | 454 | (mpath->flags & MESH_PATH_ACTIVE)) { |
455 | reply = true; | 455 | reply = true; |
456 | metric = mpath->metric; | 456 | metric = mpath->metric; |
457 | dst_dsn = mpath->dsn; | 457 | dst_dsn = mpath->dsn; |
458 | if (dst_flags & MP_F_RF) | 458 | if (dst_flags & MP_F_RF) |
459 | dst_flags |= MP_F_DO; | 459 | dst_flags |= MP_F_DO; |
460 | else | 460 | else |
461 | forward = false; | 461 | forward = false; |
462 | } | 462 | } |
463 | } | 463 | } |
464 | rcu_read_unlock(); | 464 | rcu_read_unlock(); |
465 | } | 465 | } |
466 | 466 | ||
467 | if (reply) { | 467 | if (reply) { |
468 | lifetime = PREQ_IE_LIFETIME(preq_elem); | 468 | lifetime = PREQ_IE_LIFETIME(preq_elem); |
469 | ttl = ifmsh->mshcfg.dot11MeshTTL; | 469 | ttl = ifmsh->mshcfg.dot11MeshTTL; |
470 | if (ttl != 0) | 470 | if (ttl != 0) |
471 | mesh_path_sel_frame_tx(MPATH_PREP, 0, dst_addr, | 471 | mesh_path_sel_frame_tx(MPATH_PREP, 0, dst_addr, |
472 | cpu_to_le32(dst_dsn), 0, orig_addr, | 472 | cpu_to_le32(dst_dsn), 0, orig_addr, |
473 | cpu_to_le32(orig_dsn), mgmt->sa, 0, ttl, | 473 | cpu_to_le32(orig_dsn), mgmt->sa, 0, ttl, |
474 | cpu_to_le32(lifetime), cpu_to_le32(metric), | 474 | cpu_to_le32(lifetime), cpu_to_le32(metric), |
475 | 0, sdata); | 475 | 0, sdata); |
476 | else | 476 | else |
477 | ifmsh->mshstats.dropped_frames_ttl++; | 477 | ifmsh->mshstats.dropped_frames_ttl++; |
478 | } | 478 | } |
479 | 479 | ||
480 | if (forward) { | 480 | if (forward) { |
481 | u32 preq_id; | 481 | u32 preq_id; |
482 | u8 hopcount, flags; | 482 | u8 hopcount, flags; |
483 | 483 | ||
484 | ttl = PREQ_IE_TTL(preq_elem); | 484 | ttl = PREQ_IE_TTL(preq_elem); |
485 | lifetime = PREQ_IE_LIFETIME(preq_elem); | 485 | lifetime = PREQ_IE_LIFETIME(preq_elem); |
486 | if (ttl <= 1) { | 486 | if (ttl <= 1) { |
487 | ifmsh->mshstats.dropped_frames_ttl++; | 487 | ifmsh->mshstats.dropped_frames_ttl++; |
488 | return; | 488 | return; |
489 | } | 489 | } |
490 | --ttl; | 490 | --ttl; |
491 | flags = PREQ_IE_FLAGS(preq_elem); | 491 | flags = PREQ_IE_FLAGS(preq_elem); |
492 | preq_id = PREQ_IE_PREQ_ID(preq_elem); | 492 | preq_id = PREQ_IE_PREQ_ID(preq_elem); |
493 | hopcount = PREQ_IE_HOPCOUNT(preq_elem) + 1; | 493 | hopcount = PREQ_IE_HOPCOUNT(preq_elem) + 1; |
494 | mesh_path_sel_frame_tx(MPATH_PREQ, flags, orig_addr, | 494 | mesh_path_sel_frame_tx(MPATH_PREQ, flags, orig_addr, |
495 | cpu_to_le32(orig_dsn), dst_flags, dst_addr, | 495 | cpu_to_le32(orig_dsn), dst_flags, dst_addr, |
496 | cpu_to_le32(dst_dsn), sdata->dev->broadcast, | 496 | cpu_to_le32(dst_dsn), sdata->dev->broadcast, |
497 | hopcount, ttl, cpu_to_le32(lifetime), | 497 | hopcount, ttl, cpu_to_le32(lifetime), |
498 | cpu_to_le32(metric), cpu_to_le32(preq_id), | 498 | cpu_to_le32(metric), cpu_to_le32(preq_id), |
499 | sdata); | 499 | sdata); |
500 | ifmsh->mshstats.fwded_mcast++; | 500 | ifmsh->mshstats.fwded_mcast++; |
501 | ifmsh->mshstats.fwded_frames++; | 501 | ifmsh->mshstats.fwded_frames++; |
502 | } | 502 | } |
503 | } | 503 | } |
504 | 504 | ||
505 | 505 | ||
506 | static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, | 506 | static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, |
507 | struct ieee80211_mgmt *mgmt, | 507 | struct ieee80211_mgmt *mgmt, |
508 | u8 *prep_elem, u32 metric) | 508 | u8 *prep_elem, u32 metric) |
509 | { | 509 | { |
510 | struct mesh_path *mpath; | 510 | struct mesh_path *mpath; |
511 | u8 *dst_addr, *orig_addr; | 511 | u8 *dst_addr, *orig_addr; |
512 | u8 ttl, hopcount, flags; | 512 | u8 ttl, hopcount, flags; |
513 | u8 next_hop[ETH_ALEN]; | 513 | u8 next_hop[ETH_ALEN]; |
514 | u32 dst_dsn, orig_dsn, lifetime; | 514 | u32 dst_dsn, orig_dsn, lifetime; |
515 | 515 | ||
516 | /* Note that we divert from the draft nomenclature and denominate | 516 | /* Note that we divert from the draft nomenclature and denominate |
517 | * destination to what the draft refers to as origininator. So in this | 517 | * destination to what the draft refers to as origininator. So in this |
518 | * function destnation refers to the final destination of the PREP, | 518 | * function destnation refers to the final destination of the PREP, |
519 | * which corresponds with the originator of the PREQ which this PREP | 519 | * which corresponds with the originator of the PREQ which this PREP |
520 | * replies | 520 | * replies |
521 | */ | 521 | */ |
522 | dst_addr = PREP_IE_DST_ADDR(prep_elem); | 522 | dst_addr = PREP_IE_DST_ADDR(prep_elem); |
523 | if (memcmp(dst_addr, sdata->dev->dev_addr, ETH_ALEN) == 0) | 523 | if (memcmp(dst_addr, sdata->dev->dev_addr, ETH_ALEN) == 0) |
524 | /* destination, no forwarding required */ | 524 | /* destination, no forwarding required */ |
525 | return; | 525 | return; |
526 | 526 | ||
527 | ttl = PREP_IE_TTL(prep_elem); | 527 | ttl = PREP_IE_TTL(prep_elem); |
528 | if (ttl <= 1) { | 528 | if (ttl <= 1) { |
529 | sdata->u.mesh.mshstats.dropped_frames_ttl++; | 529 | sdata->u.mesh.mshstats.dropped_frames_ttl++; |
530 | return; | 530 | return; |
531 | } | 531 | } |
532 | 532 | ||
533 | rcu_read_lock(); | 533 | rcu_read_lock(); |
534 | mpath = mesh_path_lookup(dst_addr, sdata); | 534 | mpath = mesh_path_lookup(dst_addr, sdata); |
535 | if (mpath) | 535 | if (mpath) |
536 | spin_lock_bh(&mpath->state_lock); | 536 | spin_lock_bh(&mpath->state_lock); |
537 | else | 537 | else |
538 | goto fail; | 538 | goto fail; |
539 | if (!(mpath->flags & MESH_PATH_ACTIVE)) { | 539 | if (!(mpath->flags & MESH_PATH_ACTIVE)) { |
540 | spin_unlock_bh(&mpath->state_lock); | 540 | spin_unlock_bh(&mpath->state_lock); |
541 | goto fail; | 541 | goto fail; |
542 | } | 542 | } |
543 | memcpy(next_hop, mpath->next_hop->sta.addr, ETH_ALEN); | 543 | memcpy(next_hop, mpath->next_hop->sta.addr, ETH_ALEN); |
544 | spin_unlock_bh(&mpath->state_lock); | 544 | spin_unlock_bh(&mpath->state_lock); |
545 | --ttl; | 545 | --ttl; |
546 | flags = PREP_IE_FLAGS(prep_elem); | 546 | flags = PREP_IE_FLAGS(prep_elem); |
547 | lifetime = PREP_IE_LIFETIME(prep_elem); | 547 | lifetime = PREP_IE_LIFETIME(prep_elem); |
548 | hopcount = PREP_IE_HOPCOUNT(prep_elem) + 1; | 548 | hopcount = PREP_IE_HOPCOUNT(prep_elem) + 1; |
549 | orig_addr = PREP_IE_ORIG_ADDR(prep_elem); | 549 | orig_addr = PREP_IE_ORIG_ADDR(prep_elem); |
550 | dst_dsn = PREP_IE_DST_DSN(prep_elem); | 550 | dst_dsn = PREP_IE_DST_DSN(prep_elem); |
551 | orig_dsn = PREP_IE_ORIG_DSN(prep_elem); | 551 | orig_dsn = PREP_IE_ORIG_DSN(prep_elem); |
552 | 552 | ||
553 | mesh_path_sel_frame_tx(MPATH_PREP, flags, orig_addr, | 553 | mesh_path_sel_frame_tx(MPATH_PREP, flags, orig_addr, |
554 | cpu_to_le32(orig_dsn), 0, dst_addr, | 554 | cpu_to_le32(orig_dsn), 0, dst_addr, |
555 | cpu_to_le32(dst_dsn), mpath->next_hop->sta.addr, hopcount, ttl, | 555 | cpu_to_le32(dst_dsn), mpath->next_hop->sta.addr, hopcount, ttl, |
556 | cpu_to_le32(lifetime), cpu_to_le32(metric), | 556 | cpu_to_le32(lifetime), cpu_to_le32(metric), |
557 | 0, sdata); | 557 | 0, sdata); |
558 | rcu_read_unlock(); | 558 | rcu_read_unlock(); |
559 | 559 | ||
560 | sdata->u.mesh.mshstats.fwded_unicast++; | 560 | sdata->u.mesh.mshstats.fwded_unicast++; |
561 | sdata->u.mesh.mshstats.fwded_frames++; | 561 | sdata->u.mesh.mshstats.fwded_frames++; |
562 | return; | 562 | return; |
563 | 563 | ||
564 | fail: | 564 | fail: |
565 | rcu_read_unlock(); | 565 | rcu_read_unlock(); |
566 | sdata->u.mesh.mshstats.dropped_frames_no_route++; | 566 | sdata->u.mesh.mshstats.dropped_frames_no_route++; |
567 | return; | 567 | return; |
568 | } | 568 | } |
569 | 569 | ||
570 | static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata, | 570 | static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata, |
571 | struct ieee80211_mgmt *mgmt, u8 *perr_elem) | 571 | struct ieee80211_mgmt *mgmt, u8 *perr_elem) |
572 | { | 572 | { |
573 | struct mesh_path *mpath; | 573 | struct mesh_path *mpath; |
574 | u8 *ta, *dst_addr; | 574 | u8 *ta, *dst_addr; |
575 | u32 dst_dsn; | 575 | u32 dst_dsn; |
576 | 576 | ||
577 | ta = mgmt->sa; | 577 | ta = mgmt->sa; |
578 | dst_addr = PERR_IE_DST_ADDR(perr_elem); | 578 | dst_addr = PERR_IE_DST_ADDR(perr_elem); |
579 | dst_dsn = PERR_IE_DST_DSN(perr_elem); | 579 | dst_dsn = PERR_IE_DST_DSN(perr_elem); |
580 | rcu_read_lock(); | 580 | rcu_read_lock(); |
581 | mpath = mesh_path_lookup(dst_addr, sdata); | 581 | mpath = mesh_path_lookup(dst_addr, sdata); |
582 | if (mpath) { | 582 | if (mpath) { |
583 | spin_lock_bh(&mpath->state_lock); | 583 | spin_lock_bh(&mpath->state_lock); |
584 | if (mpath->flags & MESH_PATH_ACTIVE && | 584 | if (mpath->flags & MESH_PATH_ACTIVE && |
585 | memcmp(ta, mpath->next_hop->sta.addr, ETH_ALEN) == 0 && | 585 | memcmp(ta, mpath->next_hop->sta.addr, ETH_ALEN) == 0 && |
586 | (!(mpath->flags & MESH_PATH_DSN_VALID) || | 586 | (!(mpath->flags & MESH_PATH_DSN_VALID) || |
587 | DSN_GT(dst_dsn, mpath->dsn))) { | 587 | DSN_GT(dst_dsn, mpath->dsn))) { |
588 | mpath->flags &= ~MESH_PATH_ACTIVE; | 588 | mpath->flags &= ~MESH_PATH_ACTIVE; |
589 | mpath->dsn = dst_dsn; | 589 | mpath->dsn = dst_dsn; |
590 | spin_unlock_bh(&mpath->state_lock); | 590 | spin_unlock_bh(&mpath->state_lock); |
591 | mesh_path_error_tx(dst_addr, cpu_to_le32(dst_dsn), | 591 | mesh_path_error_tx(dst_addr, cpu_to_le32(dst_dsn), |
592 | sdata->dev->broadcast, sdata); | 592 | sdata->dev->broadcast, sdata); |
593 | } else | 593 | } else |
594 | spin_unlock_bh(&mpath->state_lock); | 594 | spin_unlock_bh(&mpath->state_lock); |
595 | } | 595 | } |
596 | rcu_read_unlock(); | 596 | rcu_read_unlock(); |
597 | } | 597 | } |
598 | 598 | ||
599 | 599 | ||
600 | 600 | ||
601 | void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, | 601 | void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, |
602 | struct ieee80211_mgmt *mgmt, | 602 | struct ieee80211_mgmt *mgmt, |
603 | size_t len) | 603 | size_t len) |
604 | { | 604 | { |
605 | struct ieee802_11_elems elems; | 605 | struct ieee802_11_elems elems; |
606 | size_t baselen; | 606 | size_t baselen; |
607 | u32 last_hop_metric; | 607 | u32 last_hop_metric; |
608 | 608 | ||
609 | /* need action_code */ | 609 | /* need action_code */ |
610 | if (len < IEEE80211_MIN_ACTION_SIZE + 1) | 610 | if (len < IEEE80211_MIN_ACTION_SIZE + 1) |
611 | return; | 611 | return; |
612 | 612 | ||
613 | baselen = (u8 *) mgmt->u.action.u.mesh_action.variable - (u8 *) mgmt; | 613 | baselen = (u8 *) mgmt->u.action.u.mesh_action.variable - (u8 *) mgmt; |
614 | ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable, | 614 | ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable, |
615 | len - baselen, &elems); | 615 | len - baselen, &elems); |
616 | 616 | ||
617 | switch (mgmt->u.action.u.mesh_action.action_code) { | 617 | switch (mgmt->u.action.u.mesh_action.action_code) { |
618 | case MPATH_PREQ: | 618 | case MPATH_PREQ: |
619 | if (!elems.preq || elems.preq_len != 37) | 619 | if (!elems.preq || elems.preq_len != 37) |
620 | /* Right now we support just 1 destination and no AE */ | 620 | /* Right now we support just 1 destination and no AE */ |
621 | return; | 621 | return; |
622 | last_hop_metric = hwmp_route_info_get(sdata, mgmt, elems.preq); | 622 | last_hop_metric = hwmp_route_info_get(sdata, mgmt, elems.preq); |
623 | if (!last_hop_metric) | 623 | if (!last_hop_metric) |
624 | return; | 624 | return; |
625 | hwmp_preq_frame_process(sdata, mgmt, elems.preq, last_hop_metric); | 625 | hwmp_preq_frame_process(sdata, mgmt, elems.preq, last_hop_metric); |
626 | break; | 626 | break; |
627 | case MPATH_PREP: | 627 | case MPATH_PREP: |
628 | if (!elems.prep || elems.prep_len != 31) | 628 | if (!elems.prep || elems.prep_len != 31) |
629 | /* Right now we support no AE */ | 629 | /* Right now we support no AE */ |
630 | return; | 630 | return; |
631 | last_hop_metric = hwmp_route_info_get(sdata, mgmt, elems.prep); | 631 | last_hop_metric = hwmp_route_info_get(sdata, mgmt, elems.prep); |
632 | if (!last_hop_metric) | 632 | if (!last_hop_metric) |
633 | return; | 633 | return; |
634 | hwmp_prep_frame_process(sdata, mgmt, elems.prep, last_hop_metric); | 634 | hwmp_prep_frame_process(sdata, mgmt, elems.prep, last_hop_metric); |
635 | break; | 635 | break; |
636 | case MPATH_PERR: | 636 | case MPATH_PERR: |
637 | if (!elems.perr || elems.perr_len != 12) | 637 | if (!elems.perr || elems.perr_len != 12) |
638 | /* Right now we support only one destination per PERR */ | 638 | /* Right now we support only one destination per PERR */ |
639 | return; | 639 | return; |
640 | hwmp_perr_frame_process(sdata, mgmt, elems.perr); | 640 | hwmp_perr_frame_process(sdata, mgmt, elems.perr); |
641 | default: | 641 | default: |
642 | return; | 642 | return; |
643 | } | 643 | } |
644 | 644 | ||
645 | } | 645 | } |
646 | 646 | ||
647 | /** | 647 | /** |
648 | * mesh_queue_preq - queue a PREQ to a given destination | 648 | * mesh_queue_preq - queue a PREQ to a given destination |
649 | * | 649 | * |
650 | * @mpath: mesh path to discover | 650 | * @mpath: mesh path to discover |
651 | * @flags: special attributes of the PREQ to be sent | 651 | * @flags: special attributes of the PREQ to be sent |
652 | * | 652 | * |
653 | * Locking: the function must be called from within a rcu read lock block. | 653 | * Locking: the function must be called from within a rcu read lock block. |
654 | * | 654 | * |
655 | */ | 655 | */ |
656 | static void mesh_queue_preq(struct mesh_path *mpath, u8 flags) | 656 | static void mesh_queue_preq(struct mesh_path *mpath, u8 flags) |
657 | { | 657 | { |
658 | struct ieee80211_sub_if_data *sdata = mpath->sdata; | 658 | struct ieee80211_sub_if_data *sdata = mpath->sdata; |
659 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 659 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
660 | struct mesh_preq_queue *preq_node; | 660 | struct mesh_preq_queue *preq_node; |
661 | 661 | ||
662 | preq_node = kmalloc(sizeof(struct mesh_preq_queue), GFP_ATOMIC); | 662 | preq_node = kmalloc(sizeof(struct mesh_preq_queue), GFP_ATOMIC); |
663 | if (!preq_node) { | 663 | if (!preq_node) { |
664 | printk(KERN_DEBUG "Mesh HWMP: could not allocate PREQ node\n"); | 664 | printk(KERN_DEBUG "Mesh HWMP: could not allocate PREQ node\n"); |
665 | return; | 665 | return; |
666 | } | 666 | } |
667 | 667 | ||
668 | spin_lock(&ifmsh->mesh_preq_queue_lock); | 668 | spin_lock(&ifmsh->mesh_preq_queue_lock); |
669 | if (ifmsh->preq_queue_len == MAX_PREQ_QUEUE_LEN) { | 669 | if (ifmsh->preq_queue_len == MAX_PREQ_QUEUE_LEN) { |
670 | spin_unlock(&ifmsh->mesh_preq_queue_lock); | 670 | spin_unlock(&ifmsh->mesh_preq_queue_lock); |
671 | kfree(preq_node); | 671 | kfree(preq_node); |
672 | if (printk_ratelimit()) | 672 | if (printk_ratelimit()) |
673 | printk(KERN_DEBUG "Mesh HWMP: PREQ node queue full\n"); | 673 | printk(KERN_DEBUG "Mesh HWMP: PREQ node queue full\n"); |
674 | return; | 674 | return; |
675 | } | 675 | } |
676 | 676 | ||
677 | memcpy(preq_node->dst, mpath->dst, ETH_ALEN); | 677 | memcpy(preq_node->dst, mpath->dst, ETH_ALEN); |
678 | preq_node->flags = flags; | 678 | preq_node->flags = flags; |
679 | 679 | ||
680 | list_add_tail(&preq_node->list, &ifmsh->preq_queue.list); | 680 | list_add_tail(&preq_node->list, &ifmsh->preq_queue.list); |
681 | ++ifmsh->preq_queue_len; | 681 | ++ifmsh->preq_queue_len; |
682 | spin_unlock(&ifmsh->mesh_preq_queue_lock); | 682 | spin_unlock(&ifmsh->mesh_preq_queue_lock); |
683 | 683 | ||
684 | if (time_after(jiffies, ifmsh->last_preq + min_preq_int_jiff(sdata))) | 684 | if (time_after(jiffies, ifmsh->last_preq + min_preq_int_jiff(sdata))) |
685 | ieee80211_queue_work(&sdata->local->hw, &ifmsh->work); | 685 | ieee80211_queue_work(&sdata->local->hw, &ifmsh->work); |
686 | 686 | ||
687 | else if (time_before(jiffies, ifmsh->last_preq)) { | 687 | else if (time_before(jiffies, ifmsh->last_preq)) { |
688 | /* avoid long wait if did not send preqs for a long time | 688 | /* avoid long wait if did not send preqs for a long time |
689 | * and jiffies wrapped around | 689 | * and jiffies wrapped around |
690 | */ | 690 | */ |
691 | ifmsh->last_preq = jiffies - min_preq_int_jiff(sdata) - 1; | 691 | ifmsh->last_preq = jiffies - min_preq_int_jiff(sdata) - 1; |
692 | ieee80211_queue_work(&sdata->local->hw, &ifmsh->work); | 692 | ieee80211_queue_work(&sdata->local->hw, &ifmsh->work); |
693 | } else | 693 | } else |
694 | mod_timer(&ifmsh->mesh_path_timer, ifmsh->last_preq + | 694 | mod_timer(&ifmsh->mesh_path_timer, ifmsh->last_preq + |
695 | min_preq_int_jiff(sdata)); | 695 | min_preq_int_jiff(sdata)); |
696 | } | 696 | } |
697 | 697 | ||
698 | /** | 698 | /** |
699 | * mesh_path_start_discovery - launch a path discovery from the PREQ queue | 699 | * mesh_path_start_discovery - launch a path discovery from the PREQ queue |
700 | * | 700 | * |
701 | * @sdata: local mesh subif | 701 | * @sdata: local mesh subif |
702 | */ | 702 | */ |
703 | void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata) | 703 | void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata) |
704 | { | 704 | { |
705 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 705 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
706 | struct mesh_preq_queue *preq_node; | 706 | struct mesh_preq_queue *preq_node; |
707 | struct mesh_path *mpath; | 707 | struct mesh_path *mpath; |
708 | u8 ttl, dst_flags; | 708 | u8 ttl, dst_flags; |
709 | u32 lifetime; | 709 | u32 lifetime; |
710 | 710 | ||
711 | spin_lock_bh(&ifmsh->mesh_preq_queue_lock); | 711 | spin_lock_bh(&ifmsh->mesh_preq_queue_lock); |
712 | if (!ifmsh->preq_queue_len || | 712 | if (!ifmsh->preq_queue_len || |
713 | time_before(jiffies, ifmsh->last_preq + | 713 | time_before(jiffies, ifmsh->last_preq + |
714 | min_preq_int_jiff(sdata))) { | 714 | min_preq_int_jiff(sdata))) { |
715 | spin_unlock_bh(&ifmsh->mesh_preq_queue_lock); | 715 | spin_unlock_bh(&ifmsh->mesh_preq_queue_lock); |
716 | return; | 716 | return; |
717 | } | 717 | } |
718 | 718 | ||
719 | preq_node = list_first_entry(&ifmsh->preq_queue.list, | 719 | preq_node = list_first_entry(&ifmsh->preq_queue.list, |
720 | struct mesh_preq_queue, list); | 720 | struct mesh_preq_queue, list); |
721 | list_del(&preq_node->list); | 721 | list_del(&preq_node->list); |
722 | --ifmsh->preq_queue_len; | 722 | --ifmsh->preq_queue_len; |
723 | spin_unlock_bh(&ifmsh->mesh_preq_queue_lock); | 723 | spin_unlock_bh(&ifmsh->mesh_preq_queue_lock); |
724 | 724 | ||
725 | rcu_read_lock(); | 725 | rcu_read_lock(); |
726 | mpath = mesh_path_lookup(preq_node->dst, sdata); | 726 | mpath = mesh_path_lookup(preq_node->dst, sdata); |
727 | if (!mpath) | 727 | if (!mpath) |
728 | goto enddiscovery; | 728 | goto enddiscovery; |
729 | 729 | ||
730 | spin_lock_bh(&mpath->state_lock); | 730 | spin_lock_bh(&mpath->state_lock); |
731 | if (preq_node->flags & PREQ_Q_F_START) { | 731 | if (preq_node->flags & PREQ_Q_F_START) { |
732 | if (mpath->flags & MESH_PATH_RESOLVING) { | 732 | if (mpath->flags & MESH_PATH_RESOLVING) { |
733 | spin_unlock_bh(&mpath->state_lock); | 733 | spin_unlock_bh(&mpath->state_lock); |
734 | goto enddiscovery; | 734 | goto enddiscovery; |
735 | } else { | 735 | } else { |
736 | mpath->flags &= ~MESH_PATH_RESOLVED; | 736 | mpath->flags &= ~MESH_PATH_RESOLVED; |
737 | mpath->flags |= MESH_PATH_RESOLVING; | 737 | mpath->flags |= MESH_PATH_RESOLVING; |
738 | mpath->discovery_retries = 0; | 738 | mpath->discovery_retries = 0; |
739 | mpath->discovery_timeout = disc_timeout_jiff(sdata); | 739 | mpath->discovery_timeout = disc_timeout_jiff(sdata); |
740 | } | 740 | } |
741 | } else if (!(mpath->flags & MESH_PATH_RESOLVING) || | 741 | } else if (!(mpath->flags & MESH_PATH_RESOLVING) || |
742 | mpath->flags & MESH_PATH_RESOLVED) { | 742 | mpath->flags & MESH_PATH_RESOLVED) { |
743 | mpath->flags &= ~MESH_PATH_RESOLVING; | 743 | mpath->flags &= ~MESH_PATH_RESOLVING; |
744 | spin_unlock_bh(&mpath->state_lock); | 744 | spin_unlock_bh(&mpath->state_lock); |
745 | goto enddiscovery; | 745 | goto enddiscovery; |
746 | } | 746 | } |
747 | 747 | ||
748 | ifmsh->last_preq = jiffies; | 748 | ifmsh->last_preq = jiffies; |
749 | 749 | ||
750 | if (time_after(jiffies, ifmsh->last_dsn_update + | 750 | if (time_after(jiffies, ifmsh->last_dsn_update + |
751 | net_traversal_jiffies(sdata)) || | 751 | net_traversal_jiffies(sdata)) || |
752 | time_before(jiffies, ifmsh->last_dsn_update)) { | 752 | time_before(jiffies, ifmsh->last_dsn_update)) { |
753 | ++ifmsh->dsn; | 753 | ++ifmsh->dsn; |
754 | sdata->u.mesh.last_dsn_update = jiffies; | 754 | sdata->u.mesh.last_dsn_update = jiffies; |
755 | } | 755 | } |
756 | lifetime = default_lifetime(sdata); | 756 | lifetime = default_lifetime(sdata); |
757 | ttl = sdata->u.mesh.mshcfg.dot11MeshTTL; | 757 | ttl = sdata->u.mesh.mshcfg.dot11MeshTTL; |
758 | if (ttl == 0) { | 758 | if (ttl == 0) { |
759 | sdata->u.mesh.mshstats.dropped_frames_ttl++; | 759 | sdata->u.mesh.mshstats.dropped_frames_ttl++; |
760 | spin_unlock_bh(&mpath->state_lock); | 760 | spin_unlock_bh(&mpath->state_lock); |
761 | goto enddiscovery; | 761 | goto enddiscovery; |
762 | } | 762 | } |
763 | 763 | ||
764 | if (preq_node->flags & PREQ_Q_F_REFRESH) | 764 | if (preq_node->flags & PREQ_Q_F_REFRESH) |
765 | dst_flags = MP_F_DO; | 765 | dst_flags = MP_F_DO; |
766 | else | 766 | else |
767 | dst_flags = MP_F_RF; | 767 | dst_flags = MP_F_RF; |
768 | 768 | ||
769 | spin_unlock_bh(&mpath->state_lock); | 769 | spin_unlock_bh(&mpath->state_lock); |
770 | mesh_path_sel_frame_tx(MPATH_PREQ, 0, sdata->dev->dev_addr, | 770 | mesh_path_sel_frame_tx(MPATH_PREQ, 0, sdata->dev->dev_addr, |
771 | cpu_to_le32(ifmsh->dsn), dst_flags, mpath->dst, | 771 | cpu_to_le32(ifmsh->dsn), dst_flags, mpath->dst, |
772 | cpu_to_le32(mpath->dsn), sdata->dev->broadcast, 0, | 772 | cpu_to_le32(mpath->dsn), sdata->dev->broadcast, 0, |
773 | ttl, cpu_to_le32(lifetime), 0, | 773 | ttl, cpu_to_le32(lifetime), 0, |
774 | cpu_to_le32(ifmsh->preq_id++), sdata); | 774 | cpu_to_le32(ifmsh->preq_id++), sdata); |
775 | mod_timer(&mpath->timer, jiffies + mpath->discovery_timeout); | 775 | mod_timer(&mpath->timer, jiffies + mpath->discovery_timeout); |
776 | 776 | ||
777 | enddiscovery: | 777 | enddiscovery: |
778 | rcu_read_unlock(); | 778 | rcu_read_unlock(); |
779 | kfree(preq_node); | 779 | kfree(preq_node); |
780 | } | 780 | } |
781 | 781 | ||
782 | /** | 782 | /** |
783 | * mesh_nexthop_lookup - put the appropriate next hop on a mesh frame | 783 | * mesh_nexthop_lookup - put the appropriate next hop on a mesh frame |
784 | * | 784 | * |
785 | * @skb: 802.11 frame to be sent | 785 | * @skb: 802.11 frame to be sent |
786 | * @sdata: network subif the frame will be sent through | 786 | * @sdata: network subif the frame will be sent through |
787 | * | 787 | * |
788 | * Returns: 0 if the next hop was found. Nonzero otherwise. If no next hop is | 788 | * Returns: 0 if the next hop was found. Nonzero otherwise. If no next hop is |
789 | * found, the function will start a path discovery and queue the frame so it is | 789 | * found, the function will start a path discovery and queue the frame so it is |
790 | * sent when the path is resolved. This means the caller must not free the skb | 790 | * sent when the path is resolved. This means the caller must not free the skb |
791 | * in this case. | 791 | * in this case. |
792 | */ | 792 | */ |
793 | int mesh_nexthop_lookup(struct sk_buff *skb, | 793 | int mesh_nexthop_lookup(struct sk_buff *skb, |
794 | struct ieee80211_sub_if_data *sdata) | 794 | struct ieee80211_sub_if_data *sdata) |
795 | { | 795 | { |
796 | struct sk_buff *skb_to_free = NULL; | 796 | struct sk_buff *skb_to_free = NULL; |
797 | struct mesh_path *mpath; | 797 | struct mesh_path *mpath; |
798 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 798 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
799 | u8 *dst_addr = hdr->addr3; | 799 | u8 *dst_addr = hdr->addr3; |
800 | int err = 0; | 800 | int err = 0; |
801 | 801 | ||
802 | rcu_read_lock(); | 802 | rcu_read_lock(); |
803 | mpath = mesh_path_lookup(dst_addr, sdata); | 803 | mpath = mesh_path_lookup(dst_addr, sdata); |
804 | 804 | ||
805 | if (!mpath) { | 805 | if (!mpath) { |
806 | mesh_path_add(dst_addr, sdata); | 806 | mesh_path_add(dst_addr, sdata); |
807 | mpath = mesh_path_lookup(dst_addr, sdata); | 807 | mpath = mesh_path_lookup(dst_addr, sdata); |
808 | if (!mpath) { | 808 | if (!mpath) { |
809 | sdata->u.mesh.mshstats.dropped_frames_no_route++; | 809 | sdata->u.mesh.mshstats.dropped_frames_no_route++; |
810 | err = -ENOSPC; | 810 | err = -ENOSPC; |
811 | goto endlookup; | 811 | goto endlookup; |
812 | } | 812 | } |
813 | } | 813 | } |
814 | 814 | ||
815 | if (mpath->flags & MESH_PATH_ACTIVE) { | 815 | if (mpath->flags & MESH_PATH_ACTIVE) { |
816 | if (time_after(jiffies, mpath->exp_time + | 816 | if (time_after(jiffies, mpath->exp_time + |
817 | msecs_to_jiffies(sdata->u.mesh.mshcfg.path_refresh_time)) | 817 | msecs_to_jiffies(sdata->u.mesh.mshcfg.path_refresh_time)) |
818 | && !memcmp(sdata->dev->dev_addr, hdr->addr4, | 818 | && !memcmp(sdata->dev->dev_addr, hdr->addr4, |
819 | ETH_ALEN) | 819 | ETH_ALEN) |
820 | && !(mpath->flags & MESH_PATH_RESOLVING) | 820 | && !(mpath->flags & MESH_PATH_RESOLVING) |
821 | && !(mpath->flags & MESH_PATH_FIXED)) { | 821 | && !(mpath->flags & MESH_PATH_FIXED)) { |
822 | mesh_queue_preq(mpath, | 822 | mesh_queue_preq(mpath, |
823 | PREQ_Q_F_START | PREQ_Q_F_REFRESH); | 823 | PREQ_Q_F_START | PREQ_Q_F_REFRESH); |
824 | } | 824 | } |
825 | memcpy(hdr->addr1, mpath->next_hop->sta.addr, | 825 | memcpy(hdr->addr1, mpath->next_hop->sta.addr, |
826 | ETH_ALEN); | 826 | ETH_ALEN); |
827 | } else { | 827 | } else { |
828 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 828 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
829 | if (!(mpath->flags & MESH_PATH_RESOLVING)) { | 829 | if (!(mpath->flags & MESH_PATH_RESOLVING)) { |
830 | /* Start discovery only if it is not running yet */ | 830 | /* Start discovery only if it is not running yet */ |
831 | mesh_queue_preq(mpath, PREQ_Q_F_START); | 831 | mesh_queue_preq(mpath, PREQ_Q_F_START); |
832 | } | 832 | } |
833 | 833 | ||
834 | if (skb_queue_len(&mpath->frame_queue) >= | 834 | if (skb_queue_len(&mpath->frame_queue) >= |
835 | MESH_FRAME_QUEUE_LEN) | 835 | MESH_FRAME_QUEUE_LEN) |
836 | skb_to_free = skb_dequeue(&mpath->frame_queue); | 836 | skb_to_free = skb_dequeue(&mpath->frame_queue); |
837 | 837 | ||
838 | info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; | 838 | info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; |
839 | skb_queue_tail(&mpath->frame_queue, skb); | 839 | skb_queue_tail(&mpath->frame_queue, skb); |
840 | if (skb_to_free) | 840 | if (skb_to_free) |
841 | mesh_path_discard_frame(skb_to_free, sdata); | 841 | mesh_path_discard_frame(skb_to_free, sdata); |
842 | err = -ENOENT; | 842 | err = -ENOENT; |
843 | } | 843 | } |
844 | 844 | ||
845 | endlookup: | 845 | endlookup: |
846 | rcu_read_unlock(); | 846 | rcu_read_unlock(); |
847 | return err; | 847 | return err; |
848 | } | 848 | } |
849 | 849 | ||
850 | void mesh_path_timer(unsigned long data) | 850 | void mesh_path_timer(unsigned long data) |
851 | { | 851 | { |
852 | struct ieee80211_sub_if_data *sdata; | 852 | struct ieee80211_sub_if_data *sdata; |
853 | struct mesh_path *mpath; | 853 | struct mesh_path *mpath; |
854 | 854 | ||
855 | rcu_read_lock(); | 855 | rcu_read_lock(); |
856 | mpath = (struct mesh_path *) data; | 856 | mpath = (struct mesh_path *) data; |
857 | mpath = rcu_dereference(mpath); | 857 | mpath = rcu_dereference(mpath); |
858 | if (!mpath) | 858 | if (!mpath) |
859 | goto endmpathtimer; | 859 | goto endmpathtimer; |
860 | sdata = mpath->sdata; | 860 | sdata = mpath->sdata; |
861 | 861 | ||
862 | if (sdata->local->quiescing) { | 862 | if (sdata->local->quiescing) { |
863 | rcu_read_unlock(); | 863 | rcu_read_unlock(); |
864 | return; | 864 | return; |
865 | } | 865 | } |
866 | 866 | ||
867 | spin_lock_bh(&mpath->state_lock); | 867 | spin_lock_bh(&mpath->state_lock); |
868 | if (mpath->flags & MESH_PATH_RESOLVED || | 868 | if (mpath->flags & MESH_PATH_RESOLVED || |
869 | (!(mpath->flags & MESH_PATH_RESOLVING))) | 869 | (!(mpath->flags & MESH_PATH_RESOLVING))) |
870 | mpath->flags &= ~(MESH_PATH_RESOLVING | MESH_PATH_RESOLVED); | 870 | mpath->flags &= ~(MESH_PATH_RESOLVING | MESH_PATH_RESOLVED); |
871 | else if (mpath->discovery_retries < max_preq_retries(sdata)) { | 871 | else if (mpath->discovery_retries < max_preq_retries(sdata)) { |
872 | ++mpath->discovery_retries; | 872 | ++mpath->discovery_retries; |
873 | mpath->discovery_timeout *= 2; | 873 | mpath->discovery_timeout *= 2; |
874 | mesh_queue_preq(mpath, 0); | 874 | mesh_queue_preq(mpath, 0); |
875 | } else { | 875 | } else { |
876 | mpath->flags = 0; | 876 | mpath->flags = 0; |
877 | mpath->exp_time = jiffies; | 877 | mpath->exp_time = jiffies; |
878 | mesh_path_flush_pending(mpath); | 878 | mesh_path_flush_pending(mpath); |
879 | } | 879 | } |
880 | 880 | ||
881 | spin_unlock_bh(&mpath->state_lock); | 881 | spin_unlock_bh(&mpath->state_lock); |
882 | endmpathtimer: | 882 | endmpathtimer: |
883 | rcu_read_unlock(); | 883 | rcu_read_unlock(); |
884 | } | 884 | } |
885 | 885 |