diff options
-rw-r--r-- | include/linux/nl80211.h | 119 | ||||
-rw-r--r-- | include/net/cfg80211.h | 139 | ||||
-rw-r--r-- | net/mac80211/cfg.c | 20 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 438 |
4 files changed, 650 insertions, 66 deletions
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index a9f0b93324a2..ea6517e58b04 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h | |||
@@ -78,6 +78,18 @@ | |||
78 | * or, if no MAC address given, all stations, on the interface identified | 78 | * or, if no MAC address given, all stations, on the interface identified |
79 | * by %NL80211_ATTR_IFINDEX. | 79 | * by %NL80211_ATTR_IFINDEX. |
80 | * | 80 | * |
81 | * @NL80211_CMD_GET_MPATH: Get mesh path attributes for mesh path to | ||
82 | * destination %NL80211_ATTR_MAC on the interface identified by | ||
83 | * %NL80211_ATTR_IFINDEX. | ||
84 | * @NL80211_CMD_SET_MPATH: Set mesh path attributes for mesh path to | ||
85 | * destination %NL80211_ATTR_MAC on the interface identified by | ||
86 | * %NL80211_ATTR_IFINDEX. | ||
87 | * @NL80211_CMD_NEW_PATH: Add a mesh path with given attributes to the | ||
88 | * the interface identified by %NL80211_ATTR_IFINDEX. | ||
89 | * @NL80211_CMD_DEL_PATH: Remove a mesh path identified by %NL80211_ATTR_MAC | ||
90 | * or, if no MAC address given, all mesh paths, on the interface identified | ||
91 | * by %NL80211_ATTR_IFINDEX. | ||
92 | * | ||
81 | * @NL80211_CMD_MAX: highest used command number | 93 | * @NL80211_CMD_MAX: highest used command number |
82 | * @__NL80211_CMD_AFTER_LAST: internal use | 94 | * @__NL80211_CMD_AFTER_LAST: internal use |
83 | */ | 95 | */ |
@@ -112,6 +124,11 @@ enum nl80211_commands { | |||
112 | 124 | ||
113 | /* add commands here */ | 125 | /* add commands here */ |
114 | 126 | ||
127 | NL80211_CMD_GET_MPATH, | ||
128 | NL80211_CMD_SET_MPATH, | ||
129 | NL80211_CMD_NEW_MPATH, | ||
130 | NL80211_CMD_DEL_MPATH, | ||
131 | |||
115 | /* used to define NL80211_CMD_MAX below */ | 132 | /* used to define NL80211_CMD_MAX below */ |
116 | __NL80211_CMD_AFTER_LAST, | 133 | __NL80211_CMD_AFTER_LAST, |
117 | NL80211_CMD_MAX = __NL80211_CMD_AFTER_LAST - 1 | 134 | NL80211_CMD_MAX = __NL80211_CMD_AFTER_LAST - 1 |
@@ -157,13 +174,21 @@ enum nl80211_commands { | |||
157 | * restriction (at most %NL80211_MAX_SUPP_RATES). | 174 | * restriction (at most %NL80211_MAX_SUPP_RATES). |
158 | * @NL80211_ATTR_STA_VLAN: interface index of VLAN interface to move station | 175 | * @NL80211_ATTR_STA_VLAN: interface index of VLAN interface to move station |
159 | * to, or the AP interface the station was originally added to to. | 176 | * to, or the AP interface the station was originally added to to. |
160 | * @NL80211_ATTR_STA_STATS: statistics for a station, part of station info | 177 | * @NL80211_ATTR_STA_INFO: information about a station, part of station info |
161 | * given for %NL80211_CMD_GET_STATION, nested attribute containing | 178 | * given for %NL80211_CMD_GET_STATION, nested attribute containing |
162 | * info as possible, see &enum nl80211_sta_stats. | 179 | * info as possible, see &enum nl80211_sta_info. |
163 | * | 180 | * |
164 | * @NL80211_ATTR_WIPHY_BANDS: Information about an operating bands, | 181 | * @NL80211_ATTR_WIPHY_BANDS: Information about an operating bands, |
165 | * consisting of a nested array. | 182 | * consisting of a nested array. |
166 | * | 183 | * |
184 | * @NL80211_ATTR_MESH_ID: mesh id (1-32 bytes). | ||
185 | * @NL80211_ATTR_PLINK_ACTION: action to perform on the mesh peer link. | ||
186 | * @NL80211_ATTR_MPATH_NEXT_HOP: MAC address of the next hop for a mesh path. | ||
187 | * @NL80211_ATTR_MPATH_INFO: information about a mesh_path, part of mesh path | ||
188 | * info given for %NL80211_CMD_GET_MPATH, nested attribute described at | ||
189 | * &enum nl80211_mpath_info. | ||
190 | * | ||
191 | * | ||
167 | * @NL80211_ATTR_MNTR_FLAGS: flags, nested element with NLA_FLAG attributes of | 192 | * @NL80211_ATTR_MNTR_FLAGS: flags, nested element with NLA_FLAG attributes of |
168 | * &enum nl80211_mntr_flags. | 193 | * &enum nl80211_mntr_flags. |
169 | * | 194 | * |
@@ -199,7 +224,7 @@ enum nl80211_attrs { | |||
199 | NL80211_ATTR_STA_LISTEN_INTERVAL, | 224 | NL80211_ATTR_STA_LISTEN_INTERVAL, |
200 | NL80211_ATTR_STA_SUPPORTED_RATES, | 225 | NL80211_ATTR_STA_SUPPORTED_RATES, |
201 | NL80211_ATTR_STA_VLAN, | 226 | NL80211_ATTR_STA_VLAN, |
202 | NL80211_ATTR_STA_STATS, | 227 | NL80211_ATTR_STA_INFO, |
203 | 228 | ||
204 | NL80211_ATTR_WIPHY_BANDS, | 229 | NL80211_ATTR_WIPHY_BANDS, |
205 | 230 | ||
@@ -207,6 +232,11 @@ enum nl80211_attrs { | |||
207 | 232 | ||
208 | /* add attributes here, update the policy in nl80211.c */ | 233 | /* add attributes here, update the policy in nl80211.c */ |
209 | 234 | ||
235 | NL80211_ATTR_MESH_ID, | ||
236 | NL80211_ATTR_STA_PLINK_ACTION, | ||
237 | NL80211_ATTR_MPATH_NEXT_HOP, | ||
238 | NL80211_ATTR_MPATH_INFO, | ||
239 | |||
210 | __NL80211_ATTR_AFTER_LAST, | 240 | __NL80211_ATTR_AFTER_LAST, |
211 | NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1 | 241 | NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1 |
212 | }; | 242 | }; |
@@ -223,6 +253,7 @@ enum nl80211_attrs { | |||
223 | * @NL80211_IFTYPE_AP_VLAN: VLAN interface for access points | 253 | * @NL80211_IFTYPE_AP_VLAN: VLAN interface for access points |
224 | * @NL80211_IFTYPE_WDS: wireless distribution interface | 254 | * @NL80211_IFTYPE_WDS: wireless distribution interface |
225 | * @NL80211_IFTYPE_MONITOR: monitor interface receiving all frames | 255 | * @NL80211_IFTYPE_MONITOR: monitor interface receiving all frames |
256 | * @NL80211_IFTYPE_MESH_POINT: mesh point | ||
226 | * @NL80211_IFTYPE_MAX: highest interface type number currently defined | 257 | * @NL80211_IFTYPE_MAX: highest interface type number currently defined |
227 | * @__NL80211_IFTYPE_AFTER_LAST: internal use | 258 | * @__NL80211_IFTYPE_AFTER_LAST: internal use |
228 | * | 259 | * |
@@ -238,6 +269,7 @@ enum nl80211_iftype { | |||
238 | NL80211_IFTYPE_AP_VLAN, | 269 | NL80211_IFTYPE_AP_VLAN, |
239 | NL80211_IFTYPE_WDS, | 270 | NL80211_IFTYPE_WDS, |
240 | NL80211_IFTYPE_MONITOR, | 271 | NL80211_IFTYPE_MONITOR, |
272 | NL80211_IFTYPE_MESH_POINT, | ||
241 | 273 | ||
242 | /* keep last */ | 274 | /* keep last */ |
243 | __NL80211_IFTYPE_AFTER_LAST, | 275 | __NL80211_IFTYPE_AFTER_LAST, |
@@ -267,27 +299,78 @@ enum nl80211_sta_flags { | |||
267 | }; | 299 | }; |
268 | 300 | ||
269 | /** | 301 | /** |
270 | * enum nl80211_sta_stats - station statistics | 302 | * enum nl80211_sta_info - station information |
271 | * | 303 | * |
272 | * These attribute types are used with %NL80211_ATTR_STA_STATS | 304 | * These attribute types are used with %NL80211_ATTR_STA_INFO |
273 | * when getting information about a station. | 305 | * when getting information about a station. |
274 | * | 306 | * |
275 | * @__NL80211_STA_STAT_INVALID: attribute number 0 is reserved | 307 | * @__NL80211_STA_INFO_INVALID: attribute number 0 is reserved |
276 | * @NL80211_STA_STAT_INACTIVE_TIME: time since last activity (u32, msecs) | 308 | * @NL80211_STA_INFO_INACTIVE_TIME: time since last activity (u32, msecs) |
277 | * @NL80211_STA_STAT_RX_BYTES: total received bytes (u32, from this station) | 309 | * @NL80211_STA_INFO_RX_BYTES: total received bytes (u32, from this station) |
278 | * @NL80211_STA_STAT_TX_BYTES: total transmitted bytes (u32, to this station) | 310 | * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station) |
279 | * @__NL80211_STA_STAT_AFTER_LAST: internal | 311 | * @__NL80211_STA_INFO_AFTER_LAST: internal |
280 | * @NL80211_STA_STAT_MAX: highest possible station stats attribute | 312 | * @NL80211_STA_INFO_MAX: highest possible station info attribute |
313 | */ | ||
314 | enum nl80211_sta_info { | ||
315 | __NL80211_STA_INFO_INVALID, | ||
316 | NL80211_STA_INFO_INACTIVE_TIME, | ||
317 | NL80211_STA_INFO_RX_BYTES, | ||
318 | NL80211_STA_INFO_TX_BYTES, | ||
319 | NL80211_STA_INFO_LLID, | ||
320 | NL80211_STA_INFO_PLID, | ||
321 | NL80211_STA_INFO_PLINK_STATE, | ||
322 | |||
323 | /* keep last */ | ||
324 | __NL80211_STA_INFO_AFTER_LAST, | ||
325 | NL80211_STA_INFO_MAX = __NL80211_STA_INFO_AFTER_LAST - 1 | ||
326 | }; | ||
327 | |||
328 | /** | ||
329 | * enum nl80211_mpath_flags - nl80211 mesh path flags | ||
330 | * | ||
331 | * @NL80211_MPATH_FLAG_ACTIVE: the mesh path is active | ||
332 | * @NL80211_MPATH_FLAG_RESOLVING: the mesh path discovery process is running | ||
333 | * @NL80211_MPATH_FLAG_DSN_VALID: the mesh path contains a valid DSN | ||
334 | * @NL80211_MPATH_FLAG_FIXED: the mesh path has been manually set | ||
335 | * @NL80211_MPATH_FLAG_RESOLVED: the mesh path discovery process succeeded | ||
336 | */ | ||
337 | enum nl80211_mpath_flags { | ||
338 | NL80211_MPATH_FLAG_ACTIVE = 1<<0, | ||
339 | NL80211_MPATH_FLAG_RESOLVING = 1<<1, | ||
340 | NL80211_MPATH_FLAG_DSN_VALID = 1<<2, | ||
341 | NL80211_MPATH_FLAG_FIXED = 1<<3, | ||
342 | NL80211_MPATH_FLAG_RESOLVED = 1<<4, | ||
343 | }; | ||
344 | |||
345 | /** | ||
346 | * enum nl80211_mpath_info - mesh path information | ||
347 | * | ||
348 | * These attribute types are used with %NL80211_ATTR_MPATH_INFO when getting | ||
349 | * information about a mesh path. | ||
350 | * | ||
351 | * @__NL80211_MPATH_INFO_INVALID: attribute number 0 is reserved | ||
352 | * @NL80211_ATTR_MPATH_FRAME_QLEN: number of queued frames for this destination | ||
353 | * @NL80211_ATTR_MPATH_DSN: destination sequence number | ||
354 | * @NL80211_ATTR_MPATH_METRIC: metric (cost) of this mesh path | ||
355 | * @NL80211_ATTR_MPATH_EXPTIME: expiration time for the path, in msec from now | ||
356 | * @NL80211_ATTR_MPATH_FLAGS: mesh path flags, enumerated in | ||
357 | * &enum nl80211_mpath_flags; | ||
358 | * @NL80211_ATTR_MPATH_DISCOVERY_TIMEOUT: total path discovery timeout, in msec | ||
359 | * @NL80211_ATTR_MPATH_DISCOVERY_RETRIES: mesh path discovery retries | ||
281 | */ | 360 | */ |
282 | enum nl80211_sta_stats { | 361 | enum nl80211_mpath_info { |
283 | __NL80211_STA_STAT_INVALID, | 362 | __NL80211_MPATH_INFO_INVALID, |
284 | NL80211_STA_STAT_INACTIVE_TIME, | 363 | NL80211_MPATH_INFO_FRAME_QLEN, |
285 | NL80211_STA_STAT_RX_BYTES, | 364 | NL80211_MPATH_INFO_DSN, |
286 | NL80211_STA_STAT_TX_BYTES, | 365 | NL80211_MPATH_INFO_METRIC, |
366 | NL80211_MPATH_INFO_EXPTIME, | ||
367 | NL80211_MPATH_INFO_FLAGS, | ||
368 | NL80211_MPATH_INFO_DISCOVERY_TIMEOUT, | ||
369 | NL80211_MPATH_INFO_DISCOVERY_RETRIES, | ||
287 | 370 | ||
288 | /* keep last */ | 371 | /* keep last */ |
289 | __NL80211_STA_STAT_AFTER_LAST, | 372 | __NL80211_MPATH_INFO_AFTER_LAST, |
290 | NL80211_STA_STAT_MAX = __NL80211_STA_STAT_AFTER_LAST - 1 | 373 | NL80211_MPATH_INFO_MAX = __NL80211_MPATH_INFO_AFTER_LAST - 1 |
291 | }; | 374 | }; |
292 | 375 | ||
293 | /** | 376 | /** |
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index ab4caf63954f..e00750836ba5 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -12,6 +12,16 @@ | |||
12 | * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net> | 12 | * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net> |
13 | */ | 13 | */ |
14 | 14 | ||
15 | /** | ||
16 | * struct vif_params - describes virtual interface parameters | ||
17 | * @mesh_id: mesh ID to use | ||
18 | * @mesh_id_len: length of the mesh ID | ||
19 | */ | ||
20 | struct vif_params { | ||
21 | u8 *mesh_id; | ||
22 | int mesh_id_len; | ||
23 | }; | ||
24 | |||
15 | /* Radiotap header iteration | 25 | /* Radiotap header iteration |
16 | * implemented in net/wireless/radiotap.c | 26 | * implemented in net/wireless/radiotap.c |
17 | * docs in Documentation/networking/radiotap-headers.txt | 27 | * docs in Documentation/networking/radiotap-headers.txt |
@@ -109,6 +119,19 @@ enum station_flags { | |||
109 | }; | 119 | }; |
110 | 120 | ||
111 | /** | 121 | /** |
122 | * enum plink_action - actions to perform in mesh peers | ||
123 | * | ||
124 | * @PLINK_ACTION_INVALID: action 0 is reserved | ||
125 | * @PLINK_ACTION_OPEN: start mesh peer link establishment | ||
126 | * @PLINK_ACTION_BLOCL: block traffic from this mesh peer | ||
127 | */ | ||
128 | enum plink_actions { | ||
129 | PLINK_ACTION_INVALID, | ||
130 | PLINK_ACTION_OPEN, | ||
131 | PLINK_ACTION_BLOCK, | ||
132 | }; | ||
133 | |||
134 | /** | ||
112 | * struct station_parameters - station parameters | 135 | * struct station_parameters - station parameters |
113 | * | 136 | * |
114 | * Used to change and create a new station. | 137 | * Used to change and create a new station. |
@@ -128,39 +151,52 @@ struct station_parameters { | |||
128 | int listen_interval; | 151 | int listen_interval; |
129 | u16 aid; | 152 | u16 aid; |
130 | u8 supported_rates_len; | 153 | u8 supported_rates_len; |
154 | u8 plink_action; | ||
131 | }; | 155 | }; |
132 | 156 | ||
133 | /** | 157 | /** |
134 | * enum station_stats_flags - station statistics flags | 158 | * enum station_info_flags - station information flags |
135 | * | 159 | * |
136 | * Used by the driver to indicate which info in &struct station_stats | 160 | * Used by the driver to indicate which info in &struct station_info |
137 | * it has filled in during get_station(). | 161 | * it has filled in during get_station() or dump_station(). |
138 | * | 162 | * |
139 | * @STATION_STAT_INACTIVE_TIME: @inactive_time filled | 163 | * @STATION_INFO_INACTIVE_TIME: @inactive_time filled |
140 | * @STATION_STAT_RX_BYTES: @rx_bytes filled | 164 | * @STATION_INFO_RX_BYTES: @rx_bytes filled |
141 | * @STATION_STAT_TX_BYTES: @tx_bytes filled | 165 | * @STATION_INFO_TX_BYTES: @tx_bytes filled |
166 | * @STATION_INFO_LLID: @llid filled | ||
167 | * @STATION_INFO_PLID: @plid filled | ||
168 | * @STATION_INFO_PLINK_STATE: @plink_state filled | ||
142 | */ | 169 | */ |
143 | enum station_stats_flags { | 170 | enum station_info_flags { |
144 | STATION_STAT_INACTIVE_TIME = 1<<0, | 171 | STATION_INFO_INACTIVE_TIME = 1<<0, |
145 | STATION_STAT_RX_BYTES = 1<<1, | 172 | STATION_INFO_RX_BYTES = 1<<1, |
146 | STATION_STAT_TX_BYTES = 1<<2, | 173 | STATION_INFO_TX_BYTES = 1<<2, |
174 | STATION_INFO_LLID = 1<<3, | ||
175 | STATION_INFO_PLID = 1<<4, | ||
176 | STATION_INFO_PLINK_STATE = 1<<5, | ||
147 | }; | 177 | }; |
148 | 178 | ||
149 | /** | 179 | /** |
150 | * struct station_stats - station statistics | 180 | * struct station_info - station information |
151 | * | 181 | * |
152 | * Station information filled by driver for get_station(). | 182 | * Station information filled by driver for get_station() and dump_station. |
153 | * | 183 | * |
154 | * @filled: bitflag of flags from &enum station_stats_flags | 184 | * @filled: bitflag of flags from &enum station_info_flags |
155 | * @inactive_time: time since last station activity (tx/rx) in milliseconds | 185 | * @inactive_time: time since last station activity (tx/rx) in milliseconds |
156 | * @rx_bytes: bytes received from this station | 186 | * @rx_bytes: bytes received from this station |
157 | * @tx_bytes: bytes transmitted to this station | 187 | * @tx_bytes: bytes transmitted to this station |
188 | * @llid: mesh local link id | ||
189 | * @plid: mesh peer link id | ||
190 | * @plink_state: mesh peer link state | ||
158 | */ | 191 | */ |
159 | struct station_stats { | 192 | struct station_info { |
160 | u32 filled; | 193 | u32 filled; |
161 | u32 inactive_time; | 194 | u32 inactive_time; |
162 | u32 rx_bytes; | 195 | u32 rx_bytes; |
163 | u32 tx_bytes; | 196 | u32 tx_bytes; |
197 | u16 llid; | ||
198 | u16 plid; | ||
199 | u8 plink_state; | ||
164 | }; | 200 | }; |
165 | 201 | ||
166 | /** | 202 | /** |
@@ -183,6 +219,56 @@ enum monitor_flags { | |||
183 | MONITOR_FLAG_COOK_FRAMES = 1<<NL80211_MNTR_FLAG_COOK_FRAMES, | 219 | MONITOR_FLAG_COOK_FRAMES = 1<<NL80211_MNTR_FLAG_COOK_FRAMES, |
184 | }; | 220 | }; |
185 | 221 | ||
222 | /** | ||
223 | * enum mpath_info_flags - mesh path information flags | ||
224 | * | ||
225 | * Used by the driver to indicate which info in &struct mpath_info it has filled | ||
226 | * in during get_station() or dump_station(). | ||
227 | * | ||
228 | * MPATH_INFO_FRAME_QLEN: @frame_qlen filled | ||
229 | * MPATH_INFO_DSN: @dsn filled | ||
230 | * MPATH_INFO_METRIC: @metric filled | ||
231 | * MPATH_INFO_EXPTIME: @exptime filled | ||
232 | * MPATH_INFO_DISCOVERY_TIMEOUT: @discovery_timeout filled | ||
233 | * MPATH_INFO_DISCOVERY_RETRIES: @discovery_retries filled | ||
234 | * MPATH_INFO_FLAGS: @flags filled | ||
235 | */ | ||
236 | enum mpath_info_flags { | ||
237 | MPATH_INFO_FRAME_QLEN = BIT(0), | ||
238 | MPATH_INFO_DSN = BIT(1), | ||
239 | MPATH_INFO_METRIC = BIT(2), | ||
240 | MPATH_INFO_EXPTIME = BIT(3), | ||
241 | MPATH_INFO_DISCOVERY_TIMEOUT = BIT(4), | ||
242 | MPATH_INFO_DISCOVERY_RETRIES = BIT(5), | ||
243 | MPATH_INFO_FLAGS = BIT(6), | ||
244 | }; | ||
245 | |||
246 | /** | ||
247 | * struct mpath_info - mesh path information | ||
248 | * | ||
249 | * Mesh path information filled by driver for get_mpath() and dump_mpath(). | ||
250 | * | ||
251 | * @filled: bitfield of flags from &enum mpath_info_flags | ||
252 | * @frame_qlen: number of queued frames for this destination | ||
253 | * @dsn: destination sequence number | ||
254 | * @metric: metric (cost) of this mesh path | ||
255 | * @exptime: expiration time for the mesh path from now, in msecs | ||
256 | * @flags: mesh path flags | ||
257 | * @discovery_timeout: total mesh path discovery timeout, in msecs | ||
258 | * @discovery_retries: mesh path discovery retries | ||
259 | */ | ||
260 | struct mpath_info { | ||
261 | u32 filled; | ||
262 | u32 frame_qlen; | ||
263 | u32 dsn; | ||
264 | u32 metric; | ||
265 | u32 exptime; | ||
266 | u32 discovery_timeout; | ||
267 | u8 discovery_retries; | ||
268 | u8 flags; | ||
269 | }; | ||
270 | |||
271 | |||
186 | /* from net/wireless.h */ | 272 | /* from net/wireless.h */ |
187 | struct wiphy; | 273 | struct wiphy; |
188 | 274 | ||
@@ -230,13 +316,17 @@ struct wiphy; | |||
230 | * @del_station: Remove a station; @mac may be NULL to remove all stations. | 316 | * @del_station: Remove a station; @mac may be NULL to remove all stations. |
231 | * | 317 | * |
232 | * @change_station: Modify a given station. | 318 | * @change_station: Modify a given station. |
319 | * | ||
320 | * @set_mesh_cfg: set mesh parameters (by now, just mesh id) | ||
233 | */ | 321 | */ |
234 | struct cfg80211_ops { | 322 | struct cfg80211_ops { |
235 | int (*add_virtual_intf)(struct wiphy *wiphy, char *name, | 323 | int (*add_virtual_intf)(struct wiphy *wiphy, char *name, |
236 | enum nl80211_iftype type, u32 *flags); | 324 | enum nl80211_iftype type, u32 *flags, |
325 | struct vif_params *params); | ||
237 | int (*del_virtual_intf)(struct wiphy *wiphy, int ifindex); | 326 | int (*del_virtual_intf)(struct wiphy *wiphy, int ifindex); |
238 | int (*change_virtual_intf)(struct wiphy *wiphy, int ifindex, | 327 | int (*change_virtual_intf)(struct wiphy *wiphy, int ifindex, |
239 | enum nl80211_iftype type, u32 *flags); | 328 | enum nl80211_iftype type, u32 *flags, |
329 | struct vif_params *params); | ||
240 | 330 | ||
241 | int (*add_key)(struct wiphy *wiphy, struct net_device *netdev, | 331 | int (*add_key)(struct wiphy *wiphy, struct net_device *netdev, |
242 | u8 key_index, u8 *mac_addr, | 332 | u8 key_index, u8 *mac_addr, |
@@ -264,7 +354,22 @@ struct cfg80211_ops { | |||
264 | int (*change_station)(struct wiphy *wiphy, struct net_device *dev, | 354 | int (*change_station)(struct wiphy *wiphy, struct net_device *dev, |
265 | u8 *mac, struct station_parameters *params); | 355 | u8 *mac, struct station_parameters *params); |
266 | int (*get_station)(struct wiphy *wiphy, struct net_device *dev, | 356 | int (*get_station)(struct wiphy *wiphy, struct net_device *dev, |
267 | u8 *mac, struct station_stats *stats); | 357 | u8 *mac, struct station_info *sinfo); |
358 | int (*dump_station)(struct wiphy *wiphy, struct net_device *dev, | ||
359 | int idx, u8 *mac, struct station_info *sinfo); | ||
360 | |||
361 | int (*add_mpath)(struct wiphy *wiphy, struct net_device *dev, | ||
362 | u8 *dst, u8 *next_hop); | ||
363 | int (*del_mpath)(struct wiphy *wiphy, struct net_device *dev, | ||
364 | u8 *dst); | ||
365 | int (*change_mpath)(struct wiphy *wiphy, struct net_device *dev, | ||
366 | u8 *dst, u8 *next_hop); | ||
367 | int (*get_mpath)(struct wiphy *wiphy, struct net_device *dev, | ||
368 | u8 *dst, u8 *next_hop, | ||
369 | struct mpath_info *pinfo); | ||
370 | int (*dump_mpath)(struct wiphy *wiphy, struct net_device *dev, | ||
371 | int idx, u8 *dst, u8 *next_hop, | ||
372 | struct mpath_info *pinfo); | ||
268 | }; | 373 | }; |
269 | 374 | ||
270 | #endif /* __NET_CFG80211_H */ | 375 | #endif /* __NET_CFG80211_H */ |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index e7535ffc8e1c..006da6a2e71b 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -34,7 +34,8 @@ nl80211_type_to_mac80211_type(enum nl80211_iftype type) | |||
34 | } | 34 | } |
35 | 35 | ||
36 | static int ieee80211_add_iface(struct wiphy *wiphy, char *name, | 36 | static int ieee80211_add_iface(struct wiphy *wiphy, char *name, |
37 | enum nl80211_iftype type, u32 *flags) | 37 | enum nl80211_iftype type, u32 *flags, |
38 | struct vif_params *params) | ||
38 | { | 39 | { |
39 | struct ieee80211_local *local = wiphy_priv(wiphy); | 40 | struct ieee80211_local *local = wiphy_priv(wiphy); |
40 | enum ieee80211_if_types itype; | 41 | enum ieee80211_if_types itype; |
@@ -78,7 +79,8 @@ static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex) | |||
78 | } | 79 | } |
79 | 80 | ||
80 | static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex, | 81 | static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex, |
81 | enum nl80211_iftype type, u32 *flags) | 82 | enum nl80211_iftype type, u32 *flags, |
83 | struct vif_params *params) | ||
82 | { | 84 | { |
83 | struct ieee80211_local *local = wiphy_priv(wiphy); | 85 | struct ieee80211_local *local = wiphy_priv(wiphy); |
84 | struct net_device *dev; | 86 | struct net_device *dev; |
@@ -296,7 +298,7 @@ static int ieee80211_config_default_key(struct wiphy *wiphy, | |||
296 | } | 298 | } |
297 | 299 | ||
298 | static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, | 300 | static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, |
299 | u8 *mac, struct station_stats *stats) | 301 | u8 *mac, struct station_info *sinfo) |
300 | { | 302 | { |
301 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 303 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
302 | struct sta_info *sta; | 304 | struct sta_info *sta; |
@@ -307,13 +309,13 @@ static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, | |||
307 | 309 | ||
308 | /* XXX: verify sta->dev == dev */ | 310 | /* XXX: verify sta->dev == dev */ |
309 | 311 | ||
310 | stats->filled = STATION_STAT_INACTIVE_TIME | | 312 | sinfo->filled = STATION_INFO_INACTIVE_TIME | |
311 | STATION_STAT_RX_BYTES | | 313 | STATION_INFO_RX_BYTES | |
312 | STATION_STAT_TX_BYTES; | 314 | STATION_INFO_TX_BYTES; |
313 | 315 | ||
314 | stats->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); | 316 | sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); |
315 | stats->rx_bytes = sta->rx_bytes; | 317 | sinfo->rx_bytes = sta->rx_bytes; |
316 | stats->tx_bytes = sta->tx_bytes; | 318 | sinfo->tx_bytes = sta->tx_bytes; |
317 | 319 | ||
318 | sta_info_put(sta); | 320 | sta_info_put(sta); |
319 | 321 | ||
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 5b3474798b8d..64a7460af734 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -81,8 +81,12 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { | |||
81 | [NL80211_ATTR_STA_LISTEN_INTERVAL] = { .type = NLA_U16 }, | 81 | [NL80211_ATTR_STA_LISTEN_INTERVAL] = { .type = NLA_U16 }, |
82 | [NL80211_ATTR_STA_SUPPORTED_RATES] = { .type = NLA_BINARY, | 82 | [NL80211_ATTR_STA_SUPPORTED_RATES] = { .type = NLA_BINARY, |
83 | .len = NL80211_MAX_SUPP_RATES }, | 83 | .len = NL80211_MAX_SUPP_RATES }, |
84 | [NL80211_ATTR_STA_PLINK_ACTION] = { .type = NLA_U8 }, | ||
84 | [NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 }, | 85 | [NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 }, |
85 | [NL80211_ATTR_MNTR_FLAGS] = { .type = NLA_NESTED }, | 86 | [NL80211_ATTR_MNTR_FLAGS] = { .type = NLA_NESTED }, |
87 | [NL80211_ATTR_MESH_ID] = { .type = NLA_BINARY, | ||
88 | .len = IEEE80211_MAX_MESH_ID_LEN }, | ||
89 | [NL80211_ATTR_MPATH_NEXT_HOP] = { .type = NLA_U32 }, | ||
86 | }; | 90 | }; |
87 | 91 | ||
88 | /* message building helper */ | 92 | /* message building helper */ |
@@ -369,11 +373,14 @@ static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags) | |||
369 | static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | 373 | static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) |
370 | { | 374 | { |
371 | struct cfg80211_registered_device *drv; | 375 | struct cfg80211_registered_device *drv; |
376 | struct vif_params params; | ||
372 | int err, ifindex; | 377 | int err, ifindex; |
373 | enum nl80211_iftype type; | 378 | enum nl80211_iftype type; |
374 | struct net_device *dev; | 379 | struct net_device *dev; |
375 | u32 flags; | 380 | u32 flags; |
376 | 381 | ||
382 | memset(¶ms, 0, sizeof(params)); | ||
383 | |||
377 | if (info->attrs[NL80211_ATTR_IFTYPE]) { | 384 | if (info->attrs[NL80211_ATTR_IFTYPE]) { |
378 | type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); | 385 | type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); |
379 | if (type > NL80211_IFTYPE_MAX) | 386 | if (type > NL80211_IFTYPE_MAX) |
@@ -392,12 +399,18 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | |||
392 | goto unlock; | 399 | goto unlock; |
393 | } | 400 | } |
394 | 401 | ||
402 | if (type == NL80211_IFTYPE_MESH_POINT && | ||
403 | info->attrs[NL80211_ATTR_MESH_ID]) { | ||
404 | params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); | ||
405 | params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); | ||
406 | } | ||
407 | |||
395 | rtnl_lock(); | 408 | rtnl_lock(); |
396 | err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? | 409 | err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? |
397 | info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, | 410 | info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, |
398 | &flags); | 411 | &flags); |
399 | err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, | 412 | err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, |
400 | type, err ? NULL : &flags); | 413 | type, err ? NULL : &flags, ¶ms); |
401 | rtnl_unlock(); | 414 | rtnl_unlock(); |
402 | 415 | ||
403 | unlock: | 416 | unlock: |
@@ -408,10 +421,13 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | |||
408 | static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | 421 | static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) |
409 | { | 422 | { |
410 | struct cfg80211_registered_device *drv; | 423 | struct cfg80211_registered_device *drv; |
424 | struct vif_params params; | ||
411 | int err; | 425 | int err; |
412 | enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; | 426 | enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; |
413 | u32 flags; | 427 | u32 flags; |
414 | 428 | ||
429 | memset(¶ms, 0, sizeof(params)); | ||
430 | |||
415 | if (!info->attrs[NL80211_ATTR_IFNAME]) | 431 | if (!info->attrs[NL80211_ATTR_IFNAME]) |
416 | return -EINVAL; | 432 | return -EINVAL; |
417 | 433 | ||
@@ -430,15 +446,22 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
430 | goto unlock; | 446 | goto unlock; |
431 | } | 447 | } |
432 | 448 | ||
449 | if (type == NL80211_IFTYPE_MESH_POINT && | ||
450 | info->attrs[NL80211_ATTR_MESH_ID]) { | ||
451 | params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); | ||
452 | params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); | ||
453 | } | ||
454 | |||
433 | rtnl_lock(); | 455 | rtnl_lock(); |
434 | err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? | 456 | err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? |
435 | info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, | 457 | info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, |
436 | &flags); | 458 | &flags); |
437 | err = drv->ops->add_virtual_intf(&drv->wiphy, | 459 | err = drv->ops->add_virtual_intf(&drv->wiphy, |
438 | nla_data(info->attrs[NL80211_ATTR_IFNAME]), | 460 | nla_data(info->attrs[NL80211_ATTR_IFNAME]), |
439 | type, err ? NULL : &flags); | 461 | type, err ? NULL : &flags, ¶ms); |
440 | rtnl_unlock(); | 462 | rtnl_unlock(); |
441 | 463 | ||
464 | |||
442 | unlock: | 465 | unlock: |
443 | cfg80211_put_dev(drv); | 466 | cfg80211_put_dev(drv); |
444 | return err; | 467 | return err; |
@@ -866,10 +889,10 @@ static int parse_station_flags(struct nlattr *nla, u32 *staflags) | |||
866 | 889 | ||
867 | static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, | 890 | static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, |
868 | int flags, struct net_device *dev, | 891 | int flags, struct net_device *dev, |
869 | u8 *mac_addr, struct station_stats *stats) | 892 | u8 *mac_addr, struct station_info *sinfo) |
870 | { | 893 | { |
871 | void *hdr; | 894 | void *hdr; |
872 | struct nlattr *statsattr; | 895 | struct nlattr *sinfoattr; |
873 | 896 | ||
874 | hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION); | 897 | hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION); |
875 | if (!hdr) | 898 | if (!hdr) |
@@ -878,20 +901,29 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, | |||
878 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); | 901 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); |
879 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); | 902 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); |
880 | 903 | ||
881 | statsattr = nla_nest_start(msg, NL80211_ATTR_STA_STATS); | 904 | sinfoattr = nla_nest_start(msg, NL80211_ATTR_STA_INFO); |
882 | if (!statsattr) | 905 | if (!sinfoattr) |
883 | goto nla_put_failure; | 906 | goto nla_put_failure; |
884 | if (stats->filled & STATION_STAT_INACTIVE_TIME) | 907 | if (sinfo->filled & STATION_INFO_INACTIVE_TIME) |
885 | NLA_PUT_U32(msg, NL80211_STA_STAT_INACTIVE_TIME, | 908 | NLA_PUT_U32(msg, NL80211_STA_INFO_INACTIVE_TIME, |
886 | stats->inactive_time); | 909 | sinfo->inactive_time); |
887 | if (stats->filled & STATION_STAT_RX_BYTES) | 910 | if (sinfo->filled & STATION_INFO_RX_BYTES) |
888 | NLA_PUT_U32(msg, NL80211_STA_STAT_RX_BYTES, | 911 | NLA_PUT_U32(msg, NL80211_STA_INFO_RX_BYTES, |
889 | stats->rx_bytes); | 912 | sinfo->rx_bytes); |
890 | if (stats->filled & STATION_STAT_TX_BYTES) | 913 | if (sinfo->filled & STATION_INFO_TX_BYTES) |
891 | NLA_PUT_U32(msg, NL80211_STA_STAT_TX_BYTES, | 914 | NLA_PUT_U32(msg, NL80211_STA_INFO_TX_BYTES, |
892 | stats->tx_bytes); | 915 | sinfo->tx_bytes); |
893 | 916 | if (sinfo->filled & STATION_INFO_LLID) | |
894 | nla_nest_end(msg, statsattr); | 917 | NLA_PUT_U16(msg, NL80211_STA_INFO_LLID, |
918 | sinfo->llid); | ||
919 | if (sinfo->filled & STATION_INFO_PLID) | ||
920 | NLA_PUT_U16(msg, NL80211_STA_INFO_PLID, | ||
921 | sinfo->plid); | ||
922 | if (sinfo->filled & STATION_INFO_PLINK_STATE) | ||
923 | NLA_PUT_U8(msg, NL80211_STA_INFO_PLINK_STATE, | ||
924 | sinfo->plink_state); | ||
925 | |||
926 | nla_nest_end(msg, sinfoattr); | ||
895 | 927 | ||
896 | return genlmsg_end(msg, hdr); | 928 | return genlmsg_end(msg, hdr); |
897 | 929 | ||
@@ -899,17 +931,80 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, | |||
899 | return genlmsg_cancel(msg, hdr); | 931 | return genlmsg_cancel(msg, hdr); |
900 | } | 932 | } |
901 | 933 | ||
934 | static int nl80211_dump_station(struct sk_buff *skb, | ||
935 | struct netlink_callback *cb) | ||
936 | { | ||
937 | int wp_idx = 0; | ||
938 | int if_idx = 0; | ||
939 | int sta_idx = cb->args[2]; | ||
940 | int wp_start = cb->args[0]; | ||
941 | int if_start = cb->args[1]; | ||
942 | struct station_info sinfo; | ||
943 | struct cfg80211_registered_device *dev; | ||
944 | struct wireless_dev *wdev; | ||
945 | u8 mac_addr[ETH_ALEN]; | ||
946 | int err; | ||
947 | int exit = 0; | ||
948 | |||
949 | /* TODO: filter by device */ | ||
950 | mutex_lock(&cfg80211_drv_mutex); | ||
951 | list_for_each_entry(dev, &cfg80211_drv_list, list) { | ||
952 | if (exit) | ||
953 | break; | ||
954 | if (++wp_idx < wp_start) | ||
955 | continue; | ||
956 | if_idx = 0; | ||
957 | |||
958 | mutex_lock(&dev->devlist_mtx); | ||
959 | list_for_each_entry(wdev, &dev->netdev_list, list) { | ||
960 | if (exit) | ||
961 | break; | ||
962 | if (++if_idx < if_start) | ||
963 | continue; | ||
964 | if (!dev->ops->dump_station) | ||
965 | continue; | ||
966 | |||
967 | for (;; ++sta_idx) { | ||
968 | rtnl_lock(); | ||
969 | err = dev->ops->dump_station(&dev->wiphy, | ||
970 | wdev->netdev, sta_idx, mac_addr, | ||
971 | &sinfo); | ||
972 | rtnl_unlock(); | ||
973 | if (err) { | ||
974 | sta_idx = 0; | ||
975 | break; | ||
976 | } | ||
977 | if (nl80211_send_station(skb, | ||
978 | NETLINK_CB(cb->skb).pid, | ||
979 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | ||
980 | wdev->netdev, mac_addr, | ||
981 | &sinfo) < 0) { | ||
982 | exit = 1; | ||
983 | break; | ||
984 | } | ||
985 | } | ||
986 | } | ||
987 | mutex_unlock(&dev->devlist_mtx); | ||
988 | } | ||
989 | mutex_unlock(&cfg80211_drv_mutex); | ||
990 | |||
991 | cb->args[0] = wp_idx; | ||
992 | cb->args[1] = if_idx; | ||
993 | cb->args[2] = sta_idx; | ||
994 | |||
995 | return skb->len; | ||
996 | } | ||
902 | 997 | ||
903 | static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) | 998 | static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) |
904 | { | 999 | { |
905 | struct cfg80211_registered_device *drv; | 1000 | struct cfg80211_registered_device *drv; |
906 | int err; | 1001 | int err; |
907 | struct net_device *dev; | 1002 | struct net_device *dev; |
908 | struct station_stats stats; | 1003 | struct station_info sinfo; |
909 | struct sk_buff *msg; | 1004 | struct sk_buff *msg; |
910 | u8 *mac_addr = NULL; | 1005 | u8 *mac_addr = NULL; |
911 | 1006 | ||
912 | memset(&stats, 0, sizeof(stats)); | 1007 | memset(&sinfo, 0, sizeof(sinfo)); |
913 | 1008 | ||
914 | if (!info->attrs[NL80211_ATTR_MAC]) | 1009 | if (!info->attrs[NL80211_ATTR_MAC]) |
915 | return -EINVAL; | 1010 | return -EINVAL; |
@@ -926,15 +1021,18 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) | |||
926 | } | 1021 | } |
927 | 1022 | ||
928 | rtnl_lock(); | 1023 | rtnl_lock(); |
929 | err = drv->ops->get_station(&drv->wiphy, dev, mac_addr, &stats); | 1024 | err = drv->ops->get_station(&drv->wiphy, dev, mac_addr, &sinfo); |
930 | rtnl_unlock(); | 1025 | rtnl_unlock(); |
931 | 1026 | ||
1027 | if (err) | ||
1028 | goto out; | ||
1029 | |||
932 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | 1030 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); |
933 | if (!msg) | 1031 | if (!msg) |
934 | goto out; | 1032 | goto out; |
935 | 1033 | ||
936 | if (nl80211_send_station(msg, info->snd_pid, info->snd_seq, 0, | 1034 | if (nl80211_send_station(msg, info->snd_pid, info->snd_seq, 0, |
937 | dev, mac_addr, &stats) < 0) | 1035 | dev, mac_addr, &sinfo) < 0) |
938 | goto out_free; | 1036 | goto out_free; |
939 | 1037 | ||
940 | err = genlmsg_unicast(msg, info->snd_pid); | 1038 | err = genlmsg_unicast(msg, info->snd_pid); |
@@ -1005,6 +1103,10 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
1005 | ¶ms.station_flags)) | 1103 | ¶ms.station_flags)) |
1006 | return -EINVAL; | 1104 | return -EINVAL; |
1007 | 1105 | ||
1106 | if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) | ||
1107 | params.plink_action = | ||
1108 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); | ||
1109 | |||
1008 | err = get_drv_dev_by_info_ifindex(info, &drv, &dev); | 1110 | err = get_drv_dev_by_info_ifindex(info, &drv, &dev); |
1009 | if (err) | 1111 | if (err) |
1010 | return err; | 1112 | return err; |
@@ -1119,6 +1221,273 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) | |||
1119 | return err; | 1221 | return err; |
1120 | } | 1222 | } |
1121 | 1223 | ||
1224 | static int nl80211_send_mpath(struct sk_buff *msg, u32 pid, u32 seq, | ||
1225 | int flags, struct net_device *dev, | ||
1226 | u8 *dst, u8 *next_hop, | ||
1227 | struct mpath_info *pinfo) | ||
1228 | { | ||
1229 | void *hdr; | ||
1230 | struct nlattr *pinfoattr; | ||
1231 | |||
1232 | hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION); | ||
1233 | if (!hdr) | ||
1234 | return -1; | ||
1235 | |||
1236 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); | ||
1237 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst); | ||
1238 | NLA_PUT(msg, NL80211_ATTR_MPATH_NEXT_HOP, ETH_ALEN, next_hop); | ||
1239 | |||
1240 | pinfoattr = nla_nest_start(msg, NL80211_ATTR_MPATH_INFO); | ||
1241 | if (!pinfoattr) | ||
1242 | goto nla_put_failure; | ||
1243 | if (pinfo->filled & MPATH_INFO_FRAME_QLEN) | ||
1244 | NLA_PUT_U32(msg, NL80211_MPATH_INFO_FRAME_QLEN, | ||
1245 | pinfo->frame_qlen); | ||
1246 | if (pinfo->filled & MPATH_INFO_DSN) | ||
1247 | NLA_PUT_U32(msg, NL80211_MPATH_INFO_DSN, | ||
1248 | pinfo->dsn); | ||
1249 | if (pinfo->filled & MPATH_INFO_METRIC) | ||
1250 | NLA_PUT_U32(msg, NL80211_MPATH_INFO_METRIC, | ||
1251 | pinfo->metric); | ||
1252 | if (pinfo->filled & MPATH_INFO_EXPTIME) | ||
1253 | NLA_PUT_U32(msg, NL80211_MPATH_INFO_EXPTIME, | ||
1254 | pinfo->exptime); | ||
1255 | if (pinfo->filled & MPATH_INFO_FLAGS) | ||
1256 | NLA_PUT_U8(msg, NL80211_MPATH_INFO_FLAGS, | ||
1257 | pinfo->flags); | ||
1258 | if (pinfo->filled & MPATH_INFO_DISCOVERY_TIMEOUT) | ||
1259 | NLA_PUT_U32(msg, NL80211_MPATH_INFO_DISCOVERY_TIMEOUT, | ||
1260 | pinfo->discovery_timeout); | ||
1261 | if (pinfo->filled & MPATH_INFO_DISCOVERY_RETRIES) | ||
1262 | NLA_PUT_U8(msg, NL80211_MPATH_INFO_DISCOVERY_RETRIES, | ||
1263 | pinfo->discovery_retries); | ||
1264 | |||
1265 | nla_nest_end(msg, pinfoattr); | ||
1266 | |||
1267 | return genlmsg_end(msg, hdr); | ||
1268 | |||
1269 | nla_put_failure: | ||
1270 | return genlmsg_cancel(msg, hdr); | ||
1271 | } | ||
1272 | |||
1273 | static int nl80211_dump_mpath(struct sk_buff *skb, | ||
1274 | struct netlink_callback *cb) | ||
1275 | { | ||
1276 | int wp_idx = 0; | ||
1277 | int if_idx = 0; | ||
1278 | int sta_idx = cb->args[2]; | ||
1279 | int wp_start = cb->args[0]; | ||
1280 | int if_start = cb->args[1]; | ||
1281 | struct mpath_info pinfo; | ||
1282 | struct cfg80211_registered_device *dev; | ||
1283 | struct wireless_dev *wdev; | ||
1284 | u8 dst[ETH_ALEN]; | ||
1285 | u8 next_hop[ETH_ALEN]; | ||
1286 | int err; | ||
1287 | int exit = 0; | ||
1288 | |||
1289 | /* TODO: filter by device */ | ||
1290 | mutex_lock(&cfg80211_drv_mutex); | ||
1291 | list_for_each_entry(dev, &cfg80211_drv_list, list) { | ||
1292 | if (exit) | ||
1293 | break; | ||
1294 | if (++wp_idx < wp_start) | ||
1295 | continue; | ||
1296 | if_idx = 0; | ||
1297 | |||
1298 | mutex_lock(&dev->devlist_mtx); | ||
1299 | list_for_each_entry(wdev, &dev->netdev_list, list) { | ||
1300 | if (exit) | ||
1301 | break; | ||
1302 | if (++if_idx < if_start) | ||
1303 | continue; | ||
1304 | if (!dev->ops->dump_mpath) | ||
1305 | continue; | ||
1306 | |||
1307 | for (;; ++sta_idx) { | ||
1308 | rtnl_lock(); | ||
1309 | err = dev->ops->dump_mpath(&dev->wiphy, | ||
1310 | wdev->netdev, sta_idx, dst, | ||
1311 | next_hop, &pinfo); | ||
1312 | rtnl_unlock(); | ||
1313 | if (err) { | ||
1314 | sta_idx = 0; | ||
1315 | break; | ||
1316 | } | ||
1317 | if (nl80211_send_mpath(skb, | ||
1318 | NETLINK_CB(cb->skb).pid, | ||
1319 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | ||
1320 | wdev->netdev, dst, next_hop, | ||
1321 | &pinfo) < 0) { | ||
1322 | exit = 1; | ||
1323 | break; | ||
1324 | } | ||
1325 | } | ||
1326 | } | ||
1327 | mutex_unlock(&dev->devlist_mtx); | ||
1328 | } | ||
1329 | mutex_unlock(&cfg80211_drv_mutex); | ||
1330 | |||
1331 | cb->args[0] = wp_idx; | ||
1332 | cb->args[1] = if_idx; | ||
1333 | cb->args[2] = sta_idx; | ||
1334 | |||
1335 | return skb->len; | ||
1336 | } | ||
1337 | |||
1338 | static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) | ||
1339 | { | ||
1340 | struct cfg80211_registered_device *drv; | ||
1341 | int err; | ||
1342 | struct net_device *dev; | ||
1343 | struct mpath_info pinfo; | ||
1344 | struct sk_buff *msg; | ||
1345 | u8 *dst = NULL; | ||
1346 | u8 next_hop[ETH_ALEN]; | ||
1347 | |||
1348 | memset(&pinfo, 0, sizeof(pinfo)); | ||
1349 | |||
1350 | if (!info->attrs[NL80211_ATTR_MAC]) | ||
1351 | return -EINVAL; | ||
1352 | |||
1353 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
1354 | |||
1355 | err = get_drv_dev_by_info_ifindex(info, &drv, &dev); | ||
1356 | if (err) | ||
1357 | return err; | ||
1358 | |||
1359 | if (!drv->ops->get_mpath) { | ||
1360 | err = -EOPNOTSUPP; | ||
1361 | goto out; | ||
1362 | } | ||
1363 | |||
1364 | rtnl_lock(); | ||
1365 | err = drv->ops->get_mpath(&drv->wiphy, dev, dst, next_hop, &pinfo); | ||
1366 | rtnl_unlock(); | ||
1367 | |||
1368 | if (err) | ||
1369 | goto out; | ||
1370 | |||
1371 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | ||
1372 | if (!msg) | ||
1373 | goto out; | ||
1374 | |||
1375 | if (nl80211_send_mpath(msg, info->snd_pid, info->snd_seq, 0, | ||
1376 | dev, dst, next_hop, &pinfo) < 0) | ||
1377 | goto out_free; | ||
1378 | |||
1379 | err = genlmsg_unicast(msg, info->snd_pid); | ||
1380 | goto out; | ||
1381 | |||
1382 | out_free: | ||
1383 | nlmsg_free(msg); | ||
1384 | |||
1385 | out: | ||
1386 | cfg80211_put_dev(drv); | ||
1387 | dev_put(dev); | ||
1388 | return err; | ||
1389 | } | ||
1390 | |||
1391 | static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info) | ||
1392 | { | ||
1393 | struct cfg80211_registered_device *drv; | ||
1394 | int err; | ||
1395 | struct net_device *dev; | ||
1396 | u8 *dst = NULL; | ||
1397 | u8 *next_hop = NULL; | ||
1398 | |||
1399 | if (!info->attrs[NL80211_ATTR_MAC]) | ||
1400 | return -EINVAL; | ||
1401 | |||
1402 | if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]) | ||
1403 | return -EINVAL; | ||
1404 | |||
1405 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
1406 | next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); | ||
1407 | |||
1408 | err = get_drv_dev_by_info_ifindex(info, &drv, &dev); | ||
1409 | if (err) | ||
1410 | return err; | ||
1411 | |||
1412 | if (!drv->ops->change_mpath) { | ||
1413 | err = -EOPNOTSUPP; | ||
1414 | goto out; | ||
1415 | } | ||
1416 | |||
1417 | rtnl_lock(); | ||
1418 | err = drv->ops->change_mpath(&drv->wiphy, dev, dst, next_hop); | ||
1419 | rtnl_unlock(); | ||
1420 | |||
1421 | out: | ||
1422 | cfg80211_put_dev(drv); | ||
1423 | dev_put(dev); | ||
1424 | return err; | ||
1425 | } | ||
1426 | static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) | ||
1427 | { | ||
1428 | struct cfg80211_registered_device *drv; | ||
1429 | int err; | ||
1430 | struct net_device *dev; | ||
1431 | u8 *dst = NULL; | ||
1432 | u8 *next_hop = NULL; | ||
1433 | |||
1434 | if (!info->attrs[NL80211_ATTR_MAC]) | ||
1435 | return -EINVAL; | ||
1436 | |||
1437 | if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]) | ||
1438 | return -EINVAL; | ||
1439 | |||
1440 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
1441 | next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); | ||
1442 | |||
1443 | err = get_drv_dev_by_info_ifindex(info, &drv, &dev); | ||
1444 | if (err) | ||
1445 | return err; | ||
1446 | |||
1447 | if (!drv->ops->add_mpath) { | ||
1448 | err = -EOPNOTSUPP; | ||
1449 | goto out; | ||
1450 | } | ||
1451 | |||
1452 | rtnl_lock(); | ||
1453 | err = drv->ops->add_mpath(&drv->wiphy, dev, dst, next_hop); | ||
1454 | rtnl_unlock(); | ||
1455 | |||
1456 | out: | ||
1457 | cfg80211_put_dev(drv); | ||
1458 | dev_put(dev); | ||
1459 | return err; | ||
1460 | } | ||
1461 | |||
1462 | static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info) | ||
1463 | { | ||
1464 | struct cfg80211_registered_device *drv; | ||
1465 | int err; | ||
1466 | struct net_device *dev; | ||
1467 | u8 *dst = NULL; | ||
1468 | |||
1469 | if (info->attrs[NL80211_ATTR_MAC]) | ||
1470 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
1471 | |||
1472 | err = get_drv_dev_by_info_ifindex(info, &drv, &dev); | ||
1473 | if (err) | ||
1474 | return err; | ||
1475 | |||
1476 | if (!drv->ops->del_mpath) { | ||
1477 | err = -EOPNOTSUPP; | ||
1478 | goto out; | ||
1479 | } | ||
1480 | |||
1481 | rtnl_lock(); | ||
1482 | err = drv->ops->del_mpath(&drv->wiphy, dev, dst); | ||
1483 | rtnl_unlock(); | ||
1484 | |||
1485 | out: | ||
1486 | cfg80211_put_dev(drv); | ||
1487 | dev_put(dev); | ||
1488 | return err; | ||
1489 | } | ||
1490 | |||
1122 | static struct genl_ops nl80211_ops[] = { | 1491 | static struct genl_ops nl80211_ops[] = { |
1123 | { | 1492 | { |
1124 | .cmd = NL80211_CMD_GET_WIPHY, | 1493 | .cmd = NL80211_CMD_GET_WIPHY, |
@@ -1203,7 +1572,7 @@ static struct genl_ops nl80211_ops[] = { | |||
1203 | { | 1572 | { |
1204 | .cmd = NL80211_CMD_GET_STATION, | 1573 | .cmd = NL80211_CMD_GET_STATION, |
1205 | .doit = nl80211_get_station, | 1574 | .doit = nl80211_get_station, |
1206 | /* TODO: implement dumpit */ | 1575 | .dumpit = nl80211_dump_station, |
1207 | .policy = nl80211_policy, | 1576 | .policy = nl80211_policy, |
1208 | .flags = GENL_ADMIN_PERM, | 1577 | .flags = GENL_ADMIN_PERM, |
1209 | }, | 1578 | }, |
@@ -1225,6 +1594,31 @@ static struct genl_ops nl80211_ops[] = { | |||
1225 | .policy = nl80211_policy, | 1594 | .policy = nl80211_policy, |
1226 | .flags = GENL_ADMIN_PERM, | 1595 | .flags = GENL_ADMIN_PERM, |
1227 | }, | 1596 | }, |
1597 | { | ||
1598 | .cmd = NL80211_CMD_GET_MPATH, | ||
1599 | .doit = nl80211_get_mpath, | ||
1600 | .dumpit = nl80211_dump_mpath, | ||
1601 | .policy = nl80211_policy, | ||
1602 | .flags = GENL_ADMIN_PERM, | ||
1603 | }, | ||
1604 | { | ||
1605 | .cmd = NL80211_CMD_SET_MPATH, | ||
1606 | .doit = nl80211_set_mpath, | ||
1607 | .policy = nl80211_policy, | ||
1608 | .flags = GENL_ADMIN_PERM, | ||
1609 | }, | ||
1610 | { | ||
1611 | .cmd = NL80211_CMD_NEW_MPATH, | ||
1612 | .doit = nl80211_new_mpath, | ||
1613 | .policy = nl80211_policy, | ||
1614 | .flags = GENL_ADMIN_PERM, | ||
1615 | }, | ||
1616 | { | ||
1617 | .cmd = NL80211_CMD_DEL_MPATH, | ||
1618 | .doit = nl80211_del_mpath, | ||
1619 | .policy = nl80211_policy, | ||
1620 | .flags = GENL_ADMIN_PERM, | ||
1621 | }, | ||
1228 | }; | 1622 | }; |
1229 | 1623 | ||
1230 | /* multicast groups */ | 1624 | /* multicast groups */ |