Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

nl80211/cfg80211: support for mesh, sta dumping

Added support for mesh id and mesh path operation as well as
station structure dumping.

Signed-off-by: Luis Carlos Cobo <luisca@cozybit.com>
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>

authored by

Luis Carlos Cobo and committed by
John W. Linville
2ec600d6 cc0672a1

+649 -65
+101 -18
include/linux/nl80211.h
··· 78 78 * or, if no MAC address given, all stations, on the interface identified 79 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 93 * @NL80211_CMD_MAX: highest used command number 82 94 * @__NL80211_CMD_AFTER_LAST: internal use 83 95 */ ··· 123 111 NL80211_CMD_DEL_STATION, 124 112 125 113 /* add commands here */ 114 + 115 + NL80211_CMD_GET_MPATH, 116 + NL80211_CMD_SET_MPATH, 117 + NL80211_CMD_NEW_MPATH, 118 + NL80211_CMD_DEL_MPATH, 126 119 127 120 /* used to define NL80211_CMD_MAX below */ 128 121 __NL80211_CMD_AFTER_LAST, ··· 174 157 * restriction (at most %NL80211_MAX_SUPP_RATES). 175 158 * @NL80211_ATTR_STA_VLAN: interface index of VLAN interface to move station 176 159 * to, or the AP interface the station was originally added to to. 177 - * @NL80211_ATTR_STA_STATS: statistics for a station, part of station info 160 + * @NL80211_ATTR_STA_INFO: information about a station, part of station info 178 161 * given for %NL80211_CMD_GET_STATION, nested attribute containing 179 - * info as possible, see &enum nl80211_sta_stats. 162 + * info as possible, see &enum nl80211_sta_info. 180 163 * 181 164 * @NL80211_ATTR_WIPHY_BANDS: Information about an operating bands, 182 165 * consisting of a nested array. 166 + * 167 + * @NL80211_ATTR_MESH_ID: mesh id (1-32 bytes). 168 + * @NL80211_ATTR_PLINK_ACTION: action to perform on the mesh peer link. 169 + * @NL80211_ATTR_MPATH_NEXT_HOP: MAC address of the next hop for a mesh path. 170 + * @NL80211_ATTR_MPATH_INFO: information about a mesh_path, part of mesh path 171 + * info given for %NL80211_CMD_GET_MPATH, nested attribute described at 172 + * &enum nl80211_mpath_info. 173 + * 183 174 * 184 175 * @NL80211_ATTR_MNTR_FLAGS: flags, nested element with NLA_FLAG attributes of 185 176 * &enum nl80211_mntr_flags. ··· 224 199 NL80211_ATTR_STA_LISTEN_INTERVAL, 225 200 NL80211_ATTR_STA_SUPPORTED_RATES, 226 201 NL80211_ATTR_STA_VLAN, 227 - NL80211_ATTR_STA_STATS, 202 + NL80211_ATTR_STA_INFO, 228 203 229 204 NL80211_ATTR_WIPHY_BANDS, 230 205 231 206 NL80211_ATTR_MNTR_FLAGS, 232 207 233 208 /* add attributes here, update the policy in nl80211.c */ 209 + 210 + NL80211_ATTR_MESH_ID, 211 + NL80211_ATTR_STA_PLINK_ACTION, 212 + NL80211_ATTR_MPATH_NEXT_HOP, 213 + NL80211_ATTR_MPATH_INFO, 234 214 235 215 __NL80211_ATTR_AFTER_LAST, 236 216 NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1 ··· 253 223 * @NL80211_IFTYPE_AP_VLAN: VLAN interface for access points 254 224 * @NL80211_IFTYPE_WDS: wireless distribution interface 255 225 * @NL80211_IFTYPE_MONITOR: monitor interface receiving all frames 226 + * @NL80211_IFTYPE_MESH_POINT: mesh point 256 227 * @NL80211_IFTYPE_MAX: highest interface type number currently defined 257 228 * @__NL80211_IFTYPE_AFTER_LAST: internal use 258 229 * ··· 269 238 NL80211_IFTYPE_AP_VLAN, 270 239 NL80211_IFTYPE_WDS, 271 240 NL80211_IFTYPE_MONITOR, 241 + NL80211_IFTYPE_MESH_POINT, 272 242 273 243 /* keep last */ 274 244 __NL80211_IFTYPE_AFTER_LAST, ··· 299 267 }; 300 268 301 269 /** 302 - * enum nl80211_sta_stats - station statistics 270 + * enum nl80211_sta_info - station information 303 271 * 304 - * These attribute types are used with %NL80211_ATTR_STA_STATS 272 + * These attribute types are used with %NL80211_ATTR_STA_INFO 305 273 * when getting information about a station. 306 274 * 307 - * @__NL80211_STA_STAT_INVALID: attribute number 0 is reserved 308 - * @NL80211_STA_STAT_INACTIVE_TIME: time since last activity (u32, msecs) 309 - * @NL80211_STA_STAT_RX_BYTES: total received bytes (u32, from this station) 310 - * @NL80211_STA_STAT_TX_BYTES: total transmitted bytes (u32, to this station) 311 - * @__NL80211_STA_STAT_AFTER_LAST: internal 312 - * @NL80211_STA_STAT_MAX: highest possible station stats attribute 275 + * @__NL80211_STA_INFO_INVALID: attribute number 0 is reserved 276 + * @NL80211_STA_INFO_INACTIVE_TIME: time since last activity (u32, msecs) 277 + * @NL80211_STA_INFO_RX_BYTES: total received bytes (u32, from this station) 278 + * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station) 279 + * @__NL80211_STA_INFO_AFTER_LAST: internal 280 + * @NL80211_STA_INFO_MAX: highest possible station info attribute 313 281 */ 314 - enum nl80211_sta_stats { 315 - __NL80211_STA_STAT_INVALID, 316 - NL80211_STA_STAT_INACTIVE_TIME, 317 - NL80211_STA_STAT_RX_BYTES, 318 - NL80211_STA_STAT_TX_BYTES, 282 + enum nl80211_sta_info { 283 + __NL80211_STA_INFO_INVALID, 284 + NL80211_STA_INFO_INACTIVE_TIME, 285 + NL80211_STA_INFO_RX_BYTES, 286 + NL80211_STA_INFO_TX_BYTES, 287 + NL80211_STA_INFO_LLID, 288 + NL80211_STA_INFO_PLID, 289 + NL80211_STA_INFO_PLINK_STATE, 319 290 320 291 /* keep last */ 321 - __NL80211_STA_STAT_AFTER_LAST, 322 - NL80211_STA_STAT_MAX = __NL80211_STA_STAT_AFTER_LAST - 1 292 + __NL80211_STA_INFO_AFTER_LAST, 293 + NL80211_STA_INFO_MAX = __NL80211_STA_INFO_AFTER_LAST - 1 294 + }; 295 + 296 + /** 297 + * enum nl80211_mpath_flags - nl80211 mesh path flags 298 + * 299 + * @NL80211_MPATH_FLAG_ACTIVE: the mesh path is active 300 + * @NL80211_MPATH_FLAG_RESOLVING: the mesh path discovery process is running 301 + * @NL80211_MPATH_FLAG_DSN_VALID: the mesh path contains a valid DSN 302 + * @NL80211_MPATH_FLAG_FIXED: the mesh path has been manually set 303 + * @NL80211_MPATH_FLAG_RESOLVED: the mesh path discovery process succeeded 304 + */ 305 + enum nl80211_mpath_flags { 306 + NL80211_MPATH_FLAG_ACTIVE = 1<<0, 307 + NL80211_MPATH_FLAG_RESOLVING = 1<<1, 308 + NL80211_MPATH_FLAG_DSN_VALID = 1<<2, 309 + NL80211_MPATH_FLAG_FIXED = 1<<3, 310 + NL80211_MPATH_FLAG_RESOLVED = 1<<4, 311 + }; 312 + 313 + /** 314 + * enum nl80211_mpath_info - mesh path information 315 + * 316 + * These attribute types are used with %NL80211_ATTR_MPATH_INFO when getting 317 + * information about a mesh path. 318 + * 319 + * @__NL80211_MPATH_INFO_INVALID: attribute number 0 is reserved 320 + * @NL80211_ATTR_MPATH_FRAME_QLEN: number of queued frames for this destination 321 + * @NL80211_ATTR_MPATH_DSN: destination sequence number 322 + * @NL80211_ATTR_MPATH_METRIC: metric (cost) of this mesh path 323 + * @NL80211_ATTR_MPATH_EXPTIME: expiration time for the path, in msec from now 324 + * @NL80211_ATTR_MPATH_FLAGS: mesh path flags, enumerated in 325 + * &enum nl80211_mpath_flags; 326 + * @NL80211_ATTR_MPATH_DISCOVERY_TIMEOUT: total path discovery timeout, in msec 327 + * @NL80211_ATTR_MPATH_DISCOVERY_RETRIES: mesh path discovery retries 328 + */ 329 + enum nl80211_mpath_info { 330 + __NL80211_MPATH_INFO_INVALID, 331 + NL80211_MPATH_INFO_FRAME_QLEN, 332 + NL80211_MPATH_INFO_DSN, 333 + NL80211_MPATH_INFO_METRIC, 334 + NL80211_MPATH_INFO_EXPTIME, 335 + NL80211_MPATH_INFO_FLAGS, 336 + NL80211_MPATH_INFO_DISCOVERY_TIMEOUT, 337 + NL80211_MPATH_INFO_DISCOVERY_RETRIES, 338 + 339 + /* keep last */ 340 + __NL80211_MPATH_INFO_AFTER_LAST, 341 + NL80211_MPATH_INFO_MAX = __NL80211_MPATH_INFO_AFTER_LAST - 1 323 342 }; 324 343 325 344 /**
+122 -17
include/net/cfg80211.h
··· 12 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 25 /* Radiotap header iteration 16 26 * implemented in net/wireless/radiotap.c 17 27 * docs in Documentation/networking/radiotap-headers.txt ··· 119 109 }; 120 110 121 111 /** 112 + * enum plink_action - actions to perform in mesh peers 113 + * 114 + * @PLINK_ACTION_INVALID: action 0 is reserved 115 + * @PLINK_ACTION_OPEN: start mesh peer link establishment 116 + * @PLINK_ACTION_BLOCL: block traffic from this mesh peer 117 + */ 118 + enum plink_actions { 119 + PLINK_ACTION_INVALID, 120 + PLINK_ACTION_OPEN, 121 + PLINK_ACTION_BLOCK, 122 + }; 123 + 124 + /** 122 125 * struct station_parameters - station parameters 123 126 * 124 127 * Used to change and create a new station. ··· 151 128 int listen_interval; 152 129 u16 aid; 153 130 u8 supported_rates_len; 131 + u8 plink_action; 154 132 }; 155 133 156 134 /** 157 - * enum station_stats_flags - station statistics flags 135 + * enum station_info_flags - station information flags 158 136 * 159 - * Used by the driver to indicate which info in &struct station_stats 160 - * it has filled in during get_station(). 137 + * Used by the driver to indicate which info in &struct station_info 138 + * it has filled in during get_station() or dump_station(). 161 139 * 162 - * @STATION_STAT_INACTIVE_TIME: @inactive_time filled 163 - * @STATION_STAT_RX_BYTES: @rx_bytes filled 164 - * @STATION_STAT_TX_BYTES: @tx_bytes filled 140 + * @STATION_INFO_INACTIVE_TIME: @inactive_time filled 141 + * @STATION_INFO_RX_BYTES: @rx_bytes filled 142 + * @STATION_INFO_TX_BYTES: @tx_bytes filled 143 + * @STATION_INFO_LLID: @llid filled 144 + * @STATION_INFO_PLID: @plid filled 145 + * @STATION_INFO_PLINK_STATE: @plink_state filled 165 146 */ 166 - enum station_stats_flags { 167 - STATION_STAT_INACTIVE_TIME = 1<<0, 168 - STATION_STAT_RX_BYTES = 1<<1, 169 - STATION_STAT_TX_BYTES = 1<<2, 147 + enum station_info_flags { 148 + STATION_INFO_INACTIVE_TIME = 1<<0, 149 + STATION_INFO_RX_BYTES = 1<<1, 150 + STATION_INFO_TX_BYTES = 1<<2, 151 + STATION_INFO_LLID = 1<<3, 152 + STATION_INFO_PLID = 1<<4, 153 + STATION_INFO_PLINK_STATE = 1<<5, 170 154 }; 171 155 172 156 /** 173 - * struct station_stats - station statistics 157 + * struct station_info - station information 174 158 * 175 - * Station information filled by driver for get_station(). 159 + * Station information filled by driver for get_station() and dump_station. 176 160 * 177 - * @filled: bitflag of flags from &enum station_stats_flags 161 + * @filled: bitflag of flags from &enum station_info_flags 178 162 * @inactive_time: time since last station activity (tx/rx) in milliseconds 179 163 * @rx_bytes: bytes received from this station 180 164 * @tx_bytes: bytes transmitted to this station 165 + * @llid: mesh local link id 166 + * @plid: mesh peer link id 167 + * @plink_state: mesh peer link state 181 168 */ 182 - struct station_stats { 169 + struct station_info { 183 170 u32 filled; 184 171 u32 inactive_time; 185 172 u32 rx_bytes; 186 173 u32 tx_bytes; 174 + u16 llid; 175 + u16 plid; 176 + u8 plink_state; 187 177 }; 188 178 189 179 /** ··· 218 182 MONITOR_FLAG_OTHER_BSS = 1<<NL80211_MNTR_FLAG_OTHER_BSS, 219 183 MONITOR_FLAG_COOK_FRAMES = 1<<NL80211_MNTR_FLAG_COOK_FRAMES, 220 184 }; 185 + 186 + /** 187 + * enum mpath_info_flags - mesh path information flags 188 + * 189 + * Used by the driver to indicate which info in &struct mpath_info it has filled 190 + * in during get_station() or dump_station(). 191 + * 192 + * MPATH_INFO_FRAME_QLEN: @frame_qlen filled 193 + * MPATH_INFO_DSN: @dsn filled 194 + * MPATH_INFO_METRIC: @metric filled 195 + * MPATH_INFO_EXPTIME: @exptime filled 196 + * MPATH_INFO_DISCOVERY_TIMEOUT: @discovery_timeout filled 197 + * MPATH_INFO_DISCOVERY_RETRIES: @discovery_retries filled 198 + * MPATH_INFO_FLAGS: @flags filled 199 + */ 200 + enum mpath_info_flags { 201 + MPATH_INFO_FRAME_QLEN = BIT(0), 202 + MPATH_INFO_DSN = BIT(1), 203 + MPATH_INFO_METRIC = BIT(2), 204 + MPATH_INFO_EXPTIME = BIT(3), 205 + MPATH_INFO_DISCOVERY_TIMEOUT = BIT(4), 206 + MPATH_INFO_DISCOVERY_RETRIES = BIT(5), 207 + MPATH_INFO_FLAGS = BIT(6), 208 + }; 209 + 210 + /** 211 + * struct mpath_info - mesh path information 212 + * 213 + * Mesh path information filled by driver for get_mpath() and dump_mpath(). 214 + * 215 + * @filled: bitfield of flags from &enum mpath_info_flags 216 + * @frame_qlen: number of queued frames for this destination 217 + * @dsn: destination sequence number 218 + * @metric: metric (cost) of this mesh path 219 + * @exptime: expiration time for the mesh path from now, in msecs 220 + * @flags: mesh path flags 221 + * @discovery_timeout: total mesh path discovery timeout, in msecs 222 + * @discovery_retries: mesh path discovery retries 223 + */ 224 + struct mpath_info { 225 + u32 filled; 226 + u32 frame_qlen; 227 + u32 dsn; 228 + u32 metric; 229 + u32 exptime; 230 + u32 discovery_timeout; 231 + u8 discovery_retries; 232 + u8 flags; 233 + }; 234 + 221 235 222 236 /* from net/wireless.h */ 223 237 struct wiphy; ··· 316 230 * @del_station: Remove a station; @mac may be NULL to remove all stations. 317 231 * 318 232 * @change_station: Modify a given station. 233 + * 234 + * @set_mesh_cfg: set mesh parameters (by now, just mesh id) 319 235 */ 320 236 struct cfg80211_ops { 321 237 int (*add_virtual_intf)(struct wiphy *wiphy, char *name, 322 - enum nl80211_iftype type, u32 *flags); 238 + enum nl80211_iftype type, u32 *flags, 239 + struct vif_params *params); 323 240 int (*del_virtual_intf)(struct wiphy *wiphy, int ifindex); 324 241 int (*change_virtual_intf)(struct wiphy *wiphy, int ifindex, 325 - enum nl80211_iftype type, u32 *flags); 242 + enum nl80211_iftype type, u32 *flags, 243 + struct vif_params *params); 326 244 327 245 int (*add_key)(struct wiphy *wiphy, struct net_device *netdev, 328 246 u8 key_index, u8 *mac_addr, ··· 354 264 int (*change_station)(struct wiphy *wiphy, struct net_device *dev, 355 265 u8 *mac, struct station_parameters *params); 356 266 int (*get_station)(struct wiphy *wiphy, struct net_device *dev, 357 - u8 *mac, struct station_stats *stats); 267 + u8 *mac, struct station_info *sinfo); 268 + int (*dump_station)(struct wiphy *wiphy, struct net_device *dev, 269 + int idx, u8 *mac, struct station_info *sinfo); 270 + 271 + int (*add_mpath)(struct wiphy *wiphy, struct net_device *dev, 272 + u8 *dst, u8 *next_hop); 273 + int (*del_mpath)(struct wiphy *wiphy, struct net_device *dev, 274 + u8 *dst); 275 + int (*change_mpath)(struct wiphy *wiphy, struct net_device *dev, 276 + u8 *dst, u8 *next_hop); 277 + int (*get_mpath)(struct wiphy *wiphy, struct net_device *dev, 278 + u8 *dst, u8 *next_hop, 279 + struct mpath_info *pinfo); 280 + int (*dump_mpath)(struct wiphy *wiphy, struct net_device *dev, 281 + int idx, u8 *dst, u8 *next_hop, 282 + struct mpath_info *pinfo); 358 283 }; 359 284 360 285 #endif /* __NET_CFG80211_H */
+11 -9
net/mac80211/cfg.c
··· 34 34 } 35 35 36 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 40 struct ieee80211_local *local = wiphy_priv(wiphy); 40 41 enum ieee80211_if_types itype; ··· 79 78 } 80 79 81 80 static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex, 82 - enum nl80211_iftype type, u32 *flags) 81 + enum nl80211_iftype type, u32 *flags, 82 + struct vif_params *params) 83 83 { 84 84 struct ieee80211_local *local = wiphy_priv(wiphy); 85 85 struct net_device *dev; ··· 298 296 } 299 297 300 298 static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, 301 - u8 *mac, struct station_stats *stats) 299 + u8 *mac, struct station_info *sinfo) 302 300 { 303 301 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); 304 302 struct sta_info *sta; ··· 309 307 310 308 /* XXX: verify sta->dev == dev */ 311 309 312 - stats->filled = STATION_STAT_INACTIVE_TIME | 313 - STATION_STAT_RX_BYTES | 314 - STATION_STAT_TX_BYTES; 310 + sinfo->filled = STATION_INFO_INACTIVE_TIME | 311 + STATION_INFO_RX_BYTES | 312 + STATION_INFO_TX_BYTES; 315 313 316 - stats->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); 317 - stats->rx_bytes = sta->rx_bytes; 318 - stats->tx_bytes = sta->tx_bytes; 314 + sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); 315 + sinfo->rx_bytes = sta->rx_bytes; 316 + sinfo->tx_bytes = sta->tx_bytes; 319 317 320 318 sta_info_put(sta); 321 319
+415 -21
net/wireless/nl80211.c
··· 81 81 [NL80211_ATTR_STA_LISTEN_INTERVAL] = { .type = NLA_U16 }, 82 82 [NL80211_ATTR_STA_SUPPORTED_RATES] = { .type = NLA_BINARY, 83 83 .len = NL80211_MAX_SUPP_RATES }, 84 + [NL80211_ATTR_STA_PLINK_ACTION] = { .type = NLA_U8 }, 84 85 [NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 }, 85 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 92 /* message building helper */ ··· 373 369 static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) 374 370 { 375 371 struct cfg80211_registered_device *drv; 372 + struct vif_params params; 376 373 int err, ifindex; 377 374 enum nl80211_iftype type; 378 375 struct net_device *dev; 379 376 u32 flags; 377 + 378 + memset(&params, 0, sizeof(params)); 380 379 381 380 if (info->attrs[NL80211_ATTR_IFTYPE]) { 382 381 type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); ··· 399 392 goto unlock; 400 393 } 401 394 395 + if (type == NL80211_IFTYPE_MESH_POINT && 396 + info->attrs[NL80211_ATTR_MESH_ID]) { 397 + params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); 398 + params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); 399 + } 400 + 402 401 rtnl_lock(); 403 402 err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? 404 403 info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, 405 404 &flags); 406 405 err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, 407 - type, err ? NULL : &flags); 406 + type, err ? NULL : &flags, &params); 408 407 rtnl_unlock(); 409 408 410 409 unlock: ··· 421 408 static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) 422 409 { 423 410 struct cfg80211_registered_device *drv; 411 + struct vif_params params; 424 412 int err; 425 413 enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; 426 414 u32 flags; 415 + 416 + memset(&params, 0, sizeof(params)); 427 417 428 418 if (!info->attrs[NL80211_ATTR_IFNAME]) 429 419 return -EINVAL; ··· 446 430 goto unlock; 447 431 } 448 432 433 + if (type == NL80211_IFTYPE_MESH_POINT && 434 + info->attrs[NL80211_ATTR_MESH_ID]) { 435 + params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); 436 + params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); 437 + } 438 + 449 439 rtnl_lock(); 450 440 err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? 451 441 info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, 452 442 &flags); 453 443 err = drv->ops->add_virtual_intf(&drv->wiphy, 454 444 nla_data(info->attrs[NL80211_ATTR_IFNAME]), 455 - type, err ? NULL : &flags); 445 + type, err ? NULL : &flags, &params); 456 446 rtnl_unlock(); 447 + 457 448 458 449 unlock: 459 450 cfg80211_put_dev(drv); ··· 889 866 890 867 static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, 891 868 int flags, struct net_device *dev, 892 - u8 *mac_addr, struct station_stats *stats) 869 + u8 *mac_addr, struct station_info *sinfo) 893 870 { 894 871 void *hdr; 895 - struct nlattr *statsattr; 872 + struct nlattr *sinfoattr; 896 873 897 874 hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION); 898 875 if (!hdr) ··· 901 878 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); 902 879 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); 903 880 904 - statsattr = nla_nest_start(msg, NL80211_ATTR_STA_STATS); 905 - if (!statsattr) 881 + sinfoattr = nla_nest_start(msg, NL80211_ATTR_STA_INFO); 882 + if (!sinfoattr) 906 883 goto nla_put_failure; 907 - if (stats->filled & STATION_STAT_INACTIVE_TIME) 908 - NLA_PUT_U32(msg, NL80211_STA_STAT_INACTIVE_TIME, 909 - stats->inactive_time); 910 - if (stats->filled & STATION_STAT_RX_BYTES) 911 - NLA_PUT_U32(msg, NL80211_STA_STAT_RX_BYTES, 912 - stats->rx_bytes); 913 - if (stats->filled & STATION_STAT_TX_BYTES) 914 - NLA_PUT_U32(msg, NL80211_STA_STAT_TX_BYTES, 915 - stats->tx_bytes); 884 + if (sinfo->filled & STATION_INFO_INACTIVE_TIME) 885 + NLA_PUT_U32(msg, NL80211_STA_INFO_INACTIVE_TIME, 886 + sinfo->inactive_time); 887 + if (sinfo->filled & STATION_INFO_RX_BYTES) 888 + NLA_PUT_U32(msg, NL80211_STA_INFO_RX_BYTES, 889 + sinfo->rx_bytes); 890 + if (sinfo->filled & STATION_INFO_TX_BYTES) 891 + NLA_PUT_U32(msg, NL80211_STA_INFO_TX_BYTES, 892 + sinfo->tx_bytes); 893 + if (sinfo->filled & STATION_INFO_LLID) 894 + NLA_PUT_U16(msg, NL80211_STA_INFO_LLID, 895 + sinfo->llid); 896 + if (sinfo->filled & STATION_INFO_PLID) 897 + NLA_PUT_U16(msg, NL80211_STA_INFO_PLID, 898 + sinfo->plid); 899 + if (sinfo->filled & STATION_INFO_PLINK_STATE) 900 + NLA_PUT_U8(msg, NL80211_STA_INFO_PLINK_STATE, 901 + sinfo->plink_state); 916 902 917 - nla_nest_end(msg, statsattr); 903 + nla_nest_end(msg, sinfoattr); 918 904 919 905 return genlmsg_end(msg, hdr); 920 906 ··· 931 899 return genlmsg_cancel(msg, hdr); 932 900 } 933 901 902 + static int nl80211_dump_station(struct sk_buff *skb, 903 + struct netlink_callback *cb) 904 + { 905 + int wp_idx = 0; 906 + int if_idx = 0; 907 + int sta_idx = cb->args[2]; 908 + int wp_start = cb->args[0]; 909 + int if_start = cb->args[1]; 910 + struct station_info sinfo; 911 + struct cfg80211_registered_device *dev; 912 + struct wireless_dev *wdev; 913 + u8 mac_addr[ETH_ALEN]; 914 + int err; 915 + int exit = 0; 916 + 917 + /* TODO: filter by device */ 918 + mutex_lock(&cfg80211_drv_mutex); 919 + list_for_each_entry(dev, &cfg80211_drv_list, list) { 920 + if (exit) 921 + break; 922 + if (++wp_idx < wp_start) 923 + continue; 924 + if_idx = 0; 925 + 926 + mutex_lock(&dev->devlist_mtx); 927 + list_for_each_entry(wdev, &dev->netdev_list, list) { 928 + if (exit) 929 + break; 930 + if (++if_idx < if_start) 931 + continue; 932 + if (!dev->ops->dump_station) 933 + continue; 934 + 935 + for (;; ++sta_idx) { 936 + rtnl_lock(); 937 + err = dev->ops->dump_station(&dev->wiphy, 938 + wdev->netdev, sta_idx, mac_addr, 939 + &sinfo); 940 + rtnl_unlock(); 941 + if (err) { 942 + sta_idx = 0; 943 + break; 944 + } 945 + if (nl80211_send_station(skb, 946 + NETLINK_CB(cb->skb).pid, 947 + cb->nlh->nlmsg_seq, NLM_F_MULTI, 948 + wdev->netdev, mac_addr, 949 + &sinfo) < 0) { 950 + exit = 1; 951 + break; 952 + } 953 + } 954 + } 955 + mutex_unlock(&dev->devlist_mtx); 956 + } 957 + mutex_unlock(&cfg80211_drv_mutex); 958 + 959 + cb->args[0] = wp_idx; 960 + cb->args[1] = if_idx; 961 + cb->args[2] = sta_idx; 962 + 963 + return skb->len; 964 + } 934 965 935 966 static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) 936 967 { 937 968 struct cfg80211_registered_device *drv; 938 969 int err; 939 970 struct net_device *dev; 940 - struct station_stats stats; 971 + struct station_info sinfo; 941 972 struct sk_buff *msg; 942 973 u8 *mac_addr = NULL; 943 974 944 - memset(&stats, 0, sizeof(stats)); 975 + memset(&sinfo, 0, sizeof(sinfo)); 945 976 946 977 if (!info->attrs[NL80211_ATTR_MAC]) 947 978 return -EINVAL; ··· 1021 926 } 1022 927 1023 928 rtnl_lock(); 1024 - err = drv->ops->get_station(&drv->wiphy, dev, mac_addr, &stats); 929 + err = drv->ops->get_station(&drv->wiphy, dev, mac_addr, &sinfo); 1025 930 rtnl_unlock(); 931 + 932 + if (err) 933 + goto out; 1026 934 1027 935 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 1028 936 if (!msg) 1029 937 goto out; 1030 938 1031 939 if (nl80211_send_station(msg, info->snd_pid, info->snd_seq, 0, 1032 - dev, mac_addr, &stats) < 0) 940 + dev, mac_addr, &sinfo) < 0) 1033 941 goto out_free; 1034 942 1035 943 err = genlmsg_unicast(msg, info->snd_pid); ··· 1102 1004 if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS], 1103 1005 &params.station_flags)) 1104 1006 return -EINVAL; 1007 + 1008 + if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) 1009 + params.plink_action = 1010 + nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); 1105 1011 1106 1012 err = get_drv_dev_by_info_ifindex(info, &drv, &dev); 1107 1013 if (err) ··· 1221 1119 return err; 1222 1120 } 1223 1121 1122 + static int nl80211_send_mpath(struct sk_buff *msg, u32 pid, u32 seq, 1123 + int flags, struct net_device *dev, 1124 + u8 *dst, u8 *next_hop, 1125 + struct mpath_info *pinfo) 1126 + { 1127 + void *hdr; 1128 + struct nlattr *pinfoattr; 1129 + 1130 + hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION); 1131 + if (!hdr) 1132 + return -1; 1133 + 1134 + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); 1135 + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst); 1136 + NLA_PUT(msg, NL80211_ATTR_MPATH_NEXT_HOP, ETH_ALEN, next_hop); 1137 + 1138 + pinfoattr = nla_nest_start(msg, NL80211_ATTR_MPATH_INFO); 1139 + if (!pinfoattr) 1140 + goto nla_put_failure; 1141 + if (pinfo->filled & MPATH_INFO_FRAME_QLEN) 1142 + NLA_PUT_U32(msg, NL80211_MPATH_INFO_FRAME_QLEN, 1143 + pinfo->frame_qlen); 1144 + if (pinfo->filled & MPATH_INFO_DSN) 1145 + NLA_PUT_U32(msg, NL80211_MPATH_INFO_DSN, 1146 + pinfo->dsn); 1147 + if (pinfo->filled & MPATH_INFO_METRIC) 1148 + NLA_PUT_U32(msg, NL80211_MPATH_INFO_METRIC, 1149 + pinfo->metric); 1150 + if (pinfo->filled & MPATH_INFO_EXPTIME) 1151 + NLA_PUT_U32(msg, NL80211_MPATH_INFO_EXPTIME, 1152 + pinfo->exptime); 1153 + if (pinfo->filled & MPATH_INFO_FLAGS) 1154 + NLA_PUT_U8(msg, NL80211_MPATH_INFO_FLAGS, 1155 + pinfo->flags); 1156 + if (pinfo->filled & MPATH_INFO_DISCOVERY_TIMEOUT) 1157 + NLA_PUT_U32(msg, NL80211_MPATH_INFO_DISCOVERY_TIMEOUT, 1158 + pinfo->discovery_timeout); 1159 + if (pinfo->filled & MPATH_INFO_DISCOVERY_RETRIES) 1160 + NLA_PUT_U8(msg, NL80211_MPATH_INFO_DISCOVERY_RETRIES, 1161 + pinfo->discovery_retries); 1162 + 1163 + nla_nest_end(msg, pinfoattr); 1164 + 1165 + return genlmsg_end(msg, hdr); 1166 + 1167 + nla_put_failure: 1168 + return genlmsg_cancel(msg, hdr); 1169 + } 1170 + 1171 + static int nl80211_dump_mpath(struct sk_buff *skb, 1172 + struct netlink_callback *cb) 1173 + { 1174 + int wp_idx = 0; 1175 + int if_idx = 0; 1176 + int sta_idx = cb->args[2]; 1177 + int wp_start = cb->args[0]; 1178 + int if_start = cb->args[1]; 1179 + struct mpath_info pinfo; 1180 + struct cfg80211_registered_device *dev; 1181 + struct wireless_dev *wdev; 1182 + u8 dst[ETH_ALEN]; 1183 + u8 next_hop[ETH_ALEN]; 1184 + int err; 1185 + int exit = 0; 1186 + 1187 + /* TODO: filter by device */ 1188 + mutex_lock(&cfg80211_drv_mutex); 1189 + list_for_each_entry(dev, &cfg80211_drv_list, list) { 1190 + if (exit) 1191 + break; 1192 + if (++wp_idx < wp_start) 1193 + continue; 1194 + if_idx = 0; 1195 + 1196 + mutex_lock(&dev->devlist_mtx); 1197 + list_for_each_entry(wdev, &dev->netdev_list, list) { 1198 + if (exit) 1199 + break; 1200 + if (++if_idx < if_start) 1201 + continue; 1202 + if (!dev->ops->dump_mpath) 1203 + continue; 1204 + 1205 + for (;; ++sta_idx) { 1206 + rtnl_lock(); 1207 + err = dev->ops->dump_mpath(&dev->wiphy, 1208 + wdev->netdev, sta_idx, dst, 1209 + next_hop, &pinfo); 1210 + rtnl_unlock(); 1211 + if (err) { 1212 + sta_idx = 0; 1213 + break; 1214 + } 1215 + if (nl80211_send_mpath(skb, 1216 + NETLINK_CB(cb->skb).pid, 1217 + cb->nlh->nlmsg_seq, NLM_F_MULTI, 1218 + wdev->netdev, dst, next_hop, 1219 + &pinfo) < 0) { 1220 + exit = 1; 1221 + break; 1222 + } 1223 + } 1224 + } 1225 + mutex_unlock(&dev->devlist_mtx); 1226 + } 1227 + mutex_unlock(&cfg80211_drv_mutex); 1228 + 1229 + cb->args[0] = wp_idx; 1230 + cb->args[1] = if_idx; 1231 + cb->args[2] = sta_idx; 1232 + 1233 + return skb->len; 1234 + } 1235 + 1236 + static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) 1237 + { 1238 + struct cfg80211_registered_device *drv; 1239 + int err; 1240 + struct net_device *dev; 1241 + struct mpath_info pinfo; 1242 + struct sk_buff *msg; 1243 + u8 *dst = NULL; 1244 + u8 next_hop[ETH_ALEN]; 1245 + 1246 + memset(&pinfo, 0, sizeof(pinfo)); 1247 + 1248 + if (!info->attrs[NL80211_ATTR_MAC]) 1249 + return -EINVAL; 1250 + 1251 + dst = nla_data(info->attrs[NL80211_ATTR_MAC]); 1252 + 1253 + err = get_drv_dev_by_info_ifindex(info, &drv, &dev); 1254 + if (err) 1255 + return err; 1256 + 1257 + if (!drv->ops->get_mpath) { 1258 + err = -EOPNOTSUPP; 1259 + goto out; 1260 + } 1261 + 1262 + rtnl_lock(); 1263 + err = drv->ops->get_mpath(&drv->wiphy, dev, dst, next_hop, &pinfo); 1264 + rtnl_unlock(); 1265 + 1266 + if (err) 1267 + goto out; 1268 + 1269 + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 1270 + if (!msg) 1271 + goto out; 1272 + 1273 + if (nl80211_send_mpath(msg, info->snd_pid, info->snd_seq, 0, 1274 + dev, dst, next_hop, &pinfo) < 0) 1275 + goto out_free; 1276 + 1277 + err = genlmsg_unicast(msg, info->snd_pid); 1278 + goto out; 1279 + 1280 + out_free: 1281 + nlmsg_free(msg); 1282 + 1283 + out: 1284 + cfg80211_put_dev(drv); 1285 + dev_put(dev); 1286 + return err; 1287 + } 1288 + 1289 + static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info) 1290 + { 1291 + struct cfg80211_registered_device *drv; 1292 + int err; 1293 + struct net_device *dev; 1294 + u8 *dst = NULL; 1295 + u8 *next_hop = NULL; 1296 + 1297 + if (!info->attrs[NL80211_ATTR_MAC]) 1298 + return -EINVAL; 1299 + 1300 + if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]) 1301 + return -EINVAL; 1302 + 1303 + dst = nla_data(info->attrs[NL80211_ATTR_MAC]); 1304 + next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); 1305 + 1306 + err = get_drv_dev_by_info_ifindex(info, &drv, &dev); 1307 + if (err) 1308 + return err; 1309 + 1310 + if (!drv->ops->change_mpath) { 1311 + err = -EOPNOTSUPP; 1312 + goto out; 1313 + } 1314 + 1315 + rtnl_lock(); 1316 + err = drv->ops->change_mpath(&drv->wiphy, dev, dst, next_hop); 1317 + rtnl_unlock(); 1318 + 1319 + out: 1320 + cfg80211_put_dev(drv); 1321 + dev_put(dev); 1322 + return err; 1323 + } 1324 + static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) 1325 + { 1326 + struct cfg80211_registered_device *drv; 1327 + int err; 1328 + struct net_device *dev; 1329 + u8 *dst = NULL; 1330 + u8 *next_hop = NULL; 1331 + 1332 + if (!info->attrs[NL80211_ATTR_MAC]) 1333 + return -EINVAL; 1334 + 1335 + if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]) 1336 + return -EINVAL; 1337 + 1338 + dst = nla_data(info->attrs[NL80211_ATTR_MAC]); 1339 + next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); 1340 + 1341 + err = get_drv_dev_by_info_ifindex(info, &drv, &dev); 1342 + if (err) 1343 + return err; 1344 + 1345 + if (!drv->ops->add_mpath) { 1346 + err = -EOPNOTSUPP; 1347 + goto out; 1348 + } 1349 + 1350 + rtnl_lock(); 1351 + err = drv->ops->add_mpath(&drv->wiphy, dev, dst, next_hop); 1352 + rtnl_unlock(); 1353 + 1354 + out: 1355 + cfg80211_put_dev(drv); 1356 + dev_put(dev); 1357 + return err; 1358 + } 1359 + 1360 + static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info) 1361 + { 1362 + struct cfg80211_registered_device *drv; 1363 + int err; 1364 + struct net_device *dev; 1365 + u8 *dst = NULL; 1366 + 1367 + if (info->attrs[NL80211_ATTR_MAC]) 1368 + dst = nla_data(info->attrs[NL80211_ATTR_MAC]); 1369 + 1370 + err = get_drv_dev_by_info_ifindex(info, &drv, &dev); 1371 + if (err) 1372 + return err; 1373 + 1374 + if (!drv->ops->del_mpath) { 1375 + err = -EOPNOTSUPP; 1376 + goto out; 1377 + } 1378 + 1379 + rtnl_lock(); 1380 + err = drv->ops->del_mpath(&drv->wiphy, dev, dst); 1381 + rtnl_unlock(); 1382 + 1383 + out: 1384 + cfg80211_put_dev(drv); 1385 + dev_put(dev); 1386 + return err; 1387 + } 1388 + 1224 1389 static struct genl_ops nl80211_ops[] = { 1225 1390 { 1226 1391 .cmd = NL80211_CMD_GET_WIPHY, ··· 1572 1203 { 1573 1204 .cmd = NL80211_CMD_GET_STATION, 1574 1205 .doit = nl80211_get_station, 1575 - /* TODO: implement dumpit */ 1206 + .dumpit = nl80211_dump_station, 1576 1207 .policy = nl80211_policy, 1577 1208 .flags = GENL_ADMIN_PERM, 1578 1209 }, ··· 1591 1222 { 1592 1223 .cmd = NL80211_CMD_DEL_STATION, 1593 1224 .doit = nl80211_del_station, 1225 + .policy = nl80211_policy, 1226 + .flags = GENL_ADMIN_PERM, 1227 + }, 1228 + { 1229 + .cmd = NL80211_CMD_GET_MPATH, 1230 + .doit = nl80211_get_mpath, 1231 + .dumpit = nl80211_dump_mpath, 1232 + .policy = nl80211_policy, 1233 + .flags = GENL_ADMIN_PERM, 1234 + }, 1235 + { 1236 + .cmd = NL80211_CMD_SET_MPATH, 1237 + .doit = nl80211_set_mpath, 1238 + .policy = nl80211_policy, 1239 + .flags = GENL_ADMIN_PERM, 1240 + }, 1241 + { 1242 + .cmd = NL80211_CMD_NEW_MPATH, 1243 + .doit = nl80211_new_mpath, 1244 + .policy = nl80211_policy, 1245 + .flags = GENL_ADMIN_PERM, 1246 + }, 1247 + { 1248 + .cmd = NL80211_CMD_DEL_MPATH, 1249 + .doit = nl80211_del_mpath, 1594 1250 .policy = nl80211_policy, 1595 1251 .flags = GENL_ADMIN_PERM, 1596 1252 },