* [PATCH 00/18] mac80211 802.11s networking code
@ 2008-02-23 14:17 Johannes Berg
2008-02-23 14:17 ` [PATCH 01/18] wireless: various definitions for mesh networking Johannes Berg
` (17 more replies)
0 siblings, 18 replies; 29+ messages in thread
From: Johannes Berg @ 2008-02-23 14:17 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless, Luis Carlos Cobo
This is a cleaned up version of Luis's 11s code which doesn't break
git bisect, compiles cleanly and ultimately has a lot less #ifdefs.
Let's merge this code and fix the remaining problems later.
Notably, this marks 11s as BROKEN because of endianness problems in it.
John, this applies after the following patches:
* mac80211: fix IBSS code
* mac80211: rework TX filtered frame code
* mac80211: atomically check whether STA exists already
* mac80211: fix debugfs_sta print_mac() warning
* mac80211: Disallow concurrent IBSS/STA mode interfaces
Please apply those first and then this set, I will respin my sta_info
rework on top of these patches (it needs bugfixes anyway.)
johannes
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH 01/18] wireless: various definitions for mesh networking
2008-02-23 14:17 [PATCH 00/18] mac80211 802.11s networking code Johannes Berg
@ 2008-02-23 14:17 ` Johannes Berg
2008-02-23 14:17 ` [PATCH 02/18] WEXT: add mesh interface type Johannes Berg
` (16 subsequent siblings)
17 siblings, 0 replies; 29+ messages in thread
From: Johannes Berg @ 2008-02-23 14:17 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless, Luis Carlos Cobo
From: Luis Carlos Cobo <luisca@cozybit.com>
Signed-off-by: Luis Carlos Cobo <luisca@cozybit.com>
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
include/linux/ieee80211.h | 35 +++++++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)
--- everything.orig/include/linux/ieee80211.h 2008-02-23 14:11:44.000000000 +0100
+++ everything/include/linux/ieee80211.h 2008-02-23 14:11:52.000000000 +0100
@@ -97,6 +97,7 @@
#define IEEE80211_MAX_FRAME_LEN 2352
#define IEEE80211_MAX_SSID_LEN 32
+#define IEEE80211_MAX_MESH_ID_LEN 32
struct ieee80211_hdr {
__le16 frame_control;
@@ -109,6 +110,16 @@ struct ieee80211_hdr {
} __attribute__ ((packed));
+struct ieee80211s_hdr {
+ u8 flags;
+ u8 ttl;
+ u8 seqnum[3];
+ u8 eaddr1[6];
+ u8 eaddr2[6];
+ u8 eaddr3[6];
+} __attribute__ ((packed));
+
+
struct ieee80211_mgmt {
__le16 frame_control;
__le16 duration;
@@ -206,6 +217,23 @@ struct ieee80211_mgmt {
__le16 params;
__le16 reason_code;
} __attribute__((packed)) delba;
+ struct{
+ u8 action_code;
+ /* capab_info for open and confirm,
+ * reason for close
+ */
+ __le16 aux;
+ /* Followed in plink_confirm by status
+ * code, AID and supported rates,
+ * and directly by supported rates in
+ * plink_open and plink_close
+ */
+ u8 variable[0];
+ } __attribute__((packed)) plink_action;
+ struct{
+ u8 action_code;
+ u8 variable[0];
+ } __attribute__((packed)) mesh_action;
} u;
} __attribute__ ((packed)) action;
} u;
@@ -437,6 +465,13 @@ enum ieee80211_eid {
WLAN_EID_TS_DELAY = 43,
WLAN_EID_TCLAS_PROCESSING = 44,
WLAN_EID_QOS_CAPA = 46,
+ /* 802.11s */
+ WLAN_EID_MESH_CONFIG = 36, /* Pending IEEE 802.11 ANA approval */
+ WLAN_EID_MESH_ID = 37, /* Pending IEEE 802.11 ANA approval */
+ WLAN_EID_PEER_LINK = 40, /* Pending IEEE 802.11 ANA approval */
+ WLAN_EID_PREQ = 53, /* Pending IEEE 802.11 ANA approval */
+ WLAN_EID_PREP = 54, /* Pending IEEE 802.11 ANA approval */
+ WLAN_EID_PERR = 55, /* Pending IEEE 802.11 ANA approval */
/* 802.11h */
WLAN_EID_PWR_CONSTRAINT = 32,
WLAN_EID_PWR_CAPABILITY = 33,
--
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH 02/18] WEXT: add mesh interface type
2008-02-23 14:17 [PATCH 00/18] mac80211 802.11s networking code Johannes Berg
2008-02-23 14:17 ` [PATCH 01/18] wireless: various definitions for mesh networking Johannes Berg
@ 2008-02-23 14:17 ` Johannes Berg
2008-02-23 14:17 ` [PATCH 03/18] nl80211/cfg80211: support for mesh, sta dumping Johannes Berg
` (15 subsequent siblings)
17 siblings, 0 replies; 29+ messages in thread
From: Johannes Berg @ 2008-02-23 14:17 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless, Luis Carlos Cobo
This introduces a new WEXT type IW_MODE_MESH for mesh networks,
used for scan results.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
include/linux/wireless.h | 1 +
1 file changed, 1 insertion(+)
--- everything.orig/include/linux/wireless.h 2008-02-23 14:14:14.000000000 +0100
+++ everything/include/linux/wireless.h 2008-02-23 14:14:26.000000000 +0100
@@ -455,6 +455,7 @@
#define IW_MODE_REPEAT 4 /* Wireless Repeater (forwarder) */
#define IW_MODE_SECOND 5 /* Secondary master/repeater (backup) */
#define IW_MODE_MONITOR 6 /* Passive monitor (listen only) */
+#define IW_MODE_MESH 7 /* Mesh (IEEE 802.11s) network */
/* Statistics flags (bitmask in updated) */
#define IW_QUAL_QUAL_UPDATED 0x01 /* Value was updated since last read */
--
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH 03/18] nl80211/cfg80211: support for mesh, sta dumping
2008-02-23 14:17 [PATCH 00/18] mac80211 802.11s networking code Johannes Berg
2008-02-23 14:17 ` [PATCH 01/18] wireless: various definitions for mesh networking Johannes Berg
2008-02-23 14:17 ` [PATCH 02/18] WEXT: add mesh interface type Johannes Berg
@ 2008-02-23 14:17 ` Johannes Berg
2008-02-23 14:17 ` [PATCH 04/18] mac80211: add mesh interface type Johannes Berg
` (14 subsequent siblings)
17 siblings, 0 replies; 29+ messages in thread
From: Johannes Berg @ 2008-02-23 14:17 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless, Luis Carlos Cobo
From: Luis Carlos Cobo <luisca@cozybit.com>
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>
---
include/linux/nl80211.h | 121 +++++++++++--
include/net/cfg80211.h | 141 +++++++++++++--
net/mac80211/cfg.c | 22 +-
net/wireless/nl80211.c | 436 +++++++++++++++++++++++++++++++++++++++++++++---
4 files changed, 652 insertions(+), 68 deletions(-)
--- everything.orig/include/linux/nl80211.h 2008-02-23 14:47:07.000000000 +0100
+++ everything/include/linux/nl80211.h 2008-02-23 14:47:16.000000000 +0100
@@ -78,6 +78,18 @@
* or, if no MAC address given, all stations, on the interface identified
* by %NL80211_ATTR_IFINDEX.
*
+ * @NL80211_CMD_GET_MPATH: Get mesh path attributes for mesh path to
+ * destination %NL80211_ATTR_MAC on the interface identified by
+ * %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_SET_MPATH: Set mesh path attributes for mesh path to
+ * destination %NL80211_ATTR_MAC on the interface identified by
+ * %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_NEW_PATH: Add a mesh path with given attributes to the
+ * the interface identified by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_DEL_PATH: Remove a mesh path identified by %NL80211_ATTR_MAC
+ * or, if no MAC address given, all mesh paths, on the interface identified
+ * by %NL80211_ATTR_IFINDEX.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -112,6 +124,11 @@ enum nl80211_commands {
/* add commands here */
+ NL80211_CMD_GET_MPATH,
+ NL80211_CMD_SET_MPATH,
+ NL80211_CMD_NEW_MPATH,
+ NL80211_CMD_DEL_MPATH,
+
/* used to define NL80211_CMD_MAX below */
__NL80211_CMD_AFTER_LAST,
NL80211_CMD_MAX = __NL80211_CMD_AFTER_LAST - 1
@@ -157,13 +174,21 @@ enum nl80211_commands {
* restriction (at most %NL80211_MAX_SUPP_RATES).
* @NL80211_ATTR_STA_VLAN: interface index of VLAN interface to move station
* to, or the AP interface the station was originally added to to.
- * @NL80211_ATTR_STA_STATS: statistics for a station, part of station info
+ * @NL80211_ATTR_STA_INFO: information about a station, part of station info
* given for %NL80211_CMD_GET_STATION, nested attribute containing
- * info as possible, see &enum nl80211_sta_stats.
+ * info as possible, see &enum nl80211_sta_info.
*
* @NL80211_ATTR_WIPHY_BANDS: Information about an operating bands,
* consisting of a nested array.
*
+ * @NL80211_ATTR_MESH_ID: mesh id (1-32 bytes).
+ * @NL80211_ATTR_PLINK_ACTION: action to perform on the mesh peer link.
+ * @NL80211_ATTR_MPATH_NEXT_HOP: MAC address of the next hop for a mesh path.
+ * @NL80211_ATTR_MPATH_INFO: information about a mesh_path, part of mesh path
+ * info given for %NL80211_CMD_GET_MPATH, nested attribute described at
+ * &enum nl80211_mpath_info.
+ *
+ *
* @NL80211_ATTR_MNTR_FLAGS: flags, nested element with NLA_FLAG attributes of
* &enum nl80211_mntr_flags.
*
@@ -199,7 +224,7 @@ enum nl80211_attrs {
NL80211_ATTR_STA_LISTEN_INTERVAL,
NL80211_ATTR_STA_SUPPORTED_RATES,
NL80211_ATTR_STA_VLAN,
- NL80211_ATTR_STA_STATS,
+ NL80211_ATTR_STA_INFO,
NL80211_ATTR_WIPHY_BANDS,
@@ -207,6 +232,11 @@ enum nl80211_attrs {
/* add attributes here, update the policy in nl80211.c */
+ NL80211_ATTR_MESH_ID,
+ NL80211_ATTR_STA_PLINK_ACTION,
+ NL80211_ATTR_MPATH_NEXT_HOP,
+ NL80211_ATTR_MPATH_INFO,
+
__NL80211_ATTR_AFTER_LAST,
NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1
};
@@ -223,6 +253,7 @@ enum nl80211_attrs {
* @NL80211_IFTYPE_AP_VLAN: VLAN interface for access points
* @NL80211_IFTYPE_WDS: wireless distribution interface
* @NL80211_IFTYPE_MONITOR: monitor interface receiving all frames
+ * @NL80211_IFTYPE_MESH_POINT: mesh point
* @NL80211_IFTYPE_MAX: highest interface type number currently defined
* @__NL80211_IFTYPE_AFTER_LAST: internal use
*
@@ -238,6 +269,7 @@ enum nl80211_iftype {
NL80211_IFTYPE_AP_VLAN,
NL80211_IFTYPE_WDS,
NL80211_IFTYPE_MONITOR,
+ NL80211_IFTYPE_MESH_POINT,
/* keep last */
__NL80211_IFTYPE_AFTER_LAST,
@@ -267,27 +299,78 @@ enum nl80211_sta_flags {
};
/**
- * enum nl80211_sta_stats - station statistics
+ * enum nl80211_sta_info - station information
*
- * These attribute types are used with %NL80211_ATTR_STA_STATS
+ * These attribute types are used with %NL80211_ATTR_STA_INFO
* when getting information about a station.
*
- * @__NL80211_STA_STAT_INVALID: attribute number 0 is reserved
- * @NL80211_STA_STAT_INACTIVE_TIME: time since last activity (u32, msecs)
- * @NL80211_STA_STAT_RX_BYTES: total received bytes (u32, from this station)
- * @NL80211_STA_STAT_TX_BYTES: total transmitted bytes (u32, to this station)
- * @__NL80211_STA_STAT_AFTER_LAST: internal
- * @NL80211_STA_STAT_MAX: highest possible station stats attribute
- */
-enum nl80211_sta_stats {
- __NL80211_STA_STAT_INVALID,
- NL80211_STA_STAT_INACTIVE_TIME,
- NL80211_STA_STAT_RX_BYTES,
- NL80211_STA_STAT_TX_BYTES,
+ * @__NL80211_STA_INFO_INVALID: attribute number 0 is reserved
+ * @NL80211_STA_INFO_INACTIVE_TIME: time since last activity (u32, msecs)
+ * @NL80211_STA_INFO_RX_BYTES: total received bytes (u32, from this station)
+ * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station)
+ * @__NL80211_STA_INFO_AFTER_LAST: internal
+ * @NL80211_STA_INFO_MAX: highest possible station info attribute
+ */
+enum nl80211_sta_info {
+ __NL80211_STA_INFO_INVALID,
+ NL80211_STA_INFO_INACTIVE_TIME,
+ NL80211_STA_INFO_RX_BYTES,
+ NL80211_STA_INFO_TX_BYTES,
+ NL80211_STA_INFO_LLID,
+ NL80211_STA_INFO_PLID,
+ NL80211_STA_INFO_PLINK_STATE,
+
+ /* keep last */
+ __NL80211_STA_INFO_AFTER_LAST,
+ NL80211_STA_INFO_MAX = __NL80211_STA_INFO_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_mpath_flags - nl80211 mesh path flags
+ *
+ * @NL80211_MPATH_FLAG_ACTIVE: the mesh path is active
+ * @NL80211_MPATH_FLAG_RESOLVING: the mesh path discovery process is running
+ * @NL80211_MPATH_FLAG_DSN_VALID: the mesh path contains a valid DSN
+ * @NL80211_MPATH_FLAG_FIXED: the mesh path has been manually set
+ * @NL80211_MPATH_FLAG_RESOLVED: the mesh path discovery process succeeded
+ */
+enum nl80211_mpath_flags {
+ NL80211_MPATH_FLAG_ACTIVE = 1<<0,
+ NL80211_MPATH_FLAG_RESOLVING = 1<<1,
+ NL80211_MPATH_FLAG_DSN_VALID = 1<<2,
+ NL80211_MPATH_FLAG_FIXED = 1<<3,
+ NL80211_MPATH_FLAG_RESOLVED = 1<<4,
+};
+
+/**
+ * enum nl80211_mpath_info - mesh path information
+ *
+ * These attribute types are used with %NL80211_ATTR_MPATH_INFO when getting
+ * information about a mesh path.
+ *
+ * @__NL80211_MPATH_INFO_INVALID: attribute number 0 is reserved
+ * @NL80211_ATTR_MPATH_FRAME_QLEN: number of queued frames for this destination
+ * @NL80211_ATTR_MPATH_DSN: destination sequence number
+ * @NL80211_ATTR_MPATH_METRIC: metric (cost) of this mesh path
+ * @NL80211_ATTR_MPATH_EXPTIME: expiration time for the path, in msec from now
+ * @NL80211_ATTR_MPATH_FLAGS: mesh path flags, enumerated in
+ * &enum nl80211_mpath_flags;
+ * @NL80211_ATTR_MPATH_DISCOVERY_TIMEOUT: total path discovery timeout, in msec
+ * @NL80211_ATTR_MPATH_DISCOVERY_RETRIES: mesh path discovery retries
+ */
+enum nl80211_mpath_info {
+ __NL80211_MPATH_INFO_INVALID,
+ NL80211_MPATH_INFO_FRAME_QLEN,
+ NL80211_MPATH_INFO_DSN,
+ NL80211_MPATH_INFO_METRIC,
+ NL80211_MPATH_INFO_EXPTIME,
+ NL80211_MPATH_INFO_FLAGS,
+ NL80211_MPATH_INFO_DISCOVERY_TIMEOUT,
+ NL80211_MPATH_INFO_DISCOVERY_RETRIES,
/* keep last */
- __NL80211_STA_STAT_AFTER_LAST,
- NL80211_STA_STAT_MAX = __NL80211_STA_STAT_AFTER_LAST - 1
+ __NL80211_MPATH_INFO_AFTER_LAST,
+ NL80211_MPATH_INFO_MAX = __NL80211_MPATH_INFO_AFTER_LAST - 1
};
/**
--- everything.orig/include/net/cfg80211.h 2008-02-23 14:47:07.000000000 +0100
+++ everything/include/net/cfg80211.h 2008-02-23 14:47:16.000000000 +0100
@@ -12,6 +12,16 @@
* Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net>
*/
+/**
+ * struct vif_params - describes virtual interface parameters
+ * @mesh_id: mesh ID to use
+ * @mesh_id_len: length of the mesh ID
+ */
+struct vif_params {
+ u8 *mesh_id;
+ int mesh_id_len;
+};
+
/* Radiotap header iteration
* implemented in net/wireless/radiotap.c
* docs in Documentation/networking/radiotap-headers.txt
@@ -109,6 +119,19 @@ enum station_flags {
};
/**
+ * enum plink_action - actions to perform in mesh peers
+ *
+ * @PLINK_ACTION_INVALID: action 0 is reserved
+ * @PLINK_ACTION_OPEN: start mesh peer link establishment
+ * @PLINK_ACTION_BLOCL: block traffic from this mesh peer
+ */
+enum plink_actions {
+ PLINK_ACTION_INVALID,
+ PLINK_ACTION_OPEN,
+ PLINK_ACTION_BLOCK,
+};
+
+/**
* struct station_parameters - station parameters
*
* Used to change and create a new station.
@@ -128,39 +151,52 @@ struct station_parameters {
int listen_interval;
u16 aid;
u8 supported_rates_len;
+ u8 plink_action;
};
/**
- * enum station_stats_flags - station statistics flags
+ * enum station_info_flags - station information flags
*
- * Used by the driver to indicate which info in &struct station_stats
- * it has filled in during get_station().
+ * Used by the driver to indicate which info in &struct station_info
+ * it has filled in during get_station() or dump_station().
*
- * @STATION_STAT_INACTIVE_TIME: @inactive_time filled
- * @STATION_STAT_RX_BYTES: @rx_bytes filled
- * @STATION_STAT_TX_BYTES: @tx_bytes filled
- */
-enum station_stats_flags {
- STATION_STAT_INACTIVE_TIME = 1<<0,
- STATION_STAT_RX_BYTES = 1<<1,
- STATION_STAT_TX_BYTES = 1<<2,
+ * @STATION_INFO_INACTIVE_TIME: @inactive_time filled
+ * @STATION_INFO_RX_BYTES: @rx_bytes filled
+ * @STATION_INFO_TX_BYTES: @tx_bytes filled
+ * @STATION_INFO_LLID: @llid filled
+ * @STATION_INFO_PLID: @plid filled
+ * @STATION_INFO_PLINK_STATE: @plink_state filled
+ */
+enum station_info_flags {
+ STATION_INFO_INACTIVE_TIME = 1<<0,
+ STATION_INFO_RX_BYTES = 1<<1,
+ STATION_INFO_TX_BYTES = 1<<2,
+ STATION_INFO_LLID = 1<<3,
+ STATION_INFO_PLID = 1<<4,
+ STATION_INFO_PLINK_STATE = 1<<5,
};
/**
- * struct station_stats - station statistics
+ * struct station_info - station information
*
- * Station information filled by driver for get_station().
+ * Station information filled by driver for get_station() and dump_station.
*
- * @filled: bitflag of flags from &enum station_stats_flags
+ * @filled: bitflag of flags from &enum station_info_flags
* @inactive_time: time since last station activity (tx/rx) in milliseconds
* @rx_bytes: bytes received from this station
* @tx_bytes: bytes transmitted to this station
+ * @llid: mesh local link id
+ * @plid: mesh peer link id
+ * @plink_state: mesh peer link state
*/
-struct station_stats {
+struct station_info {
u32 filled;
u32 inactive_time;
u32 rx_bytes;
u32 tx_bytes;
+ u16 llid;
+ u16 plid;
+ u8 plink_state;
};
/**
@@ -183,6 +219,56 @@ enum monitor_flags {
MONITOR_FLAG_COOK_FRAMES = 1<<NL80211_MNTR_FLAG_COOK_FRAMES,
};
+/**
+ * enum mpath_info_flags - mesh path information flags
+ *
+ * Used by the driver to indicate which info in &struct mpath_info it has filled
+ * in during get_station() or dump_station().
+ *
+ * MPATH_INFO_FRAME_QLEN: @frame_qlen filled
+ * MPATH_INFO_DSN: @dsn filled
+ * MPATH_INFO_METRIC: @metric filled
+ * MPATH_INFO_EXPTIME: @exptime filled
+ * MPATH_INFO_DISCOVERY_TIMEOUT: @discovery_timeout filled
+ * MPATH_INFO_DISCOVERY_RETRIES: @discovery_retries filled
+ * MPATH_INFO_FLAGS: @flags filled
+ */
+enum mpath_info_flags {
+ MPATH_INFO_FRAME_QLEN = BIT(0),
+ MPATH_INFO_DSN = BIT(1),
+ MPATH_INFO_METRIC = BIT(2),
+ MPATH_INFO_EXPTIME = BIT(3),
+ MPATH_INFO_DISCOVERY_TIMEOUT = BIT(4),
+ MPATH_INFO_DISCOVERY_RETRIES = BIT(5),
+ MPATH_INFO_FLAGS = BIT(6),
+};
+
+/**
+ * struct mpath_info - mesh path information
+ *
+ * Mesh path information filled by driver for get_mpath() and dump_mpath().
+ *
+ * @filled: bitfield of flags from &enum mpath_info_flags
+ * @frame_qlen: number of queued frames for this destination
+ * @dsn: destination sequence number
+ * @metric: metric (cost) of this mesh path
+ * @exptime: expiration time for the mesh path from now, in msecs
+ * @flags: mesh path flags
+ * @discovery_timeout: total mesh path discovery timeout, in msecs
+ * @discovery_retries: mesh path discovery retries
+ */
+struct mpath_info {
+ u32 filled;
+ u32 frame_qlen;
+ u32 dsn;
+ u32 metric;
+ u32 exptime;
+ u32 discovery_timeout;
+ u8 discovery_retries;
+ u8 flags;
+};
+
+
/* from net/wireless.h */
struct wiphy;
@@ -230,13 +316,17 @@ struct wiphy;
* @del_station: Remove a station; @mac may be NULL to remove all stations.
*
* @change_station: Modify a given station.
+ *
+ * @set_mesh_cfg: set mesh parameters (by now, just mesh id)
*/
struct cfg80211_ops {
int (*add_virtual_intf)(struct wiphy *wiphy, char *name,
- enum nl80211_iftype type, u32 *flags);
+ enum nl80211_iftype type, u32 *flags,
+ struct vif_params *params);
int (*del_virtual_intf)(struct wiphy *wiphy, int ifindex);
int (*change_virtual_intf)(struct wiphy *wiphy, int ifindex,
- enum nl80211_iftype type, u32 *flags);
+ enum nl80211_iftype type, u32 *flags,
+ struct vif_params *params);
int (*add_key)(struct wiphy *wiphy, struct net_device *netdev,
u8 key_index, u8 *mac_addr,
@@ -264,7 +354,22 @@ struct cfg80211_ops {
int (*change_station)(struct wiphy *wiphy, struct net_device *dev,
u8 *mac, struct station_parameters *params);
int (*get_station)(struct wiphy *wiphy, struct net_device *dev,
- u8 *mac, struct station_stats *stats);
+ u8 *mac, struct station_info *sinfo);
+ int (*dump_station)(struct wiphy *wiphy, struct net_device *dev,
+ int idx, u8 *mac, struct station_info *sinfo);
+
+ int (*add_mpath)(struct wiphy *wiphy, struct net_device *dev,
+ u8 *dst, u8 *next_hop);
+ int (*del_mpath)(struct wiphy *wiphy, struct net_device *dev,
+ u8 *dst);
+ int (*change_mpath)(struct wiphy *wiphy, struct net_device *dev,
+ u8 *dst, u8 *next_hop);
+ int (*get_mpath)(struct wiphy *wiphy, struct net_device *dev,
+ u8 *dst, u8 *next_hop,
+ struct mpath_info *pinfo);
+ int (*dump_mpath)(struct wiphy *wiphy, struct net_device *dev,
+ int idx, u8 *dst, u8 *next_hop,
+ struct mpath_info *pinfo);
};
#endif /* __NET_CFG80211_H */
--- everything.orig/net/wireless/nl80211.c 2008-02-23 14:47:07.000000000 +0100
+++ everything/net/wireless/nl80211.c 2008-02-23 14:47:27.000000000 +0100
@@ -81,8 +81,12 @@ static struct nla_policy nl80211_policy[
[NL80211_ATTR_STA_LISTEN_INTERVAL] = { .type = NLA_U16 },
[NL80211_ATTR_STA_SUPPORTED_RATES] = { .type = NLA_BINARY,
.len = NL80211_MAX_SUPP_RATES },
+ [NL80211_ATTR_STA_PLINK_ACTION] = { .type = NLA_U8 },
[NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 },
[NL80211_ATTR_MNTR_FLAGS] = { .type = NLA_NESTED },
+ [NL80211_ATTR_MESH_ID] = { .type = NLA_BINARY,
+ .len = IEEE80211_MAX_MESH_ID_LEN },
+ [NL80211_ATTR_MPATH_NEXT_HOP] = { .type = NLA_U32 },
};
/* message building helper */
@@ -369,11 +373,14 @@ static int parse_monitor_flags(struct nl
static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *drv;
+ struct vif_params params;
int err, ifindex;
enum nl80211_iftype type;
struct net_device *dev;
u32 flags;
+ memset(¶ms, 0, sizeof(params));
+
if (info->attrs[NL80211_ATTR_IFTYPE]) {
type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
if (type > NL80211_IFTYPE_MAX)
@@ -392,12 +399,18 @@ static int nl80211_set_interface(struct
goto unlock;
}
+ if (type == NL80211_IFTYPE_MESH_POINT &&
+ info->attrs[NL80211_ATTR_MESH_ID]) {
+ params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]);
+ params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
+ }
+
rtnl_lock();
err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
&flags);
err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex,
- type, err ? NULL : &flags);
+ type, err ? NULL : &flags, ¶ms);
rtnl_unlock();
unlock:
@@ -408,10 +421,13 @@ static int nl80211_set_interface(struct
static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *drv;
+ struct vif_params params;
int err;
enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
u32 flags;
+ memset(¶ms, 0, sizeof(params));
+
if (!info->attrs[NL80211_ATTR_IFNAME])
return -EINVAL;
@@ -430,15 +446,22 @@ static int nl80211_new_interface(struct
goto unlock;
}
+ if (type == NL80211_IFTYPE_MESH_POINT &&
+ info->attrs[NL80211_ATTR_MESH_ID]) {
+ params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]);
+ params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
+ }
+
rtnl_lock();
err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
&flags);
err = drv->ops->add_virtual_intf(&drv->wiphy,
nla_data(info->attrs[NL80211_ATTR_IFNAME]),
- type, err ? NULL : &flags);
+ type, err ? NULL : &flags, ¶ms);
rtnl_unlock();
+
unlock:
cfg80211_put_dev(drv);
return err;
@@ -866,10 +889,10 @@ static int parse_station_flags(struct nl
static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
int flags, struct net_device *dev,
- u8 *mac_addr, struct station_stats *stats)
+ u8 *mac_addr, struct station_info *sinfo)
{
void *hdr;
- struct nlattr *statsattr;
+ struct nlattr *sinfoattr;
hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION);
if (!hdr)
@@ -878,20 +901,29 @@ static int nl80211_send_station(struct s
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
- statsattr = nla_nest_start(msg, NL80211_ATTR_STA_STATS);
- if (!statsattr)
+ sinfoattr = nla_nest_start(msg, NL80211_ATTR_STA_INFO);
+ if (!sinfoattr)
goto nla_put_failure;
- if (stats->filled & STATION_STAT_INACTIVE_TIME)
- NLA_PUT_U32(msg, NL80211_STA_STAT_INACTIVE_TIME,
- stats->inactive_time);
- if (stats->filled & STATION_STAT_RX_BYTES)
- NLA_PUT_U32(msg, NL80211_STA_STAT_RX_BYTES,
- stats->rx_bytes);
- if (stats->filled & STATION_STAT_TX_BYTES)
- NLA_PUT_U32(msg, NL80211_STA_STAT_TX_BYTES,
- stats->tx_bytes);
+ if (sinfo->filled & STATION_INFO_INACTIVE_TIME)
+ NLA_PUT_U32(msg, NL80211_STA_INFO_INACTIVE_TIME,
+ sinfo->inactive_time);
+ if (sinfo->filled & STATION_INFO_RX_BYTES)
+ NLA_PUT_U32(msg, NL80211_STA_INFO_RX_BYTES,
+ sinfo->rx_bytes);
+ if (sinfo->filled & STATION_INFO_TX_BYTES)
+ NLA_PUT_U32(msg, NL80211_STA_INFO_TX_BYTES,
+ sinfo->tx_bytes);
+ if (sinfo->filled & STATION_INFO_LLID)
+ NLA_PUT_U16(msg, NL80211_STA_INFO_LLID,
+ sinfo->llid);
+ if (sinfo->filled & STATION_INFO_PLID)
+ NLA_PUT_U16(msg, NL80211_STA_INFO_PLID,
+ sinfo->plid);
+ if (sinfo->filled & STATION_INFO_PLINK_STATE)
+ NLA_PUT_U8(msg, NL80211_STA_INFO_PLINK_STATE,
+ sinfo->plink_state);
- nla_nest_end(msg, statsattr);
+ nla_nest_end(msg, sinfoattr);
return genlmsg_end(msg, hdr);
@@ -899,17 +931,80 @@ static int nl80211_send_station(struct s
return genlmsg_cancel(msg, hdr);
}
+static int nl80211_dump_station(struct sk_buff *skb,
+ struct netlink_callback *cb)
+{
+ int wp_idx = 0;
+ int if_idx = 0;
+ int sta_idx = cb->args[2];
+ int wp_start = cb->args[0];
+ int if_start = cb->args[1];
+ struct station_info sinfo;
+ struct cfg80211_registered_device *dev;
+ struct wireless_dev *wdev;
+ u8 mac_addr[ETH_ALEN];
+ int err;
+ int exit = 0;
+
+ /* TODO: filter by device */
+ mutex_lock(&cfg80211_drv_mutex);
+ list_for_each_entry(dev, &cfg80211_drv_list, list) {
+ if (exit)
+ break;
+ if (++wp_idx < wp_start)
+ continue;
+ if_idx = 0;
+
+ mutex_lock(&dev->devlist_mtx);
+ list_for_each_entry(wdev, &dev->netdev_list, list) {
+ if (exit)
+ break;
+ if (++if_idx < if_start)
+ continue;
+ if (!dev->ops->dump_station)
+ continue;
+
+ for (;; ++sta_idx) {
+ rtnl_lock();
+ err = dev->ops->dump_station(&dev->wiphy,
+ wdev->netdev, sta_idx, mac_addr,
+ &sinfo);
+ rtnl_unlock();
+ if (err) {
+ sta_idx = 0;
+ break;
+ }
+ if (nl80211_send_station(skb,
+ NETLINK_CB(cb->skb).pid,
+ cb->nlh->nlmsg_seq, NLM_F_MULTI,
+ wdev->netdev, mac_addr,
+ &sinfo) < 0) {
+ exit = 1;
+ break;
+ }
+ }
+ }
+ mutex_unlock(&dev->devlist_mtx);
+ }
+ mutex_unlock(&cfg80211_drv_mutex);
+
+ cb->args[0] = wp_idx;
+ cb->args[1] = if_idx;
+ cb->args[2] = sta_idx;
+
+ return skb->len;
+}
static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *drv;
int err;
struct net_device *dev;
- struct station_stats stats;
+ struct station_info sinfo;
struct sk_buff *msg;
u8 *mac_addr = NULL;
- memset(&stats, 0, sizeof(stats));
+ memset(&sinfo, 0, sizeof(sinfo));
if (!info->attrs[NL80211_ATTR_MAC])
return -EINVAL;
@@ -926,15 +1021,18 @@ static int nl80211_get_station(struct sk
}
rtnl_lock();
- err = drv->ops->get_station(&drv->wiphy, dev, mac_addr, &stats);
+ err = drv->ops->get_station(&drv->wiphy, dev, mac_addr, &sinfo);
rtnl_unlock();
+ if (err)
+ goto out;
+
msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
if (!msg)
goto out;
if (nl80211_send_station(msg, info->snd_pid, info->snd_seq, 0,
- dev, mac_addr, &stats) < 0)
+ dev, mac_addr, &sinfo) < 0)
goto out_free;
err = genlmsg_unicast(msg, info->snd_pid);
@@ -1005,6 +1103,10 @@ static int nl80211_set_station(struct sk
¶ms.station_flags))
return -EINVAL;
+ if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION])
+ params.plink_action =
+ nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
+
err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
if (err)
return err;
@@ -1119,6 +1221,273 @@ static int nl80211_del_station(struct sk
return err;
}
+static int nl80211_send_mpath(struct sk_buff *msg, u32 pid, u32 seq,
+ int flags, struct net_device *dev,
+ u8 *dst, u8 *next_hop,
+ struct mpath_info *pinfo)
+{
+ void *hdr;
+ struct nlattr *pinfoattr;
+
+ hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION);
+ if (!hdr)
+ return -1;
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst);
+ NLA_PUT(msg, NL80211_ATTR_MPATH_NEXT_HOP, ETH_ALEN, next_hop);
+
+ pinfoattr = nla_nest_start(msg, NL80211_ATTR_MPATH_INFO);
+ if (!pinfoattr)
+ goto nla_put_failure;
+ if (pinfo->filled & MPATH_INFO_FRAME_QLEN)
+ NLA_PUT_U32(msg, NL80211_MPATH_INFO_FRAME_QLEN,
+ pinfo->frame_qlen);
+ if (pinfo->filled & MPATH_INFO_DSN)
+ NLA_PUT_U32(msg, NL80211_MPATH_INFO_DSN,
+ pinfo->dsn);
+ if (pinfo->filled & MPATH_INFO_METRIC)
+ NLA_PUT_U32(msg, NL80211_MPATH_INFO_METRIC,
+ pinfo->metric);
+ if (pinfo->filled & MPATH_INFO_EXPTIME)
+ NLA_PUT_U32(msg, NL80211_MPATH_INFO_EXPTIME,
+ pinfo->exptime);
+ if (pinfo->filled & MPATH_INFO_FLAGS)
+ NLA_PUT_U8(msg, NL80211_MPATH_INFO_FLAGS,
+ pinfo->flags);
+ if (pinfo->filled & MPATH_INFO_DISCOVERY_TIMEOUT)
+ NLA_PUT_U32(msg, NL80211_MPATH_INFO_DISCOVERY_TIMEOUT,
+ pinfo->discovery_timeout);
+ if (pinfo->filled & MPATH_INFO_DISCOVERY_RETRIES)
+ NLA_PUT_U8(msg, NL80211_MPATH_INFO_DISCOVERY_RETRIES,
+ pinfo->discovery_retries);
+
+ nla_nest_end(msg, pinfoattr);
+
+ return genlmsg_end(msg, hdr);
+
+ nla_put_failure:
+ return genlmsg_cancel(msg, hdr);
+}
+
+static int nl80211_dump_mpath(struct sk_buff *skb,
+ struct netlink_callback *cb)
+{
+ int wp_idx = 0;
+ int if_idx = 0;
+ int sta_idx = cb->args[2];
+ int wp_start = cb->args[0];
+ int if_start = cb->args[1];
+ struct mpath_info pinfo;
+ struct cfg80211_registered_device *dev;
+ struct wireless_dev *wdev;
+ u8 dst[ETH_ALEN];
+ u8 next_hop[ETH_ALEN];
+ int err;
+ int exit = 0;
+
+ /* TODO: filter by device */
+ mutex_lock(&cfg80211_drv_mutex);
+ list_for_each_entry(dev, &cfg80211_drv_list, list) {
+ if (exit)
+ break;
+ if (++wp_idx < wp_start)
+ continue;
+ if_idx = 0;
+
+ mutex_lock(&dev->devlist_mtx);
+ list_for_each_entry(wdev, &dev->netdev_list, list) {
+ if (exit)
+ break;
+ if (++if_idx < if_start)
+ continue;
+ if (!dev->ops->dump_mpath)
+ continue;
+
+ for (;; ++sta_idx) {
+ rtnl_lock();
+ err = dev->ops->dump_mpath(&dev->wiphy,
+ wdev->netdev, sta_idx, dst,
+ next_hop, &pinfo);
+ rtnl_unlock();
+ if (err) {
+ sta_idx = 0;
+ break;
+ }
+ if (nl80211_send_mpath(skb,
+ NETLINK_CB(cb->skb).pid,
+ cb->nlh->nlmsg_seq, NLM_F_MULTI,
+ wdev->netdev, dst, next_hop,
+ &pinfo) < 0) {
+ exit = 1;
+ break;
+ }
+ }
+ }
+ mutex_unlock(&dev->devlist_mtx);
+ }
+ mutex_unlock(&cfg80211_drv_mutex);
+
+ cb->args[0] = wp_idx;
+ cb->args[1] = if_idx;
+ cb->args[2] = sta_idx;
+
+ return skb->len;
+}
+
+static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *drv;
+ int err;
+ struct net_device *dev;
+ struct mpath_info pinfo;
+ struct sk_buff *msg;
+ u8 *dst = NULL;
+ u8 next_hop[ETH_ALEN];
+
+ memset(&pinfo, 0, sizeof(pinfo));
+
+ if (!info->attrs[NL80211_ATTR_MAC])
+ return -EINVAL;
+
+ dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+ err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+ if (err)
+ return err;
+
+ if (!drv->ops->get_mpath) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ rtnl_lock();
+ err = drv->ops->get_mpath(&drv->wiphy, dev, dst, next_hop, &pinfo);
+ rtnl_unlock();
+
+ if (err)
+ goto out;
+
+ msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+ if (!msg)
+ goto out;
+
+ if (nl80211_send_mpath(msg, info->snd_pid, info->snd_seq, 0,
+ dev, dst, next_hop, &pinfo) < 0)
+ goto out_free;
+
+ err = genlmsg_unicast(msg, info->snd_pid);
+ goto out;
+
+ out_free:
+ nlmsg_free(msg);
+
+ out:
+ cfg80211_put_dev(drv);
+ dev_put(dev);
+ return err;
+}
+
+static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *drv;
+ int err;
+ struct net_device *dev;
+ u8 *dst = NULL;
+ u8 *next_hop = NULL;
+
+ if (!info->attrs[NL80211_ATTR_MAC])
+ return -EINVAL;
+
+ if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP])
+ return -EINVAL;
+
+ dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
+ next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]);
+
+ err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+ if (err)
+ return err;
+
+ if (!drv->ops->change_mpath) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ rtnl_lock();
+ err = drv->ops->change_mpath(&drv->wiphy, dev, dst, next_hop);
+ rtnl_unlock();
+
+ out:
+ cfg80211_put_dev(drv);
+ dev_put(dev);
+ return err;
+}
+static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *drv;
+ int err;
+ struct net_device *dev;
+ u8 *dst = NULL;
+ u8 *next_hop = NULL;
+
+ if (!info->attrs[NL80211_ATTR_MAC])
+ return -EINVAL;
+
+ if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP])
+ return -EINVAL;
+
+ dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
+ next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]);
+
+ err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+ if (err)
+ return err;
+
+ if (!drv->ops->add_mpath) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ rtnl_lock();
+ err = drv->ops->add_mpath(&drv->wiphy, dev, dst, next_hop);
+ rtnl_unlock();
+
+ out:
+ cfg80211_put_dev(drv);
+ dev_put(dev);
+ return err;
+}
+
+static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *drv;
+ int err;
+ struct net_device *dev;
+ u8 *dst = NULL;
+
+ if (info->attrs[NL80211_ATTR_MAC])
+ dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+ err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+ if (err)
+ return err;
+
+ if (!drv->ops->del_mpath) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ rtnl_lock();
+ err = drv->ops->del_mpath(&drv->wiphy, dev, dst);
+ rtnl_unlock();
+
+ out:
+ cfg80211_put_dev(drv);
+ dev_put(dev);
+ return err;
+}
+
static struct genl_ops nl80211_ops[] = {
{
.cmd = NL80211_CMD_GET_WIPHY,
@@ -1203,7 +1572,7 @@ static struct genl_ops nl80211_ops[] = {
{
.cmd = NL80211_CMD_GET_STATION,
.doit = nl80211_get_station,
- /* TODO: implement dumpit */
+ .dumpit = nl80211_dump_station,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
},
@@ -1225,6 +1594,31 @@ static struct genl_ops nl80211_ops[] = {
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
},
+ {
+ .cmd = NL80211_CMD_GET_MPATH,
+ .doit = nl80211_get_mpath,
+ .dumpit = nl80211_dump_mpath,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
+ {
+ .cmd = NL80211_CMD_SET_MPATH,
+ .doit = nl80211_set_mpath,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
+ {
+ .cmd = NL80211_CMD_NEW_MPATH,
+ .doit = nl80211_new_mpath,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
+ {
+ .cmd = NL80211_CMD_DEL_MPATH,
+ .doit = nl80211_del_mpath,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
};
/* multicast groups */
--- everything.orig/net/mac80211/cfg.c 2008-02-23 14:47:07.000000000 +0100
+++ everything/net/mac80211/cfg.c 2008-02-23 14:47:16.000000000 +0100
@@ -34,7 +34,8 @@ nl80211_type_to_mac80211_type(enum nl802
}
static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
- enum nl80211_iftype type, u32 *flags)
+ enum nl80211_iftype type, u32 *flags,
+ struct vif_params *params)
{
struct ieee80211_local *local = wiphy_priv(wiphy);
enum ieee80211_if_types itype;
@@ -78,7 +79,8 @@ static int ieee80211_del_iface(struct wi
}
static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex,
- enum nl80211_iftype type, u32 *flags)
+ enum nl80211_iftype type, u32 *flags,
+ struct vif_params *params)
{
struct ieee80211_local *local = wiphy_priv(wiphy);
struct net_device *dev;
@@ -285,7 +287,7 @@ static int ieee80211_config_default_key(
}
static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
- u8 *mac, struct station_stats *stats)
+ u8 *mac, struct station_info *sinfo)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct sta_info *sta;
@@ -296,13 +298,13 @@ static int ieee80211_get_station(struct
/* XXX: verify sta->dev == dev */
- stats->filled = STATION_STAT_INACTIVE_TIME |
- STATION_STAT_RX_BYTES |
- STATION_STAT_TX_BYTES;
-
- stats->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx);
- stats->rx_bytes = sta->rx_bytes;
- stats->tx_bytes = sta->tx_bytes;
+ sinfo->filled = STATION_INFO_INACTIVE_TIME |
+ STATION_INFO_RX_BYTES |
+ STATION_INFO_TX_BYTES;
+
+ sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx);
+ sinfo->rx_bytes = sta->rx_bytes;
+ sinfo->tx_bytes = sta->tx_bytes;
sta_info_put(sta);
--
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH 04/18] mac80211: add mesh interface type
2008-02-23 14:17 [PATCH 00/18] mac80211 802.11s networking code Johannes Berg
` (2 preceding siblings ...)
2008-02-23 14:17 ` [PATCH 03/18] nl80211/cfg80211: support for mesh, sta dumping Johannes Berg
@ 2008-02-23 14:17 ` Johannes Berg
2008-02-23 14:17 ` [PATCH 05/18] mac80211: mesh function and data structures definitions Johannes Berg
` (13 subsequent siblings)
17 siblings, 0 replies; 29+ messages in thread
From: Johannes Berg @ 2008-02-23 14:17 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless, Luis Carlos Cobo
This adds the mesh interface type.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
include/net/mac80211.h | 1 +
net/mac80211/ieee80211.c | 1 +
net/mac80211/ieee80211_iface.c | 1 +
net/mac80211/rx.c | 10 ++++++++++
net/mac80211/util.c | 1 +
5 files changed, 14 insertions(+)
--- everything.orig/include/net/mac80211.h 2008-02-23 14:23:35.000000000 +0100
+++ everything/include/net/mac80211.h 2008-02-23 14:23:36.000000000 +0100
@@ -439,6 +439,7 @@ enum ieee80211_if_types {
IEEE80211_IF_TYPE_AP,
IEEE80211_IF_TYPE_STA,
IEEE80211_IF_TYPE_IBSS,
+ IEEE80211_IF_TYPE_MESH_POINT,
IEEE80211_IF_TYPE_MNTR,
IEEE80211_IF_TYPE_WDS,
IEEE80211_IF_TYPE_VLAN,
--- everything.orig/net/mac80211/ieee80211.c 2008-02-23 14:23:35.000000000 +0100
+++ everything/net/mac80211/ieee80211.c 2008-02-23 14:23:36.000000000 +0100
@@ -258,6 +258,7 @@ static int ieee80211_open(struct net_dev
case IEEE80211_IF_TYPE_STA:
case IEEE80211_IF_TYPE_MNTR:
case IEEE80211_IF_TYPE_IBSS:
+ case IEEE80211_IF_TYPE_MESH_POINT:
/* no special treatment */
break;
case IEEE80211_IF_TYPE_INVALID:
--- everything.orig/net/mac80211/ieee80211_iface.c 2008-02-23 14:23:35.000000000 +0100
+++ everything/net/mac80211/ieee80211_iface.c 2008-02-23 14:23:36.000000000 +0100
@@ -231,6 +231,7 @@ void ieee80211_if_reinit(struct net_devi
#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
}
break;
+ case IEEE80211_IF_TYPE_MESH_POINT:
case IEEE80211_IF_TYPE_STA:
case IEEE80211_IF_TYPE_IBSS:
kfree(sdata->u.sta.extra_ie);
--- everything.orig/net/mac80211/rx.c 2008-02-23 14:23:35.000000000 +0100
+++ everything/net/mac80211/rx.c 2008-02-23 14:23:36.000000000 +0100
@@ -1713,6 +1713,16 @@ static int prepare_for_handlers(struct i
rx->sta = ieee80211_ibss_add_sta(sdata->dev, rx->skb,
bssid, hdr->addr2);
break;
+ case IEEE80211_IF_TYPE_MESH_POINT:
+ if (!multicast &&
+ compare_ether_addr(sdata->dev->dev_addr,
+ hdr->addr1) != 0) {
+ if (!(sdata->dev->flags & IFF_PROMISC))
+ return 0;
+
+ rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH;
+ }
+ break;
case IEEE80211_IF_TYPE_VLAN:
case IEEE80211_IF_TYPE_AP:
if (!bssid) {
--- everything.orig/net/mac80211/util.c 2008-02-23 14:23:35.000000000 +0100
+++ everything/net/mac80211/util.c 2008-02-23 14:23:36.000000000 +0100
@@ -382,6 +382,7 @@ void ieee80211_iterate_active_interfaces
case IEEE80211_IF_TYPE_STA:
case IEEE80211_IF_TYPE_IBSS:
case IEEE80211_IF_TYPE_WDS:
+ case IEEE80211_IF_TYPE_MESH_POINT:
break;
}
if (sdata->dev == local->mdev)
--
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH 05/18] mac80211: mesh function and data structures definitions
2008-02-23 14:17 [PATCH 00/18] mac80211 802.11s networking code Johannes Berg
` (3 preceding siblings ...)
2008-02-23 14:17 ` [PATCH 04/18] mac80211: add mesh interface type Johannes Berg
@ 2008-02-23 14:17 ` Johannes Berg
2008-02-23 14:17 ` [PATCH 06/18] mac80211: support functions for mesh Johannes Berg
` (12 subsequent siblings)
17 siblings, 0 replies; 29+ messages in thread
From: Johannes Berg @ 2008-02-23 14:17 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless, Luis Carlos Cobo
From: Luis Carlos Cobo <luisca@cozybit.com>
Signed-off-by: Luis Carlos Cobo <luisca@cozybit.com>
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
net/mac80211/mesh.h | 283 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 283 insertions(+)
create mode 100644 net/mac80211/mesh.h
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ everything/net/mac80211/mesh.h 2008-02-23 14:19:13.000000000 +0100
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 2008 open80211s Ltd.
+ * Authors: Luis Carlos Cobo <luisca@cozybit.com>
+ * Javier Cardona <javier@cozybit.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef IEEE80211S_H
+#define IEEE80211S_H
+
+#include "ieee80211_i.h"
+#include <linux/jhash.h>
+
+extern int mesh_allocated;
+
+/* Data structures */
+
+/**
+ * enum mesh_path_flags - mac80211 mesh path flags
+ *
+ *
+ *
+ * @MESH_PATH_ACTIVE: the mesh path is can be used for forwarding
+ * @MESH_PATH_RESOLVED: the discovery process is running for this mesh path
+ * @MESH_PATH_DSN_VALID: the mesh path contains a valid destination sequence
+ * number
+ * @MESH_PATH_FIXED: the mesh path has been manually set and should not be
+ * modified
+ * @MESH_PATH_RESOLVED: the mesh path can has been resolved
+ * @MESH_PATH_DELETE: the mesh path is scheduled to be deleted
+ *
+ * MESH_PATH_RESOLVED and MESH_PATH_DELETE are used by the mesh path timer to
+ * decide when to stop or cancel the mesh path discovery.
+ */
+enum mesh_path_flags {
+ MESH_PATH_ACTIVE = BIT(0),
+ MESH_PATH_RESOLVING = BIT(1),
+ MESH_PATH_DSN_VALID = BIT(2),
+ MESH_PATH_FIXED = BIT(3),
+ MESH_PATH_RESOLVED = BIT(4),
+ MESH_PATH_DELETE = BIT(5),
+};
+
+/**
+ * struct mesh_path - mac80211 mesh path structure
+ *
+ * @dst: mesh path destination mac address
+ * @dev: mesh path device
+ * @next_hop: mesh neighbor to which frames for this destination will be
+ * forwarded
+ * @timer: mesh path discovery timer
+ * @frame_queue: pending queue for frames sent to this destination while the
+ * path is unresolved
+ * @dsn: destination sequence number of the destination
+ * @metric: current metric to this destination
+ * @hop_count: hops to destination
+ * @exp_time: in jiffies, when the path will expire or when it expired
+ * @discovery_timeout: timeout (lapse in jiffies) used for the last discovery
+ * retry
+ * @discovery_retries: number of discovery retries
+ * @flags: mesh path flags, as specified on &enum mesh_path_flags
+ * @state_lock: mesh pat state lock
+ *
+ *
+ * The combination of dst and dev is unique in the mesh path table. A reference
+ * to the next_hop sta will be kept and in case this sta is removed, the
+ * mesh_path structure must be also removed or substitued in a rcu safe way
+ */
+struct mesh_path {
+ u8 dst[ETH_ALEN];
+ struct net_device *dev;
+ struct sta_info *next_hop;
+ struct timer_list timer;
+ struct sk_buff_head frame_queue;
+ struct rcu_head rcu;
+ u32 dsn;
+ u32 metric;
+ u8 hop_count;
+ unsigned long exp_time;
+ u32 discovery_timeout;
+ u8 discovery_retries;
+ enum mesh_path_flags flags;
+ spinlock_t state_lock;
+};
+
+/**
+ * struct mesh_table
+ *
+ * @hash_buckets: array of hash buckets of the table
+ * @hashwlock: array of locks to protect write operations, one per bucket
+ * @hash_mask: 2^size_order - 1, used to compute hash idx
+ * @hash_rnd: random value used for hash computations
+ * @entries: number of entries in the table
+ * @free_node: function to free nodes of the table
+ * @copy_node: fuction to copy nodes of the table
+ * @size_order: determines size of the table, there will be 2^size_order hash
+ * buckets
+ * @mean_chain_len: maximum average length for the hash buckets' list, if it is
+ * reached, the table will grow
+ */
+struct mesh_table {
+ /* Number of buckets will be 2^N */
+ struct hlist_head *hash_buckets;
+ spinlock_t *hashwlock; /* One per bucket, for add/del */
+ unsigned int hash_mask; /* (2^size_order) - 1 */
+ __u32 hash_rnd; /* Used for hash generation */
+ atomic_t entries; /* Up to MAX_MESH_NEIGHBOURS */
+ void (*free_node) (struct hlist_node *p, bool free_leafs);
+ void (*copy_node) (struct hlist_node *p, struct mesh_table *newtbl);
+ int size_order;
+ int mean_chain_len;
+};
+
+/* Recent multicast cache */
+/* RMC_BUCKETS must be a power of 2, maximum 256 */
+#define RMC_BUCKETS 256
+#define RMC_QUEUE_MAX_LEN 4
+#define RMC_TIMEOUT (3 * HZ)
+
+/**
+ * struct rmc_entry - entry in the Recent Multicast Cache
+ *
+ * @seqnum: mesh sequence number of the frame
+ * @exp_time: expiration time of the entry, in jiffies
+ * @sa: source address of the frame
+ *
+ * The Recent Multicast Cache keeps track of the latest multicast frames that
+ * have been received by a mesh interface and discards received multicast frames
+ * that are found in the cache.
+ */
+struct rmc_entry {
+ struct list_head list;
+ u32 seqnum;
+ unsigned long exp_time;
+ u8 sa[ETH_ALEN];
+};
+
+struct mesh_rmc {
+ struct rmc_entry bucket[RMC_BUCKETS];
+ u8 idx_mask;
+};
+
+
+/* Mesh IEs constants */
+#define MESH_CFG_LEN 19
+
+/*
+ * MESH_CFG_COMP_LEN Includes:
+ * - Active path selection protocol ID.
+ * - Active path selection metric ID.
+ * - Congestion control mode identifier.
+ * - Channel precedence.
+ * Does not include mesh capabilities, which may vary across nodes in the same
+ * mesh
+ */
+#define MESH_CFG_CMP_LEN 17
+
+/* Default values, timeouts in ms */
+#define MESH_TTL 5
+#define MESH_MAX_RETR 3
+#define MESH_RET_T 100
+#define MESH_CONF_T 100
+#define MESH_HOLD_T 100
+
+#define MESH_PATH_TIMEOUT 5000
+/* Minimum interval between two consecutive PREQs originated by the same
+ * interface
+ */
+#define MESH_PREQ_MIN_INT 10
+#define MESH_DIAM_TRAVERSAL_TIME 50
+/* Paths will be refreshed if they are closer than PATH_REFRESH_TIME to their
+ * expiration
+ */
+#define MESH_PATH_REFRESH_TIME 1000
+#define MESH_MIN_DISCOVERY_TIMEOUT (2 * MESH_DIAM_TRAVERSAL_TIME)
+
+#define MESH_MAX_PREQ_RETRIES 4
+#define MESH_PATH_EXPIRE (600 * HZ)
+
+/* Default maximum number of established plinks per interface */
+#define MESH_MAX_ESTAB_PLINKS 32
+
+/* Default maximum number of plinks per interface */
+#define MESH_MAX_PLINKS 256
+
+/* Maximum number of paths per interface */
+#define MESH_MAX_MPATHS 1024
+
+/* Pending ANA approval */
+#define PLINK_CATEGORY 30
+#define MESH_PATH_SEL_CATEGORY 32
+
+/* Mesh Header Flags */
+#define IEEE80211S_FLAGS_AE 0x3
+
+/* Public interfaces */
+/* Various */
+u8 mesh_id_hash(u8 *mesh_id, int mesh_id_len);
+int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr);
+int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr,
+ struct ieee80211_sub_if_data *sdata);
+int mesh_rmc_check(u8 *addr, struct ieee80211s_hdr *mesh_hdr,
+ struct net_device *dev);
+bool mesh_matches_local(struct ieee802_11_elems *ie, struct net_device *dev);
+void mesh_ids_set_default(struct ieee80211_if_sta *sta);
+void mesh_mgmt_ies_add(struct sk_buff *skb, struct net_device *dev);
+void mesh_rmc_free(struct net_device *dev);
+int mesh_rmc_init(struct net_device *dev);
+void ieee80211s_init(void);
+void ieee80211s_stop(void);
+/* Mesh paths */
+int mesh_nexthop_lookup(u8 *next_hop, struct sk_buff *skb,
+ struct net_device *dev);
+void mesh_path_start_discovery(struct net_device *dev);
+struct mesh_path *mesh_path_lookup(u8 *dst, struct net_device *dev);
+struct mesh_path *mesh_path_lookup_by_idx(int idx, struct net_device *dev);
+void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop);
+void mesh_path_expire(struct net_device *dev);
+void mesh_path_flush(struct net_device *dev);
+void mesh_rx_path_sel_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
+ size_t len);
+int mesh_path_add(u8 *dst, struct net_device *dev);
+/* Mesh plinks */
+void mesh_neighbour_update(u8 *hw_addr, u64 rates, struct net_device *dev,
+ bool add);
+bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie,
+ struct net_device *dev);
+void mesh_accept_plinks_update(struct net_device *dev);
+struct sta_info *mesh_plink_add(u8 *hw_addr, u64 rates, struct net_device *dev);
+void mesh_plink_broken(struct sta_info *sta);
+void mesh_plink_deactivate(struct sta_info *sta);
+int mesh_plink_open(struct sta_info *sta);
+int mesh_plink_close(struct sta_info *sta);
+void mesh_plink_block(struct sta_info *sta);
+void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
+ size_t len, struct ieee80211_rx_status *rx_status);
+
+/* Private interfaces */
+/* Mesh tables */
+struct mesh_table *mesh_table_alloc(int size_order);
+void mesh_table_free(struct mesh_table *tbl, bool free_leafs);
+struct mesh_table *mesh_table_grow(struct mesh_table *tbl);
+u32 mesh_table_hash(u8 *addr, struct net_device *dev, struct mesh_table *tbl);
+/* Mesh paths */
+int mesh_path_error_tx(u8 *dest, __le32 dest_dsn, u8 *ra,
+ struct net_device *dev);
+void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta);
+void mesh_path_flush_pending(struct mesh_path *mpath);
+void mesh_path_tx_pending(struct mesh_path *mpath);
+int mesh_pathtbl_init(void);
+void mesh_pathtbl_unregister(void);
+int mesh_path_del(u8 *addr, struct net_device *dev);
+void mesh_path_timer(unsigned long data);
+void mesh_path_flush_by_nexthop(struct sta_info *sta);
+void mesh_path_discard_frame(struct sk_buff *skb, struct net_device *dev);
+
+static inline int mesh_plink_free_count(struct ieee80211_sub_if_data *sdata)
+{
+ return sdata->u.sta.mshcfg.dot11MeshMaxPeerLinks -
+ atomic_read(&sdata->u.sta.mshstats.estab_plinks);
+}
+
+static inline bool mesh_plink_availables(struct ieee80211_sub_if_data *sdata)
+{
+ return (min(mesh_plink_free_count(sdata),
+ MESH_MAX_PLINKS - sdata->local->num_sta)) > 0;
+}
+
+static inline void mesh_path_activate(struct mesh_path *mpath)
+{
+ mpath->flags |= MESH_PATH_ACTIVE | MESH_PATH_RESOLVED;
+}
+
+#define for_each_mesh_entry(x, p, node, i) \
+ for (i = 0; i <= x->hash_mask; i++) \
+ hlist_for_each_entry_rcu(node, p, &x->hash_buckets[i], list)
+
+#define MESH_PREQ(skb) (skb->cb + 30)
+
+#endif /* IEEE80211S_H */
--
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH 06/18] mac80211: support functions for mesh
2008-02-23 14:17 [PATCH 00/18] mac80211 802.11s networking code Johannes Berg
` (4 preceding siblings ...)
2008-02-23 14:17 ` [PATCH 05/18] mac80211: mesh function and data structures definitions Johannes Berg
@ 2008-02-23 14:17 ` Johannes Berg
2008-02-23 14:17 ` [PATCH 07/18] mac80211: support for mesh interfaces in mac80211 data path Johannes Berg
` (11 subsequent siblings)
17 siblings, 0 replies; 29+ messages in thread
From: Johannes Berg @ 2008-02-23 14:17 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless, Luis Carlos Cobo
From: Luis Carlos Cobo <luisca@cozybit.com>
The two important features coded in mesh.c are:
Recently Multicast Cache: in on-demand HWMP, multicast traffic is retransmitted
by every receiving node. Even though a mesh TTL counter avoids infinite loops,
it is also necessary to avoid traffic explosion by keeping a cache of multicast
mesh frame that have been received recently. With this feature, maximum number
of retransmissions of a multicast frame for the case of N nodes within the range
of each other would be N. Without it, the maximum number of retransmissions
would be in the order of N^(MESH_TTL - 1).
Code to support mesh tables.
Signed-off-by: Luis Carlos Cobo <luisca@cozybit.com>
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
net/mac80211/mesh.c | 383 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 383 insertions(+)
create mode 100644 net/mac80211/mesh.c
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ everything/net/mac80211/mesh.c 2008-02-23 14:51:39.000000000 +0100
@@ -0,0 +1,383 @@
+/*
+ * Copyright (c) 2008 open80211s Ltd.
+ * Authors: Luis Carlos Cobo <luisca@cozybit.com>
+ * Javier Cardona <javier@cozybit.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "ieee80211_i.h"
+#include "mesh.h"
+
+#define PP_OFFSET 1 /* Path Selection Protocol */
+#define PM_OFFSET 5 /* Path Selection Metric */
+#define CC_OFFSET 9 /* Congestion Control Mode */
+#define CAPAB_OFFSET 17
+#define ACCEPT_PLINKS 0x80
+
+int mesh_allocated;
+static struct kmem_cache *rm_cache;
+
+void ieee80211s_init(void)
+{
+ mesh_pathtbl_init();
+ mesh_allocated = 1;
+ rm_cache = kmem_cache_create("mesh_rmc", sizeof(struct rmc_entry),
+ 0, 0, NULL);
+}
+
+void ieee80211s_stop(void)
+{
+ mesh_pathtbl_unregister();
+ kmem_cache_destroy(rm_cache);
+}
+
+/**
+ * mesh_matches_local - check if the config of a mesh point matches ours
+ *
+ * @ie: information elements of a management frame from the mesh peer
+ * @dev: local mesh interface
+ *
+ * This function checks if the mesh configuration of a mesh point matches the
+ * local mesh configuration, i.e. if both nodes belong to the same mesh network.
+ */
+bool mesh_matches_local(struct ieee802_11_elems *ie, struct net_device *dev)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_if_sta *sta = &sdata->u.sta;
+
+ if (sta->mesh_id_len == ie->mesh_id_len &&
+ memcmp(sta->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 &&
+ memcmp(sta->mesh_pp_id, ie->mesh_config + PP_OFFSET, 4) == 0 &&
+ memcmp(sta->mesh_pm_id, ie->mesh_config + PM_OFFSET, 4) == 0 &&
+ memcmp(sta->mesh_cc_id, ie->mesh_config + CC_OFFSET, 4) == 0)
+ /*
+ * As support for each feature is added, check for matching
+ * - On mesh config capabilities
+ * - Power Save Support En
+ * - Sync support enabled
+ * - Sync support active
+ * - Sync support required from peer
+ * - MDA enabled
+ * - Power management control on fc
+ */
+ return true;
+
+ return false;
+}
+
+/**
+ * mesh_peer_accepts_plinks - check if an mp is willing to establish peer links
+ *
+ * @ie: information elements of a management frame from the mesh peer
+ * @dev: local mesh interface
+ */
+bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie,
+ struct net_device *dev)
+{
+ return (*(ie->mesh_config + CAPAB_OFFSET) & ACCEPT_PLINKS) != 0;
+}
+
+/**
+ * mesh_accept_plinks_update: update accepting_plink in local mesh beacons
+ *
+ * @dev: mesh interface in which mesh beacons are going to be updated
+ */
+void mesh_accept_plinks_update(struct net_device *dev)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ bool free_plinks;
+
+ /* In case mesh_plink_free_count > 0 and mesh_plinktbl_capacity == 0,
+ * the mesh interface might be able to establish plinks with peers that
+ * are already on the table but are not on ESTAB state. However, in
+ * general the mesh interface is not accepting peer link requests from
+ * new peers, and that must be reflected in the beacon
+ */
+ free_plinks = mesh_plink_availables(sdata);
+
+ if (free_plinks != sdata->u.sta.accepting_plinks)
+ ieee80211_sta_timer((unsigned long) sdata);
+}
+
+void mesh_ids_set_default(struct ieee80211_if_sta *sta)
+{
+ u8 def_id[4] = {0x00, 0x0F, 0xAC, 0xff};
+
+ memcpy(sta->mesh_pp_id, def_id, 4);
+ memcpy(sta->mesh_pm_id, def_id, 4);
+ memcpy(sta->mesh_cc_id, def_id, 4);
+}
+
+int mesh_rmc_init(struct net_device *dev)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ int i;
+
+ sdata->u.sta.rmc = kmalloc(sizeof(struct mesh_rmc), GFP_KERNEL);
+ if (!sdata->u.sta.rmc)
+ return -ENOMEM;
+ sdata->u.sta.rmc->idx_mask = RMC_BUCKETS - 1;
+ for (i = 0; i < RMC_BUCKETS; i++)
+ INIT_LIST_HEAD(&sdata->u.sta.rmc->bucket[i].list);
+ return 0;
+}
+
+void mesh_rmc_free(struct net_device *dev)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct mesh_rmc *rmc = sdata->u.sta.rmc;
+ struct rmc_entry *p, *n;
+ int i;
+
+ if (!sdata->u.sta.rmc)
+ return;
+
+ for (i = 0; i < RMC_BUCKETS; i++)
+ list_for_each_entry_safe(p, n, &rmc->bucket[i].list, list) {
+ list_del(&p->list);
+ kmem_cache_free(rm_cache, p);
+ }
+
+ kfree(rmc);
+ sdata->u.sta.rmc = NULL;
+}
+
+/**
+ * mesh_rmc_check - Check frame in recent multicast cache and add if absent.
+ *
+ * @sa: source address
+ * @mesh_hdr: mesh_header
+ *
+ * Returns: 0 if the frame is not in the cache, nonzero otherwise.
+ *
+ * Checks using the source address and the mesh sequence number if we have
+ * received this frame lately. If the frame is not in the cache, it is added to
+ * it.
+ */
+int mesh_rmc_check(u8 *sa, struct ieee80211s_hdr *mesh_hdr,
+ struct net_device *dev)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct mesh_rmc *rmc = sdata->u.sta.rmc;
+ u32 seqnum = 0;
+ int entries = 0;
+ u8 idx;
+ struct rmc_entry *p, *n;
+
+ /* Don't care about endianness since only match matters */
+ memcpy(&seqnum, mesh_hdr->seqnum, sizeof(mesh_hdr->seqnum));
+ idx = mesh_hdr->seqnum[0] & rmc->idx_mask;
+ list_for_each_entry_safe(p, n, &rmc->bucket[idx].list, list) {
+ ++entries;
+ if (time_after(jiffies, p->exp_time) ||
+ (entries == RMC_QUEUE_MAX_LEN)) {
+ list_del(&p->list);
+ kmem_cache_free(rm_cache, p);
+ --entries;
+ } else if ((seqnum == p->seqnum)
+ && (memcmp(sa, p->sa, ETH_ALEN) == 0))
+ return -1;
+ }
+
+ p = kmem_cache_alloc(rm_cache, GFP_ATOMIC);
+ if (!p) {
+ printk(KERN_DEBUG "o11s: could not allocate RMC entry\n");
+ return 0;
+ }
+ p->seqnum = seqnum;
+ p->exp_time = jiffies + RMC_TIMEOUT;
+ memcpy(p->sa, sa, ETH_ALEN);
+ list_add(&p->list, &rmc->bucket[idx].list);
+ return 0;
+}
+
+void mesh_mgmt_ies_add(struct sk_buff *skb, struct net_device *dev)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_supported_band *sband;
+ u8 *pos;
+ int len, i, rate;
+
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+ len = sband->n_bitrates;
+ if (len > 8)
+ len = 8;
+ pos = skb_put(skb, len + 2);
+ *pos++ = WLAN_EID_SUPP_RATES;
+ *pos++ = len;
+ for (i = 0; i < len; i++) {
+ rate = sband->bitrates[i].bitrate;
+ *pos++ = (u8) (rate / 5);
+ }
+
+ if (sband->n_bitrates > len) {
+ pos = skb_put(skb, sband->n_bitrates - len + 2);
+ *pos++ = WLAN_EID_EXT_SUPP_RATES;
+ *pos++ = sband->n_bitrates - len;
+ for (i = len; i < sband->n_bitrates; i++) {
+ rate = sband->bitrates[i].bitrate;
+ *pos++ = (u8) (rate / 5);
+ }
+ }
+
+ pos = skb_put(skb, 2 + sdata->u.sta.mesh_id_len);
+ *pos++ = WLAN_EID_MESH_ID;
+ *pos++ = sdata->u.sta.mesh_id_len;
+ if (sdata->u.sta.mesh_id_len)
+ memcpy(pos, sdata->u.sta.mesh_id, sdata->u.sta.mesh_id_len);
+
+ pos = skb_put(skb, 21);
+ *pos++ = WLAN_EID_MESH_CONFIG;
+ *pos++ = MESH_CFG_LEN;
+ /* Version */
+ *pos++ = 1;
+
+ /* Active path selection protocol ID */
+ memcpy(pos, sdata->u.sta.mesh_pp_id, 4);
+ pos += 4;
+
+ /* Active path selection metric ID */
+ memcpy(pos, sdata->u.sta.mesh_pm_id, 4);
+ pos += 4;
+
+ /* Congestion control mode identifier */
+ memcpy(pos, sdata->u.sta.mesh_cc_id, 4);
+ pos += 4;
+
+ /* Channel precedence:
+ * Not running simple channel unification protocol
+ */
+ memset(pos, 0x00, 4);
+ pos += 4;
+
+ /* Mesh capability */
+ sdata->u.sta.accepting_plinks = mesh_plink_availables(sdata);
+ *pos++ = sdata->u.sta.accepting_plinks ? ACCEPT_PLINKS : 0x00;
+ *pos++ = 0x00;
+
+ return;
+}
+
+u32 mesh_table_hash(u8 *addr, struct net_device *dev, struct mesh_table *tbl)
+{
+ /* Use last four bytes of hw addr and interface index as hash index */
+ return jhash_2words(*(u32 *)(addr+2), dev->ifindex, tbl->hash_rnd)
+ & tbl->hash_mask;
+}
+
+u8 mesh_id_hash(u8 *mesh_id, int mesh_id_len)
+{
+ if (!mesh_id_len)
+ return 1;
+ else if (mesh_id_len == 1)
+ return (u8) mesh_id[0];
+ else
+ return (u8) (mesh_id[0] + 2 * mesh_id[1]);
+}
+
+struct mesh_table *mesh_table_alloc(int size_order)
+{
+ int i;
+ struct mesh_table *newtbl;
+
+ newtbl = kmalloc(sizeof(struct mesh_table), GFP_KERNEL);
+ if (!newtbl)
+ return NULL;
+
+ newtbl->hash_buckets = kzalloc(sizeof(struct hlist_head) *
+ (1 << size_order), GFP_KERNEL);
+
+ if (!newtbl->hash_buckets) {
+ kfree(newtbl);
+ return NULL;
+ }
+
+ newtbl->hashwlock = kmalloc(sizeof(spinlock_t) *
+ (1 << size_order), GFP_KERNEL);
+ if (!newtbl->hashwlock) {
+ kfree(newtbl->hash_buckets);
+ kfree(newtbl);
+ return NULL;
+ }
+
+ newtbl->size_order = size_order;
+ newtbl->hash_mask = (1 << size_order) - 1;
+ atomic_set(&newtbl->entries, 0);
+ get_random_bytes(&newtbl->hash_rnd,
+ sizeof(newtbl->hash_rnd));
+ for (i = 0; i <= newtbl->hash_mask; i++)
+ spin_lock_init(&newtbl->hashwlock[i]);
+
+ return newtbl;
+}
+
+void mesh_table_free(struct mesh_table *tbl, bool free_leafs)
+{
+ struct hlist_head *mesh_hash;
+ struct hlist_node *p, *q;
+ int i;
+
+ mesh_hash = tbl->hash_buckets;
+ for (i = 0; i <= tbl->hash_mask; i++) {
+ spin_lock(&tbl->hashwlock[i]);
+ hlist_for_each_safe(p, q, &mesh_hash[i]) {
+ tbl->free_node(p, free_leafs);
+ atomic_dec(&tbl->entries);
+ }
+ spin_unlock(&tbl->hashwlock[i]);
+ }
+ kfree(tbl->hash_buckets);
+ kfree(tbl->hashwlock);
+ kfree(tbl);
+}
+
+static void ieee80211_mesh_path_timer(unsigned long data)
+{
+ struct ieee80211_sub_if_data *sdata =
+ (struct ieee80211_sub_if_data *) data;
+ struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+ struct ieee80211_local *local = wdev_priv(&sdata->wdev);
+
+ queue_work(local->hw.workqueue, &ifsta->work);
+}
+
+struct mesh_table *mesh_table_grow(struct mesh_table *tbl)
+{
+ struct mesh_table *newtbl;
+ struct hlist_head *oldhash;
+ struct hlist_node *p;
+ int err = 0;
+ int i;
+
+ if (atomic_read(&tbl->entries)
+ < tbl->mean_chain_len * (tbl->hash_mask + 1)) {
+ err = -EPERM;
+ goto endgrow;
+ }
+
+ newtbl = mesh_table_alloc(tbl->size_order + 1);
+ if (!newtbl) {
+ err = -ENOMEM;
+ goto endgrow;
+ }
+
+ newtbl->free_node = tbl->free_node;
+ newtbl->mean_chain_len = tbl->mean_chain_len;
+ newtbl->copy_node = tbl->copy_node;
+ atomic_set(&newtbl->entries, atomic_read(&tbl->entries));
+
+ oldhash = tbl->hash_buckets;
+ for (i = 0; i <= tbl->hash_mask; i++)
+ hlist_for_each(p, &oldhash[i])
+ tbl->copy_node(p, newtbl);
+
+endgrow:
+ if (err)
+ return NULL;
+ else
+ return newtbl;
+}
--
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH 07/18] mac80211: support for mesh interfaces in mac80211 data path
2008-02-23 14:17 [PATCH 00/18] mac80211 802.11s networking code Johannes Berg
` (5 preceding siblings ...)
2008-02-23 14:17 ` [PATCH 06/18] mac80211: support functions for mesh Johannes Berg
@ 2008-02-23 14:17 ` Johannes Berg
2008-02-23 14:17 ` [PATCH 08/18] mac80211: mesh data structures and first mesh changes Johannes Berg
` (10 subsequent siblings)
17 siblings, 0 replies; 29+ messages in thread
From: Johannes Berg @ 2008-02-23 14:17 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless, Luis Carlos Cobo
From: Luis Carlos Cobo <luisca@cozybit.com>
This changes the TX/RX paths in mac80211 to support mesh interfaces.
This code will be cleaned up later again before being enabled.
Signed-off-by: Luis Carlos Cobo <luisca@cozybit.com>
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
net/mac80211/rx.c | 121 +++++++++++++++++++++++++++++++++++++++--
net/mac80211/tx.c | 158 ++++++++++++++++++++++++++++++++++++++++++++----------
2 files changed, 246 insertions(+), 33 deletions(-)
--- everything.orig/net/mac80211/rx.c 2008-02-23 14:25:19.000000000 +0100
+++ everything/net/mac80211/rx.c 2008-02-23 14:28:13.000000000 +0100
@@ -20,6 +20,9 @@
#include "ieee80211_i.h"
#include "ieee80211_led.h"
+#ifdef CONFIG_MAC80211_MESH
+#include "mesh.h"
+#endif
#include "wep.h"
#include "wpa.h"
#include "tkip.h"
@@ -390,10 +393,60 @@ ieee80211_rx_h_passive_scan(struct ieee8
return RX_CONTINUE;
}
+#ifdef CONFIG_MAC80211_MESH
+#define msh_h_get(h, l) ((struct ieee80211s_hdr *) ((u8 *)h + l))
+static ieee80211_rx_result
+ieee80211_rx_mesh_check(struct ieee80211_txrx_data *rx)
+{
+ int hdrlen = ieee80211_get_hdrlen(rx->fc);
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
+ if ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) {
+ if (!((rx->fc & IEEE80211_FCTL_FROMDS) &&
+ (rx->fc & IEEE80211_FCTL_TODS)))
+ return RX_DROP_MONITOR;
+ if (memcmp(hdr->addr4, rx->dev->dev_addr, ETH_ALEN) == 0)
+ return RX_DROP_MONITOR;
+ }
+
+ /* If there is not an established peer link and this is not a peer link
+ * establisment frame, beacon or probe, drop the frame.
+ */
+
+ if (!rx->sta || rx->sta->plink_state != ESTAB) {
+ struct ieee80211_mgmt *mgmt;
+ if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT)
+ return RX_DROP_MONITOR;
+
+ switch (rx->fc & IEEE80211_FCTL_STYPE) {
+ case IEEE80211_STYPE_ACTION:
+ mgmt = (struct ieee80211_mgmt *)hdr;
+ if (mgmt->u.action.category != PLINK_CATEGORY)
+ return RX_DROP_MONITOR;
+ /* fall through on else */
+ case IEEE80211_STYPE_PROBE_REQ:
+ case IEEE80211_STYPE_PROBE_RESP:
+ case IEEE80211_STYPE_BEACON:
+ return RX_CONTINUE;
+ break;
+ default:
+ return RX_DROP_MONITOR;
+ }
+
+ } else if ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA &&
+ is_broadcast_ether_addr(hdr->addr1) &&
+ mesh_rmc_check(hdr->addr4, msh_h_get(hdr, hdrlen), rx->dev))
+ return RX_DROP_MONITOR;
+ else
+ return RX_CONTINUE;
+}
+#endif
+
+
static ieee80211_rx_result
ieee80211_rx_h_check(struct ieee80211_txrx_data *rx)
{
struct ieee80211_hdr *hdr;
+
hdr = (struct ieee80211_hdr *) rx->skb->data;
/* Drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.2.9) */
@@ -423,6 +476,12 @@ ieee80211_rx_h_check(struct ieee80211_tx
* deauth/disassoc frames when needed. In addition, hostapd is
* responsible for filtering on both auth and assoc states.
*/
+
+#ifdef CONFIG_MAC80211_MESH
+ if (rx->sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT)
+ return ieee80211_rx_mesh_check(rx);
+#endif
+
if (unlikely(((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA ||
((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL &&
(rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)) &&
@@ -657,6 +716,8 @@ ieee80211_rx_h_sta_process(struct ieee80
/* Update last_rx only for unicast frames in order to prevent
* the Probe Request frames (the only broadcast frames from a
* STA in infrastructure mode) from keeping a connection alive.
+ * Mesh beacons will update last_rx when if they are found to
+ * match the current local configuration when processed.
*/
sta->last_rx = jiffies;
}
@@ -1050,6 +1111,23 @@ ieee80211_data_to_8023(struct ieee80211_
hdrlen = ieee80211_get_hdrlen(fc);
+#ifdef CONFIG_MAC80211_MESH
+ if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) {
+ int meshhdrlen = ieee80211_get_mesh_hdrlen(
+ (struct ieee80211s_hdr *) (skb->data + hdrlen));
+ /* Copy on cb:
+ * - mesh header: to be used for mesh forwarding
+ * decision. It will also be used as mesh header template at
+ * tx.c:ieee80211_subif_start_xmit() if interface
+ * type is mesh and skb->pkt_type == PACKET_OTHERHOST
+ * - ta: to be used if a RERR needs to be sent.
+ */
+ memcpy(skb->cb, skb->data + hdrlen, meshhdrlen);
+ memcpy(MESH_PREQ(skb), hdr->addr2, ETH_ALEN);
+ hdrlen += meshhdrlen;
+ }
+#endif
+
/* convert IEEE 802.11 header + possible LLC headers into Ethernet
* header
* IEEE 802.11 address fields:
@@ -1083,9 +1161,10 @@ ieee80211_data_to_8023(struct ieee80211_
memcpy(dst, hdr->addr3, ETH_ALEN);
memcpy(src, hdr->addr4, ETH_ALEN);
- if (unlikely(sdata->vif.type != IEEE80211_IF_TYPE_WDS)) {
- if (net_ratelimit())
- printk(KERN_DEBUG "%s: dropped FromDS&ToDS "
+ if (unlikely(sdata->vif.type != IEEE80211_IF_TYPE_WDS &&
+ sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)) {
+ if (net_ratelimit())
+ printk(KERN_DEBUG "%s: dropped FromDS&ToDS "
"frame (RA=%s TA=%s DA=%s SA=%s)\n",
rx->dev->name,
print_mac(mac, hdr->addr1),
@@ -1227,6 +1306,39 @@ ieee80211_deliver_skb(struct ieee80211_t
}
}
+#ifdef CONFIG_MAC80211_MESH
+ /* Mesh forwarding */
+ if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) {
+ u8 *mesh_ttl = &((struct ieee80211s_hdr *)skb->cb)->ttl;
+ (*mesh_ttl)--;
+
+ if (is_multicast_ether_addr(skb->data)) {
+ if (*mesh_ttl > 0) {
+ xmit_skb = skb_copy(skb, GFP_ATOMIC);
+ if (!xmit_skb && net_ratelimit())
+ printk(KERN_DEBUG "%s: failed to clone "
+ "multicast frame\n", dev->name);
+ else
+ xmit_skb->pkt_type = PACKET_OTHERHOST;
+ } else
+ sdata->u.sta.mshstats.dropped_frames_ttl++;
+
+ } else if (skb->pkt_type != PACKET_OTHERHOST &&
+ compare_ether_addr(dev->dev_addr, skb->data) != 0) {
+ if (*mesh_ttl == 0) {
+ sdata->u.sta.mshstats.dropped_frames_ttl++;
+ dev_kfree_skb(skb);
+ skb = NULL;
+ } else {
+ xmit_skb = skb;
+ xmit_skb->pkt_type = PACKET_OTHERHOST;
+ if (!(dev->flags & IFF_PROMISC))
+ skb = NULL;
+ }
+ }
+ }
+#endif
+
if (skb) {
/* deliver to local stack */
skb->protocol = eth_type_trans(skb, dev);
@@ -1444,7 +1556,8 @@ ieee80211_rx_h_mgmt(struct ieee80211_txr
sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
if ((sdata->vif.type == IEEE80211_IF_TYPE_STA ||
- sdata->vif.type == IEEE80211_IF_TYPE_IBSS) &&
+ sdata->vif.type == IEEE80211_IF_TYPE_IBSS ||
+ sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) &&
!(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME))
ieee80211_sta_rx_mgmt(rx->dev, rx->skb, rx->u.rx.status);
else
--- everything.orig/net/mac80211/tx.c 2008-02-23 14:25:19.000000000 +0100
+++ everything/net/mac80211/tx.c 2008-02-23 14:26:03.000000000 +0100
@@ -26,6 +26,9 @@
#include "ieee80211_i.h"
#include "ieee80211_led.h"
+#ifdef CONFIG_MAC80211_MESH
+#include "mesh.h"
+#endif
#include "wep.h"
#include "wpa.h"
#include "wme.h"
@@ -249,6 +252,9 @@ ieee80211_tx_h_check_assoc(struct ieee80
(tx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PROBE_REQ))
return TX_DROP;
+ if (tx->sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT)
+ return TX_CONTINUE;
+
if (tx->flags & IEEE80211_TXRXD_TXPS_BUFFERED)
return TX_CONTINUE;
@@ -1384,8 +1390,9 @@ int ieee80211_subif_start_xmit(struct sk
struct ieee80211_tx_packet_data *pkt_data;
struct ieee80211_sub_if_data *sdata;
int ret = 1, head_need;
- u16 ethertype, hdrlen, fc;
+ u16 ethertype, hdrlen, meshhdrlen = 0, fc;
struct ieee80211_hdr hdr;
+ struct ieee80211s_hdr mesh_hdr;
const u8 *encaps_data;
int encaps_len, skip_header_bytes;
int nh_pos, h_pos;
@@ -1427,6 +1434,37 @@ int ieee80211_subif_start_xmit(struct sk
memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
hdrlen = 30;
break;
+#ifdef CONFIG_MAC80211_MESH
+ case IEEE80211_IF_TYPE_MESH_POINT:
+ fc |= IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS;
+ /* RA TA DA SA */
+ if (is_multicast_ether_addr(skb->data))
+ memcpy(hdr.addr1, skb->data, ETH_ALEN);
+ else if (mesh_nexthop_lookup(hdr.addr1, skb, dev))
+ return 0;
+ memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
+ memcpy(hdr.addr3, skb->data, ETH_ALEN);
+ memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
+ if (skb->pkt_type == PACKET_OTHERHOST) {
+ /* Forwarded frame, keep mesh ttl and seqnum */
+ struct ieee80211s_hdr *prev_meshhdr;
+ prev_meshhdr = ((struct ieee80211s_hdr *)skb->cb);
+ meshhdrlen = ieee80211_get_mesh_hdrlen(prev_meshhdr);
+ memcpy(&mesh_hdr, prev_meshhdr, meshhdrlen);
+ sdata->u.sta.mshstats.fwded_frames++;
+ } else {
+ if (!sdata->u.sta.mshcfg.dot11MeshTTL) {
+ /* Do not send frames with mesh_ttl == 0 */
+ sdata->u.sta.mshstats.dropped_frames_ttl++;
+ ret = 0;
+ goto fail;
+ }
+ meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr,
+ sdata);
+ }
+ hdrlen = 30;
+ break;
+#endif
case IEEE80211_IF_TYPE_STA:
fc |= IEEE80211_FCTL_TODS;
/* BSSID SA DA */
@@ -1471,8 +1509,8 @@ int ieee80211_subif_start_xmit(struct sk
* EAPOL frames from the local station.
*/
if (unlikely(!is_multicast_ether_addr(hdr.addr1) &&
- !(sta_flags & WLAN_STA_AUTHORIZED) &&
- !(ethertype == ETH_P_PAE &&
+ !(sta_flags & WLAN_STA_AUTHORIZED) &&
+ !(ethertype == ETH_P_PAE &&
compare_ether_addr(dev->dev_addr,
skb->data + ETH_ALEN) == 0))) {
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
@@ -1525,7 +1563,7 @@ int ieee80211_subif_start_xmit(struct sk
* build in headroom in __dev_alloc_skb() (linux/skbuff.h) and
* alloc_skb() (net/core/skbuff.c)
*/
- head_need = hdrlen + encaps_len + local->tx_headroom;
+ head_need = hdrlen + encaps_len + meshhdrlen + local->tx_headroom;
head_need -= skb_headroom(skb);
/* We are going to modify skb data, so make a copy of it if happens to
@@ -1559,6 +1597,12 @@ int ieee80211_subif_start_xmit(struct sk
h_pos += encaps_len;
}
+ if (meshhdrlen > 0) {
+ memcpy(skb_push(skb, meshhdrlen), &mesh_hdr, meshhdrlen);
+ nh_pos += meshhdrlen;
+ h_pos += meshhdrlen;
+ }
+
if (fc & IEEE80211_STYPE_QOS_DATA) {
__le16 *qos_control;
@@ -1734,6 +1778,40 @@ static void ieee80211_beacon_add_tim(str
read_unlock_bh(&local->sta_lock);
}
+#ifdef CONFIG_MAC80211_MESH
+static struct sk_buff *ieee80211_mesh_beacon_get(struct net_device *dev)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
+ struct ieee80211_mgmt *mgmt;
+ u8 *pos;
+
+ if (!skb)
+ return NULL;
+ skb_reserve(skb, local->hw.extra_tx_headroom);
+ mgmt = (struct ieee80211_mgmt *)
+ skb_put(skb, 24 + sizeof(mgmt->u.beacon));
+ memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));
+ mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+ IEEE80211_STYPE_BEACON);
+ memset(mgmt->da, 0xff, ETH_ALEN);
+ memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
+ /* BSSID is left zeroed, wildcard value */
+ mgmt->u.beacon.beacon_int =
+ cpu_to_le16(local->hw.conf.beacon_int);
+ mgmt->u.beacon.capab_info = 0x0; /* 0x0 for MPs */
+
+ pos = skb_put(skb, 2);
+ *pos++ = WLAN_EID_SSID;
+ *pos++ = 0x0;
+
+ mesh_mgmt_ies_add(skb, dev);
+
+ return skb;
+}
+#endif
+
+
struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_tx_control *control)
@@ -1746,6 +1824,8 @@ struct sk_buff *ieee80211_beacon_get(str
struct rate_selection rsel;
struct beacon_data *beacon;
struct ieee80211_supported_band *sband;
+ int *num_beacons;
+ int err = 0;
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
@@ -1753,11 +1833,51 @@ struct sk_buff *ieee80211_beacon_get(str
sdata = vif_to_sdata(vif);
bdev = sdata->dev;
- ap = &sdata->u.ap;
- beacon = rcu_dereference(ap->beacon);
+ switch (sdata->vif.type) {
+ case IEEE80211_IF_TYPE_AP:
+ ap = &sdata->u.ap;
+ beacon = rcu_dereference(ap->beacon);
+ if (!ap || !beacon) {
+ err = -1;
+ break;
+ }
+
+ /* headroom, head length, tail length and maximum TIM length */
+ skb = dev_alloc_skb(local->tx_headroom + beacon->head_len +
+ beacon->tail_len + 256);
+ if (!skb)
+ goto out;
+
+ skb_reserve(skb, local->tx_headroom);
+ memcpy(skb_put(skb, beacon->head_len), beacon->head,
+ beacon->head_len);
- if (!ap || sdata->vif.type != IEEE80211_IF_TYPE_AP || !beacon) {
+ ieee80211_include_sequence(sdata,
+ (struct ieee80211_hdr *)skb->data);
+
+ ieee80211_beacon_add_tim(local, ap, skb, beacon);
+
+ if (beacon->tail)
+ memcpy(skb_put(skb, beacon->tail_len), beacon->tail,
+ beacon->tail_len);
+
+ num_beacons = &ap->num_beacons;
+ break;
+
+#ifdef CONFIG_MAC80211_MESH
+ case IEEE80211_IF_TYPE_MESH_POINT:
+ skb = ieee80211_mesh_beacon_get(bdev);
+ num_beacons = &sdata->u.sta.num_beacons;
+ break;
+#endif
+
+ default:
+ err = -1;
+ break;
+ }
+
+ if (err) {
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
if (net_ratelimit())
printk(KERN_DEBUG "no beacon data avail for %s\n",
@@ -1767,24 +1887,6 @@ struct sk_buff *ieee80211_beacon_get(str
goto out;
}
- /* headroom, head length, tail length and maximum TIM length */
- skb = dev_alloc_skb(local->tx_headroom + beacon->head_len +
- beacon->tail_len + 256);
- if (!skb)
- goto out;
-
- skb_reserve(skb, local->tx_headroom);
- memcpy(skb_put(skb, beacon->head_len), beacon->head,
- beacon->head_len);
-
- ieee80211_include_sequence(sdata, (struct ieee80211_hdr *)skb->data);
-
- ieee80211_beacon_add_tim(local, ap, skb, beacon);
-
- if (beacon->tail)
- memcpy(skb_put(skb, beacon->tail_len), beacon->tail,
- beacon->tail_len);
-
if (control) {
rate_control_get_rate(local->mdev, sband, skb, &rsel);
if (!rsel.rate) {
@@ -1808,10 +1910,8 @@ struct sk_buff *ieee80211_beacon_get(str
control->retry_limit = 1;
control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT;
}
-
- ap->num_beacons++;
-
- out:
+ (*num_beacons)++;
+out:
rcu_read_unlock();
return skb;
}
--
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH 08/18] mac80211: mesh data structures and first mesh changes
2008-02-23 14:17 [PATCH 00/18] mac80211 802.11s networking code Johannes Berg
` (6 preceding siblings ...)
2008-02-23 14:17 ` [PATCH 07/18] mac80211: support for mesh interfaces in mac80211 data path Johannes Berg
@ 2008-02-23 14:17 ` Johannes Berg
2008-02-23 14:17 ` [PATCH 09/18] mac80211: mesh changes to the MLME Johannes Berg
` (9 subsequent siblings)
17 siblings, 0 replies; 29+ messages in thread
From: Johannes Berg @ 2008-02-23 14:17 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless, Luis Carlos Cobo
From: Luis Carlos Cobo <luisca@cozybit.com>
Includes integration in struct sta_info of mesh peer link elements, previously
on their own mesh peer link table.
Signed-off-by: Luis Carlos Cobo <luisca@cozybit.com>
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
net/mac80211/cfg.c | 2
net/mac80211/ieee80211.c | 2
net/mac80211/ieee80211_i.h | 170 +++++++++++++++++++++++++++++++++++++++-
net/mac80211/ieee80211_iface.c | 62 ++++++++++++++
net/mac80211/ieee80211_ioctl.c | 1
net/mac80211/ieee80211_sta.c | 70 ++++++----------
net/mac80211/rc80211_pid_algo.c | 14 +++
net/mac80211/sta_info.c | 42 +++++++++
net/mac80211/sta_info.h | 30 +++++++
net/mac80211/util.c | 51 ++++++++++++
10 files changed, 394 insertions(+), 50 deletions(-)
--- everything.orig/net/mac80211/ieee80211_i.h 2008-02-23 14:51:27.000000000 +0100
+++ everything/net/mac80211/ieee80211_i.h 2008-02-23 14:58:05.000000000 +0100
@@ -90,6 +90,12 @@ struct ieee80211_sta_bss {
size_t wmm_ie_len;
u8 *ht_ie;
size_t ht_ie_len;
+#ifdef CONFIG_MAC80211_MESH
+ u8 *mesh_id;
+ size_t mesh_id_len;
+#endif
+ /* mesh_cfg left out the ifdef to reduce clutter on bss handling */
+ u8 *mesh_cfg;
#define IEEE80211_MAX_SUPP_RATES 32
u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
size_t supp_rates_len;
@@ -227,6 +233,43 @@ struct ieee80211_if_vlan {
struct list_head list;
};
+#ifdef CONFIG_MAC80211_MESH
+struct mesh_stats {
+ __u32 fwded_frames; /* Mesh forwarded frames */
+ __u32 dropped_frames_ttl; /* Not transmitted since mesh_ttl == 0*/
+ __u32 dropped_frames_no_route; /* Not transmitted, no route found */
+ atomic_t estab_plinks;
+};
+
+#define PREQ_Q_F_START 0x1
+#define PREQ_Q_F_REFRESH 0x2
+struct mesh_preq_queue {
+ struct list_head list;
+ u8 dst[ETH_ALEN];
+ u8 flags;
+};
+
+
+struct mesh_config {
+ /* Timeouts in ms */
+ /* Mesh plink management parameters */
+ u16 dot11MeshRetryTimeout;
+ u16 dot11MeshConfirmTimeout;
+ u16 dot11MeshHoldingTimeout;
+ u16 dot11MeshMaxPeerLinks;
+ u8 dot11MeshMaxRetries;
+ u8 dot11MeshTTL;
+ bool auto_open_plinks;
+ /* HWMP parameters */
+ u32 dot11MeshHWMPactivePathTimeout;
+ u16 dot11MeshHWMPpreqMinInterval;
+ u16 dot11MeshHWMPnetDiameterTraversalTime;
+ u8 dot11MeshHWMPmaxPREQretries;
+ u32 path_refresh_time;
+ u16 min_discovery_timeout;
+};
+#endif
+
/* flags used in struct ieee80211_if_sta.flags */
#define IEEE80211_STA_SSID_SET BIT(0)
#define IEEE80211_STA_BSSID_SET BIT(1)
@@ -245,7 +288,8 @@ struct ieee80211_if_sta {
enum {
IEEE80211_DISABLED, IEEE80211_AUTHENTICATE,
IEEE80211_ASSOCIATE, IEEE80211_ASSOCIATED,
- IEEE80211_IBSS_SEARCH, IEEE80211_IBSS_JOINED
+ IEEE80211_IBSS_SEARCH, IEEE80211_IBSS_JOINED,
+ IEEE80211_MESH_UP
} state;
struct timer_list timer;
struct work_struct work;
@@ -254,6 +298,34 @@ struct ieee80211_if_sta {
size_t ssid_len;
u8 scan_ssid[IEEE80211_MAX_SSID_LEN];
size_t scan_ssid_len;
+#ifdef CONFIG_MAC80211_MESH
+ struct timer_list mesh_path_timer;
+ u8 mesh_id[IEEE80211_MAX_MESH_ID_LEN];
+ bool accepting_plinks;
+ size_t mesh_id_len;
+ /* Active Path Selection Protocol Identifier */
+ u8 mesh_pp_id[4];
+ /* Active Path Selection Metric Identifier */
+ u8 mesh_pm_id[4];
+ /* Congestion Control Mode Identifier */
+ u8 mesh_cc_id[4];
+ /* Local mesh Destination Sequence Number */
+ u32 dsn;
+ /* Last used PREQ ID */
+ u32 preq_id;
+ atomic_t mpaths;
+ /* Timestamp of last DSN update */
+ unsigned long last_dsn_update;
+ /* Timestamp of last DSN sent */
+ unsigned long last_preq;
+ struct mesh_rmc *rmc;
+ spinlock_t mesh_preq_queue_lock;
+ struct mesh_preq_queue preq_queue;
+ int preq_queue_len;
+ struct mesh_stats mshstats;
+ struct mesh_config mshcfg;
+ u8 mesh_seqnum[3];
+#endif
u16 aid;
u16 ap_capab, capab;
u8 *extra_ie; /* to be added to the end of AssocReq */
@@ -286,6 +358,7 @@ struct ieee80211_if_sta {
u32 supp_rates_bits[IEEE80211_NUM_BANDS];
int wmm_last_param_set;
+ int num_beacons; /* number of TXed beacon frames by this STA */
};
@@ -365,6 +438,7 @@ struct ieee80211_sub_if_data {
struct dentry *auth_alg;
struct dentry *auth_transaction;
struct dentry *flags;
+ struct dentry *num_beacons_sta;
} sta;
struct {
struct dentry *channel_use;
@@ -390,6 +464,35 @@ struct ieee80211_sub_if_data {
} monitor;
struct dentry *default_key;
} debugfs;
+
+#ifdef CONFIG_MAC80211_MESH
+ struct dentry *mesh_stats_dir;
+ struct {
+ struct dentry *fwded_frames;
+ struct dentry *dropped_frames_ttl;
+ struct dentry *dropped_frames_no_route;
+ struct dentry *estab_plinks;
+ struct timer_list mesh_path_timer;
+ } mesh_stats;
+
+ struct dentry *mesh_config_dir;
+ struct {
+ struct dentry *dot11MeshRetryTimeout;
+ struct dentry *dot11MeshConfirmTimeout;
+ struct dentry *dot11MeshHoldingTimeout;
+ struct dentry *dot11MeshMaxRetries;
+ struct dentry *dot11MeshTTL;
+ struct dentry *auto_open_plinks;
+ struct dentry *dot11MeshMaxPeerLinks;
+ struct dentry *dot11MeshHWMPactivePathTimeout;
+ struct dentry *dot11MeshHWMPpreqMinInterval;
+ struct dentry *dot11MeshHWMPnetDiameterTraversalTime;
+ struct dentry *dot11MeshHWMPmaxPREQretries;
+ struct dentry *path_refresh_time;
+ struct dentry *min_discovery_timeout;
+ } mesh_config;
+#endif
+
#endif
/* must be last, dynamically sized area in this! */
struct ieee80211_vif vif;
@@ -617,6 +720,57 @@ struct ieee80211_ra_tid {
u16 tid;
};
+/* Parsed Information Elements */
+struct ieee802_11_elems {
+ /* pointers to IEs */
+ u8 *ssid;
+ u8 *supp_rates;
+ u8 *fh_params;
+ u8 *ds_params;
+ u8 *cf_params;
+ u8 *tim;
+ u8 *ibss_params;
+ u8 *challenge;
+ u8 *wpa;
+ u8 *rsn;
+ u8 *erp_info;
+ u8 *ext_supp_rates;
+ u8 *wmm_info;
+ u8 *wmm_param;
+ u8 *ht_cap_elem;
+ u8 *ht_info_elem;
+ u8 *mesh_config;
+ u8 *mesh_id;
+ u8 *peer_link;
+ u8 *preq;
+ u8 *prep;
+ u8 *perr;
+
+ /* length of them, respectively */
+ u8 ssid_len;
+ u8 supp_rates_len;
+ u8 fh_params_len;
+ u8 ds_params_len;
+ u8 cf_params_len;
+ u8 tim_len;
+ u8 ibss_params_len;
+ u8 challenge_len;
+ u8 wpa_len;
+ u8 rsn_len;
+ u8 erp_info_len;
+ u8 ext_supp_rates_len;
+ u8 wmm_info_len;
+ u8 wmm_param_len;
+ u8 ht_cap_elem_len;
+ u8 ht_info_elem_len;
+ u8 mesh_config_len;
+ u8 mesh_id_len;
+ u8 peer_link_len;
+ u8 preq_len;
+ u8 prep_len;
+ u8 perr_len;
+};
+
static inline struct ieee80211_local *hw_to_local(
struct ieee80211_hw *hw)
{
@@ -686,6 +840,7 @@ int ieee80211_set_compression(struct iee
struct net_device *dev, struct sta_info *sta);
int ieee80211_set_freq(struct ieee80211_local *local, int freq);
/* ieee80211_sta.c */
+#define IEEE80211_FC(type, stype) cpu_to_le16(type | stype)
void ieee80211_sta_timer(unsigned long data);
void ieee80211_sta_work(struct work_struct *work);
void ieee80211_sta_scan_work(struct work_struct *work);
@@ -726,9 +881,20 @@ void ieee80211_sta_stop_rx_ba_session(st
u16 tid, u16 initiator, u16 reason);
void sta_rx_agg_session_timer_expired(unsigned long data);
void sta_addba_resp_timer_expired(unsigned long data);
+u64 ieee80211_sta_get_rates(struct ieee80211_local *local,
+ struct ieee802_11_elems *elems,
+ enum ieee80211_band band);
+void ieee80211_start_mesh(struct net_device *dev);
+void ieee80211_sta_tx(struct net_device *dev, struct sk_buff *skb,
+ int encrypt);
+void ieee802_11_parse_elems(u8 *start, size_t len,
+ struct ieee802_11_elems *elems);
+
+
/* ieee80211_iface.c */
int ieee80211_if_add(struct net_device *dev, const char *name,
- struct net_device **new_dev, int type);
+ struct net_device **new_dev, int type,
+ struct vif_params *params);
void ieee80211_if_set_type(struct net_device *dev, int type);
void ieee80211_if_reinit(struct net_device *dev);
void __ieee80211_if_del(struct ieee80211_local *local,
--- everything.orig/net/mac80211/ieee80211_iface.c 2008-02-23 14:51:27.000000000 +0100
+++ everything/net/mac80211/ieee80211_iface.c 2008-02-23 14:57:46.000000000 +0100
@@ -15,6 +15,9 @@
#include "ieee80211_i.h"
#include "sta_info.h"
#include "debugfs_netdev.h"
+#ifdef CONFIG_MAC80211_MESH
+#include "mesh.h"
+#endif
void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata)
{
@@ -39,7 +42,8 @@ static void ieee80211_if_sdata_deinit(st
/* Must be called with rtnl lock held. */
int ieee80211_if_add(struct net_device *dev, const char *name,
- struct net_device **new_dev, int type)
+ struct net_device **new_dev, int type,
+ struct vif_params *params)
{
struct net_device *ndev;
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
@@ -78,6 +82,15 @@ int ieee80211_if_add(struct net_device *
ieee80211_debugfs_add_netdev(sdata);
ieee80211_if_set_type(ndev, type);
+#ifdef CONFIG_MAC80211_MESH
+ if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT &&
+ params && params->mesh_id_len) {
+ sdata->u.sta.mesh_id_len = params->mesh_id_len;
+ memcpy(sdata->u.sta.mesh_id, params->mesh_id,
+ params->mesh_id_len);
+ }
+#endif
+
/* we're under RTNL so all this is fine */
if (unlikely(local->reg_state == IEEE80211_DEV_UNREGISTERED)) {
__ieee80211_if_del(local, sdata);
@@ -134,6 +147,7 @@ void ieee80211_if_set_type(struct net_de
sdata->bss = &sdata->u.ap;
INIT_LIST_HEAD(&sdata->u.ap.vlans);
break;
+ case IEEE80211_IF_TYPE_MESH_POINT:
case IEEE80211_IF_TYPE_STA:
case IEEE80211_IF_TYPE_IBSS: {
struct ieee80211_sub_if_data *msdata;
@@ -155,6 +169,48 @@ void ieee80211_if_set_type(struct net_de
msdata = IEEE80211_DEV_TO_SUB_IF(sdata->local->mdev);
sdata->bss = &msdata->u.ap;
+
+#ifdef CONFIG_MAC80211_MESH
+ if (type == IEEE80211_IF_TYPE_MESH_POINT) {
+ ifsta->mshcfg.dot11MeshRetryTimeout = MESH_RET_T;
+ ifsta->mshcfg.dot11MeshConfirmTimeout = MESH_CONF_T;
+ ifsta->mshcfg.dot11MeshHoldingTimeout = MESH_HOLD_T;
+ ifsta->mshcfg.dot11MeshMaxRetries = MESH_MAX_RETR;
+ ifsta->mshcfg.dot11MeshTTL = MESH_TTL;
+ ifsta->mshcfg.auto_open_plinks = true;
+ ifsta->mshcfg.dot11MeshMaxPeerLinks =
+ MESH_MAX_ESTAB_PLINKS;
+ ifsta->mshcfg.dot11MeshHWMPactivePathTimeout =
+ MESH_PATH_TIMEOUT;
+ ifsta->mshcfg.dot11MeshHWMPpreqMinInterval =
+ MESH_PREQ_MIN_INT;
+ ifsta->mshcfg.dot11MeshHWMPnetDiameterTraversalTime =
+ MESH_DIAM_TRAVERSAL_TIME;
+ ifsta->mshcfg.dot11MeshHWMPmaxPREQretries =
+ MESH_MAX_PREQ_RETRIES;
+ ifsta->mshcfg.path_refresh_time =
+ MESH_PATH_REFRESH_TIME;
+ ifsta->mshcfg.min_discovery_timeout =
+ MESH_MIN_DISCOVERY_TIMEOUT;
+ ifsta->accepting_plinks = true;
+ ifsta->preq_id = 0;
+ ifsta->dsn = 0;
+ atomic_set(&ifsta->mpaths, 0);
+ mesh_rmc_init(dev);
+ ifsta->last_preq = jiffies;
+ /* Allocate all mesh structures when creating the first
+ * mesh interface.
+ */
+ if (!mesh_allocated)
+ ieee80211s_init();
+ mesh_ids_set_default(ifsta);
+ setup_timer(&ifsta->mesh_path_timer,
+ ieee80211_mesh_path_timer,
+ (unsigned long) sdata);
+ INIT_LIST_HEAD(&ifsta->preq_queue.list);
+ spin_lock_init(&ifsta->mesh_preq_queue_lock);
+ }
+#endif
break;
}
case IEEE80211_IF_TYPE_MNTR:
@@ -232,6 +288,10 @@ void ieee80211_if_reinit(struct net_devi
}
break;
case IEEE80211_IF_TYPE_MESH_POINT:
+#ifdef CONFIG_MAC80211_MESH
+ mesh_rmc_free(dev);
+#endif
+ /* fall through */
case IEEE80211_IF_TYPE_STA:
case IEEE80211_IF_TYPE_IBSS:
kfree(sdata->u.sta.extra_ie);
--- everything.orig/net/mac80211/ieee80211_ioctl.c 2008-02-23 14:51:27.000000000 +0100
+++ everything/net/mac80211/ieee80211_ioctl.c 2008-02-23 14:52:04.000000000 +0100
@@ -519,6 +519,7 @@ static int ieee80211_ioctl_siwscan(struc
if (sdata->vif.type != IEEE80211_IF_TYPE_STA &&
sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
+ sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT &&
sdata->vif.type != IEEE80211_IF_TYPE_AP)
return -EOPNOTSUPP;
--- everything.orig/net/mac80211/rc80211_pid_algo.c 2008-02-23 14:51:27.000000000 +0100
+++ everything/net/mac80211/rc80211_pid_algo.c 2008-02-23 14:57:45.000000000 +0100
@@ -15,6 +15,9 @@
#include <linux/debugfs.h>
#include <net/mac80211.h>
#include "ieee80211_rate.h"
+#ifdef CONFIG_MAC80211_MESH
+#include "mesh.h"
+#endif
#include "rc80211_pid.h"
@@ -148,6 +151,9 @@ static void rate_control_pid_sample(stru
struct ieee80211_local *local,
struct sta_info *sta)
{
+#ifdef CONFIG_MAC80211_MESH
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
+#endif
struct rc_pid_sta_info *spinfo = sta->rate_ctrl_priv;
struct rc_pid_rateinfo *rinfo = pinfo->rinfo;
struct ieee80211_supported_band *sband;
@@ -178,7 +184,14 @@ static void rate_control_pid_sample(stru
pf = spinfo->last_pf;
else {
pf = spinfo->tx_num_failed * 100 / spinfo->tx_num_xmit;
+#ifdef CONFIG_MAC80211_MESH
+ if (pf == 100 &&
+ sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT)
+ mesh_plink_broken(sta);
+#endif
pf <<= RC_PID_ARITH_SHIFT;
+ sta->fail_avg = ((pf + (spinfo->last_pf << 3)) / 9)
+ >> RC_PID_ARITH_SHIFT;
}
spinfo->tx_num_xmit = 0;
@@ -360,6 +373,7 @@ static void rate_control_pid_rate_init(v
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
sta->txrate_idx = rate_lowest_index(local, sband, sta);
+ sta->fail_avg = 0;
}
static void *rate_control_pid_alloc(struct ieee80211_local *local)
--- everything.orig/net/mac80211/sta_info.c 2008-02-23 14:51:27.000000000 +0100
+++ everything/net/mac80211/sta_info.c 2008-02-23 14:57:46.000000000 +0100
@@ -21,6 +21,9 @@
#include "ieee80211_rate.h"
#include "sta_info.h"
#include "debugfs_sta.h"
+#ifdef CONFIG_MAC80211_MESH
+#include "mesh.h"
+#endif
/* Caller must hold local->sta_lock */
static void sta_info_hash_add(struct ieee80211_local *local,
@@ -84,6 +87,27 @@ struct sta_info *sta_info_get(struct iee
}
EXPORT_SYMBOL(sta_info_get);
+struct sta_info *sta_info_get_by_idx(struct ieee80211_local *local, int idx,
+ struct net_device *dev)
+{
+ struct sta_info *sta;
+ int i = 0;
+
+ read_lock_bh(&local->sta_lock);
+ list_for_each_entry(sta, &local->sta_list, list) {
+ if (i < idx) {
+ ++i;
+ continue;
+ } else if (!dev || dev == sta->dev) {
+ __sta_info_get(sta);
+ read_unlock_bh(&local->sta_lock);
+ return sta;
+ }
+ }
+ read_unlock_bh(&local->sta_lock);
+
+ return NULL;
+}
static void sta_info_release(struct kref *kref)
{
@@ -284,12 +308,19 @@ void sta_info_remove(struct sta_info *st
__sta_info_clear_tim_bit(sdata->bss, sta);
}
local->num_sta--;
+
+#ifdef CONFIG_MAC80211_MESH
+ if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT)
+ mesh_accept_plinks_update(sdata->dev);
+#endif
}
void sta_info_free(struct sta_info *sta)
{
struct sk_buff *skb;
struct ieee80211_local *local = sta->local;
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
+
DECLARE_MAC_BUF(mac);
might_sleep();
@@ -298,6 +329,14 @@ void sta_info_free(struct sta_info *sta)
sta_info_remove(sta);
write_unlock_bh(&local->sta_lock);
+#ifdef CONFIG_MAC80211_MESH
+ if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) {
+ spin_lock_bh(&sta->plink_lock);
+ mesh_plink_deactivate(sta);
+ spin_unlock_bh(&sta->plink_lock);
+ }
+#endif
+
while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) {
local->total_ps_buffered--;
dev_kfree_skb(skb);
@@ -315,9 +354,6 @@ void sta_info_free(struct sta_info *sta)
sta->key = NULL;
if (local->ops->sta_notify) {
- struct ieee80211_sub_if_data *sdata;
-
- sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN)
sdata = sdata->u.vlan.ap;
--- everything.orig/net/mac80211/sta_info.h 2008-02-23 14:51:27.000000000 +0100
+++ everything/net/mac80211/sta_info.h 2008-02-23 14:57:45.000000000 +0100
@@ -107,6 +107,18 @@ struct tid_ampdu_rx {
struct timer_list session_timer;
};
+#ifdef CONFIG_MAC80211_MESH
+enum plink_state {
+ LISTEN,
+ OPN_SNT,
+ OPN_RCVD,
+ CNF_RCVD,
+ ESTAB,
+ HOLDING,
+ BLOCKED
+};
+#endif
+
/**
* struct sta_ampdu_mlme - STA aggregation information.
*
@@ -144,6 +156,8 @@ struct sta_info {
unsigned long rx_bytes, tx_bytes;
unsigned long tx_retry_failed, tx_retry_count;
unsigned long tx_filtered_count;
+ /* moving percentage of failed MSDUs */
+ unsigned int fail_avg;
unsigned int wep_weak_iv_count; /* number of RX frames with weak IV */
@@ -194,6 +208,20 @@ struct sta_info {
struct sta_ampdu_mlme ampdu_mlme;
u8 timer_to_tid[STA_TID_NUM]; /* convert timer id to tid */
u8 tid_to_tx_q[STA_TID_NUM]; /* map tid to tx queue */
+#ifdef CONFIG_MAC80211_MESH
+ /* mesh peer link attributes */
+ __le16 llid; /* Local link ID */
+ __le16 plid; /* Peer link ID */
+ __le16 reason; /* Buffer for cancel reason on HOLDING state */
+ enum plink_state plink_state;
+ u32 plink_timeout;
+ struct timer_list plink_timer;
+ u8 plink_retries; /* Retries in establishment */
+ bool ignore_plink_timer;
+ spinlock_t plink_lock; /* For peer_state reads / updates and other
+ updates in the structure. Ensures robust
+ transitions for the peerlink FSM */
+#endif
#ifdef CONFIG_MAC80211_DEBUGFS
struct sta_info_debugfsdentries {
@@ -238,6 +266,8 @@ static inline void __sta_info_get(struct
}
struct sta_info * sta_info_get(struct ieee80211_local *local, u8 *addr);
+struct sta_info *sta_info_get_by_idx(struct ieee80211_local *local, int idx,
+ struct net_device *dev);
void sta_info_put(struct sta_info *sta);
struct sta_info *sta_info_add(struct ieee80211_local *local,
struct net_device *dev, u8 *addr, gfp_t gfp);
--- everything.orig/net/mac80211/util.c 2008-02-23 14:51:27.000000000 +0100
+++ everything/net/mac80211/util.c 2008-02-23 14:57:45.000000000 +0100
@@ -26,6 +26,9 @@
#include "ieee80211_i.h"
#include "ieee80211_rate.h"
+#ifdef CONFIG_MAC80211_MESH
+#include "mesh.h"
+#endif
#include "wme.h"
/* privid for wiphys to determine whether they belong to us or not */
@@ -146,6 +149,26 @@ int ieee80211_get_hdrlen_from_skb(const
}
EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb);
+#ifdef CONFIG_MAC80211_MESH
+int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)
+{
+ int ae = meshhdr->flags & IEEE80211S_FLAGS_AE;
+ /* 7.1.3.5a.2 */
+ switch (ae) {
+ case 0:
+ return 5;
+ case 1:
+ return 11;
+ case 2:
+ return 17;
+ case 3:
+ return 23;
+ default:
+ return 5;
+ }
+}
+#endif
+
void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
@@ -395,3 +418,31 @@ void ieee80211_iterate_active_interfaces
rcu_read_unlock();
}
EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces);
+
+#ifdef CONFIG_MAC80211_MESH
+/**
+ * ieee80211_new_mesh_header - create a new mesh header
+ * @meshhdr: uninitialized mesh header
+ * @sdata: mesh interface to be used
+ *
+ * Return the header length.
+ */
+int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr,
+ struct ieee80211_sub_if_data *sdata)
+{
+ meshhdr->flags = 0;
+ meshhdr->ttl = sdata->u.sta.mshcfg.dot11MeshTTL;
+
+ meshhdr->seqnum[0] = sdata->u.sta.mesh_seqnum[0]++;
+ meshhdr->seqnum[1] = sdata->u.sta.mesh_seqnum[1];
+ meshhdr->seqnum[2] = sdata->u.sta.mesh_seqnum[2];
+
+ if (sdata->u.sta.mesh_seqnum[0] == 0) {
+ sdata->u.sta.mesh_seqnum[1]++;
+ if (sdata->u.sta.mesh_seqnum[1] == 0)
+ sdata->u.sta.mesh_seqnum[2]++;
+ }
+
+ return 5;
+}
+#endif
--- everything.orig/net/mac80211/ieee80211.c 2008-02-23 14:51:27.000000000 +0100
+++ everything/net/mac80211/ieee80211.c 2008-02-23 14:57:46.000000000 +0100
@@ -1663,7 +1663,7 @@ int ieee80211_register_hw(struct ieee802
/* add one default STA interface */
result = ieee80211_if_add(local->mdev, "wlan%d", NULL,
- IEEE80211_IF_TYPE_STA);
+ IEEE80211_IF_TYPE_STA, NULL);
if (result)
printk(KERN_WARNING "%s: Failed to add default virtual iface\n",
wiphy_name(local->hw.wiphy));
--- everything.orig/net/mac80211/cfg.c 2008-02-23 14:51:27.000000000 +0100
+++ everything/net/mac80211/cfg.c 2008-02-23 14:57:46.000000000 +0100
@@ -50,7 +50,7 @@ static int ieee80211_add_iface(struct wi
if (itype == IEEE80211_IF_TYPE_INVALID)
return -EINVAL;
- err = ieee80211_if_add(local->mdev, name, &dev, itype);
+ err = ieee80211_if_add(local->mdev, name, &dev, itype, params);
if (err || itype != IEEE80211_IF_TYPE_MNTR || !flags)
return err;
--- everything.orig/net/mac80211/ieee80211_sta.c 2008-02-23 14:51:27.000000000 +0100
+++ everything/net/mac80211/ieee80211_sta.c 2008-02-23 14:57:47.000000000 +0100
@@ -87,46 +87,8 @@ static int ieee80211_sta_config_auth(str
struct ieee80211_if_sta *ifsta);
-/* Parsed Information Elements */
-struct ieee802_11_elems {
- /* pointers to IEs */
- u8 *ssid;
- u8 *supp_rates;
- u8 *fh_params;
- u8 *ds_params;
- u8 *cf_params;
- u8 *tim;
- u8 *ibss_params;
- u8 *challenge;
- u8 *wpa;
- u8 *rsn;
- u8 *erp_info;
- u8 *ext_supp_rates;
- u8 *wmm_info;
- u8 *wmm_param;
- u8 *ht_cap_elem;
- u8 *ht_info_elem;
- /* length of them, respectively */
- u8 ssid_len;
- u8 supp_rates_len;
- u8 fh_params_len;
- u8 ds_params_len;
- u8 cf_params_len;
- u8 tim_len;
- u8 ibss_params_len;
- u8 challenge_len;
- u8 wpa_len;
- u8 rsn_len;
- u8 erp_info_len;
- u8 ext_supp_rates_len;
- u8 wmm_info_len;
- u8 wmm_param_len;
- u8 ht_cap_elem_len;
- u8 ht_info_elem_len;
-};
-
-static void ieee802_11_parse_elems(u8 *start, size_t len,
- struct ieee802_11_elems *elems)
+void ieee802_11_parse_elems(u8 *start, size_t len,
+ struct ieee802_11_elems *elems)
{
size_t left = len;
u8 *pos = start;
@@ -215,6 +177,30 @@ static void ieee802_11_parse_elems(u8 *s
elems->ht_info_elem = pos;
elems->ht_info_elem_len = elen;
break;
+ case WLAN_EID_MESH_ID:
+ elems->mesh_id = pos;
+ elems->mesh_id_len = elen;
+ break;
+ case WLAN_EID_MESH_CONFIG:
+ elems->mesh_config = pos;
+ elems->mesh_config_len = elen;
+ break;
+ case WLAN_EID_PEER_LINK:
+ elems->peer_link = pos;
+ elems->peer_link_len = elen;
+ break;
+ case WLAN_EID_PREQ:
+ elems->preq = pos;
+ elems->preq_len = elen;
+ break;
+ case WLAN_EID_PREP:
+ elems->prep = pos;
+ elems->prep_len = elen;
+ break;
+ case WLAN_EID_PERR:
+ elems->perr = pos;
+ elems->perr_len = elen;
+ break;
default:
break;
}
@@ -501,8 +487,8 @@ static void ieee80211_set_disassoc(struc
ieee80211_set_associated(dev, ifsta, 0);
}
-static void ieee80211_sta_tx(struct net_device *dev, struct sk_buff *skb,
- int encrypt)
+void ieee80211_sta_tx(struct net_device *dev, struct sk_buff *skb,
+ int encrypt)
{
struct ieee80211_sub_if_data *sdata;
struct ieee80211_tx_packet_data *pkt_data;
--
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH 09/18] mac80211: mesh changes to the MLME
2008-02-23 14:17 [PATCH 00/18] mac80211 802.11s networking code Johannes Berg
` (7 preceding siblings ...)
2008-02-23 14:17 ` [PATCH 08/18] mac80211: mesh data structures and first mesh changes Johannes Berg
@ 2008-02-23 14:17 ` Johannes Berg
2008-02-23 14:17 ` [PATCH 10/18] mac80211: mesh peer link implementation Johannes Berg
` (8 subsequent siblings)
17 siblings, 0 replies; 29+ messages in thread
From: Johannes Berg @ 2008-02-23 14:17 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless, Luis Carlos Cobo
From: Luis Carlos Cobo <luisca@cozybit.com>
This includes support for mesh network scanning. The ugly code in
ieee80211_sta_scan_result() is my approach to work around wext. This has been
tested with wireless tools version 29 and works as expected (the new interface
mode is just not shown).
Signed-off-by: Luis Carlos Cobo <luisca@cozybit.com>
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
net/mac80211/ieee80211_sta.c | 322 +++++++++++++++++++++++++++++++++++--------
1 file changed, 263 insertions(+), 59 deletions(-)
--- everything.orig/net/mac80211/ieee80211_sta.c 2008-02-23 14:49:09.000000000 +0100
+++ everything/net/mac80211/ieee80211_sta.c 2008-02-23 14:50:13.000000000 +0100
@@ -31,12 +31,16 @@
#include "ieee80211_i.h"
#include "ieee80211_rate.h"
#include "ieee80211_led.h"
+#ifdef CONFIG_MAC80211_MESH
+#include "mesh.h"
+#endif
#define IEEE80211_AUTH_TIMEOUT (HZ / 5)
#define IEEE80211_AUTH_MAX_TRIES 3
#define IEEE80211_ASSOC_TIMEOUT (HZ / 5)
#define IEEE80211_ASSOC_MAX_TRIES 3
#define IEEE80211_MONITORING_INTERVAL (2 * HZ)
+#define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ)
#define IEEE80211_PROBE_INTERVAL (60 * HZ)
#define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ)
#define IEEE80211_SCAN_INTERVAL (2 * HZ)
@@ -49,6 +53,7 @@
#define IEEE80211_SCAN_RESULT_EXPIRE (10 * HZ)
#define IEEE80211_IBSS_MERGE_INTERVAL (30 * HZ)
#define IEEE80211_IBSS_INACTIVITY_LIMIT (60 * HZ)
+#define IEEE80211_MESH_PEER_INACTIVITY_LIMIT (1800 * HZ)
#define IEEE80211_IBSS_MAX_STA_ENTRIES 128
@@ -1890,8 +1895,15 @@ static void __ieee80211_rx_bss_hash_add(
struct ieee80211_sta_bss *bss)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- bss->hnext = local->sta_bss_hash[STA_HASH(bss->bssid)];
- local->sta_bss_hash[STA_HASH(bss->bssid)] = bss;
+ u8 hash_idx;
+#ifdef CONFIG_MAC80211_MESH
+ if (bss->mesh_cfg)
+ hash_idx = mesh_id_hash(bss->mesh_id, bss->mesh_id_len);
+ else
+#endif
+ hash_idx = STA_HASH(bss->bssid);
+ bss->hnext = local->sta_bss_hash[hash_idx];
+ local->sta_bss_hash[hash_idx] = bss;
}
@@ -1944,7 +1956,6 @@ ieee80211_rx_bss_add(struct net_device *
return bss;
}
-
static struct ieee80211_sta_bss *
ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int freq,
u8 *ssid, u8 ssid_len)
@@ -1955,7 +1966,7 @@ ieee80211_rx_bss_get(struct net_device *
spin_lock_bh(&local->sta_bss_lock);
bss = local->sta_bss_hash[STA_HASH(bssid)];
while (bss) {
- if (!memcmp(bss->bssid, bssid, ETH_ALEN) &&
+ if (!bss->mesh_cfg && !memcmp(bss->bssid, bssid, ETH_ALEN) &&
bss->freq == freq &&
bss->ssid_len == ssid_len &&
(ssid_len == 0 || !memcmp(bss->ssid, ssid, ssid_len))) {
@@ -1968,6 +1979,72 @@ ieee80211_rx_bss_get(struct net_device *
return bss;
}
+#ifdef CONFIG_MAC80211_MESH
+static struct ieee80211_sta_bss *
+ieee80211_rx_mesh_bss_get(struct net_device *dev, u8 *mesh_id, int mesh_id_len,
+ u8 *mesh_cfg, int freq)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sta_bss *bss;
+
+ spin_lock_bh(&local->sta_bss_lock);
+ bss = local->sta_bss_hash[mesh_id_hash(mesh_id, mesh_id_len)];
+ while (bss) {
+ if (bss->mesh_cfg &&
+ !memcmp(bss->mesh_cfg, mesh_cfg, MESH_CFG_CMP_LEN) &&
+ bss->freq == freq &&
+ mesh_id_len == bss->mesh_id_len &&
+ (mesh_id_len == 0 || !memcmp(bss->mesh_id, mesh_id,
+ mesh_id_len))) {
+ atomic_inc(&bss->users);
+ break;
+ }
+ bss = bss->hnext;
+ }
+ spin_unlock_bh(&local->sta_bss_lock);
+ return bss;
+}
+
+static struct ieee80211_sta_bss *
+ieee80211_rx_mesh_bss_add(struct net_device *dev, u8 *mesh_id, int mesh_id_len,
+ u8 *mesh_cfg, int freq)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sta_bss *bss;
+
+ bss = kzalloc(sizeof(*bss), GFP_ATOMIC);
+ if (!bss)
+ return NULL;
+
+ bss->mesh_cfg = kmalloc(MESH_CFG_CMP_LEN, GFP_ATOMIC);
+ if (!bss->mesh_cfg) {
+ kfree(bss);
+ return NULL;
+ }
+
+ if (mesh_id_len && mesh_id_len <= IEEE80211_MAX_MESH_ID_LEN) {
+ bss->mesh_id = kmalloc(mesh_id_len, GFP_ATOMIC);
+ if (!bss->mesh_id) {
+ kfree(bss->mesh_cfg);
+ kfree(bss);
+ return NULL;
+ }
+ memcpy(bss->mesh_id, mesh_id, mesh_id_len);
+ }
+
+ atomic_inc(&bss->users);
+ atomic_inc(&bss->users);
+ memcpy(bss->mesh_cfg, mesh_cfg, MESH_CFG_CMP_LEN);
+ bss->mesh_id_len = mesh_id_len;
+ bss->freq = freq;
+ spin_lock_bh(&local->sta_bss_lock);
+ /* TODO: order by RSSI? */
+ list_add_tail(&bss->list, &local->sta_bss_list);
+ __ieee80211_rx_bss_hash_add(dev, bss);
+ spin_unlock_bh(&local->sta_bss_lock);
+ return bss;
+}
+#endif
static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss)
{
@@ -1975,6 +2052,10 @@ static void ieee80211_rx_bss_free(struct
kfree(bss->rsn_ie);
kfree(bss->wmm_ie);
kfree(bss->ht_ie);
+#ifdef CONFIG_MAC80211_MESH
+ kfree(bss->mesh_id);
+ kfree(bss->mesh_cfg);
+#endif
kfree(bss);
}
@@ -2170,6 +2251,42 @@ static int ieee80211_sta_join_ibss(struc
return res;
}
+u64 ieee80211_sta_get_rates(struct ieee80211_local *local,
+ struct ieee802_11_elems *elems,
+ enum ieee80211_band band)
+{
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_rate *bitrates;
+ size_t num_rates;
+ u64 supp_rates;
+ int i, j;
+ sband = local->hw.wiphy->bands[band];
+
+ if (!sband) {
+ WARN_ON(1);
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+ }
+
+ bitrates = sband->bitrates;
+ num_rates = sband->n_bitrates;
+ supp_rates = 0;
+ for (i = 0; i < elems->supp_rates_len +
+ elems->ext_supp_rates_len; i++) {
+ u8 rate = 0;
+ int own_rate;
+ if (i < elems->supp_rates_len)
+ rate = elems->supp_rates[i];
+ else if (elems->ext_supp_rates)
+ rate = elems->ext_supp_rates
+ [i - elems->supp_rates_len];
+ own_rate = 5 * (rate & 0x7f);
+ for (j = 0; j < num_rates; j++)
+ if (bitrates[j].bitrate == own_rate)
+ supp_rates |= BIT(j);
+ }
+ return supp_rates;
+}
+
static void ieee80211_rx_bss_info(struct net_device *dev,
struct ieee80211_mgmt *mgmt,
@@ -2204,41 +2321,23 @@ static void ieee80211_rx_bss_info(struct
beacon_timestamp = le64_to_cpu(mgmt->u.beacon.timestamp);
ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems);
+#ifdef CONFIG_MAC80211_MESH
+ if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT && elems.mesh_id
+ && elems.mesh_config)
+ if (mesh_matches_local(&elems, dev)) {
+ u64 rates = ieee80211_sta_get_rates(local, &elems,
+ rx_status->band);
+ mesh_neighbour_update(mgmt->sa, rates, dev,
+ mesh_peer_accepts_plinks(&elems, dev));
+ }
+#endif
+
if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && elems.supp_rates &&
memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0 &&
(sta = sta_info_get(local, mgmt->sa))) {
- struct ieee80211_supported_band *sband;
- struct ieee80211_rate *bitrates;
- size_t num_rates;
- u64 supp_rates, prev_rates;
- int i, j;
-
- sband = local->hw.wiphy->bands[rx_status->band];
-
- if (!sband) {
- WARN_ON(1);
- sband = local->hw.wiphy->bands[
- local->hw.conf.channel->band];
- }
-
- bitrates = sband->bitrates;
- num_rates = sband->n_bitrates;
-
- supp_rates = 0;
- for (i = 0; i < elems.supp_rates_len +
- elems.ext_supp_rates_len; i++) {
- u8 rate = 0;
- int own_rate;
- if (i < elems.supp_rates_len)
- rate = elems.supp_rates[i];
- else if (elems.ext_supp_rates)
- rate = elems.ext_supp_rates
- [i - elems.supp_rates_len];
- own_rate = 5 * (rate & 0x7f);
- for (j = 0; j < num_rates; j++)
- if (bitrates[j].bitrate == own_rate)
- supp_rates |= BIT(j);
- }
+ u64 prev_rates;
+ u64 supp_rates = ieee80211_sta_get_rates(local, &elems,
+ rx_status->band);
prev_rates = sta->supp_rates[rx_status->band];
sta->supp_rates[rx_status->band] &= supp_rates;
@@ -2261,19 +2360,28 @@ static void ieee80211_rx_bss_info(struct
sta_info_put(sta);
}
- if (!elems.ssid)
- return;
-
if (elems.ds_params && elems.ds_params_len == 1)
freq = ieee80211_channel_to_frequency(elems.ds_params[0]);
else
freq = rx_status->freq;
- bss = ieee80211_rx_bss_get(dev, mgmt->bssid, freq,
- elems.ssid, elems.ssid_len);
- if (!bss) {
- bss = ieee80211_rx_bss_add(dev, mgmt->bssid, freq,
+#ifdef CONFIG_MAC80211_MESH
+ if (elems.mesh_config)
+ bss = ieee80211_rx_mesh_bss_get(dev, elems.mesh_id,
+ elems.mesh_id_len, elems.mesh_config, freq);
+ else
+#endif
+ bss = ieee80211_rx_bss_get(dev, mgmt->bssid, freq,
elems.ssid, elems.ssid_len);
+ if (!bss) {
+#ifdef CONFIG_MAC80211_MESH
+ if (elems.mesh_config)
+ bss = ieee80211_rx_mesh_bss_add(dev, elems.mesh_id,
+ elems.mesh_id_len, elems.mesh_config, freq);
+ else
+#endif
+ bss = ieee80211_rx_bss_add(dev, mgmt->bssid, freq,
+ elems.ssid, elems.ssid_len);
if (!bss)
return;
} else {
@@ -2600,8 +2708,13 @@ static void ieee80211_rx_mgmt_probe_req(
static void ieee80211_rx_mgmt_action(struct net_device *dev,
struct ieee80211_if_sta *ifsta,
struct ieee80211_mgmt *mgmt,
- size_t len)
+ size_t len,
+ struct ieee80211_rx_status *rx_status)
{
+#ifdef CONFIG_MAC80211_MESH
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+#endif
+
if (len < IEEE80211_MIN_ACTION_SIZE)
return;
@@ -2633,7 +2746,21 @@ static void ieee80211_rx_mgmt_action(str
break;
}
break;
+#ifdef CONFIG_MAC80211_MESH
+ case PLINK_CATEGORY:
+ if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT)
+ mesh_rx_plink_frame(dev, mgmt, len, rx_status);
+ break;
+
+ case MESH_PATH_SEL_CATEGORY:
+ if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT)
+ mesh_rx_path_sel_frame(dev, mgmt, len);
+ break;
+#endif
default:
+ if (net_ratelimit())
+ printk(KERN_DEBUG "%s: Rx unknown action frame - "
+ "category=%d\n", dev->name, mgmt->u.action.category);
break;
}
}
@@ -2660,13 +2787,13 @@ void ieee80211_sta_rx_mgmt(struct net_de
case IEEE80211_STYPE_PROBE_REQ:
case IEEE80211_STYPE_PROBE_RESP:
case IEEE80211_STYPE_BEACON:
+ case IEEE80211_STYPE_ACTION:
memcpy(skb->cb, rx_status, sizeof(*rx_status));
case IEEE80211_STYPE_AUTH:
case IEEE80211_STYPE_ASSOC_RESP:
case IEEE80211_STYPE_REASSOC_RESP:
case IEEE80211_STYPE_DEAUTH:
case IEEE80211_STYPE_DISASSOC:
- case IEEE80211_STYPE_ACTION:
skb_queue_tail(&ifsta->skb_queue, skb);
queue_work(local->hw.workqueue, &ifsta->work);
return;
@@ -2725,7 +2852,7 @@ static void ieee80211_sta_rx_queued_mgmt
ieee80211_rx_mgmt_disassoc(dev, ifsta, mgmt, skb->len);
break;
case IEEE80211_STYPE_ACTION:
- ieee80211_rx_mgmt_action(dev, ifsta, mgmt, skb->len);
+ ieee80211_rx_mgmt_action(dev, ifsta, mgmt, skb->len, rx_status);
break;
}
@@ -2790,7 +2917,7 @@ static int ieee80211_sta_active_ibss(str
}
-static void ieee80211_sta_expire(struct net_device *dev)
+static void ieee80211_sta_expire(struct net_device *dev, unsigned long exp_time)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct sta_info *sta, *tmp;
@@ -2799,8 +2926,7 @@ static void ieee80211_sta_expire(struct
write_lock_bh(&local->sta_lock);
list_for_each_entry_safe(sta, tmp, &local->sta_list, list)
- if (time_after(jiffies, sta->last_rx +
- IEEE80211_IBSS_INACTIVITY_LIMIT)) {
+ if (time_after(jiffies, sta->last_rx + exp_time)) {
printk(KERN_DEBUG "%s: expiring inactive STA %s\n",
dev->name, print_mac(mac, sta->addr));
__sta_info_get(sta);
@@ -2821,7 +2947,7 @@ static void ieee80211_sta_merge_ibss(str
{
mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL);
- ieee80211_sta_expire(dev);
+ ieee80211_sta_expire(dev, IEEE80211_IBSS_INACTIVITY_LIMIT);
if (ieee80211_sta_active_ibss(dev))
return;
@@ -2831,6 +2957,36 @@ static void ieee80211_sta_merge_ibss(str
}
+#ifdef CONFIG_MAC80211_MESH
+static void ieee80211_mesh_housekeeping(struct net_device *dev,
+ struct ieee80211_if_sta *ifsta)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ bool free_plinks;
+
+ ieee80211_sta_expire(dev, IEEE80211_MESH_PEER_INACTIVITY_LIMIT);
+ mesh_path_expire(dev);
+
+ free_plinks = mesh_plink_availables(sdata);
+ if (free_plinks != sdata->u.sta.accepting_plinks)
+ ieee80211_if_config_beacon(dev);
+
+ mod_timer(&ifsta->timer, jiffies +
+ IEEE80211_MESH_HOUSEKEEPING_INTERVAL);
+}
+
+
+void ieee80211_start_mesh(struct net_device *dev)
+{
+ struct ieee80211_if_sta *ifsta;
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ ifsta = &sdata->u.sta;
+ ifsta->state = IEEE80211_MESH_UP;
+ ieee80211_sta_timer((unsigned long)sdata);
+}
+#endif
+
+
void ieee80211_sta_timer(unsigned long data)
{
struct ieee80211_sub_if_data *sdata =
@@ -2842,7 +2998,6 @@ void ieee80211_sta_timer(unsigned long d
queue_work(local->hw.workqueue, &ifsta->work);
}
-
void ieee80211_sta_work(struct work_struct *work)
{
struct ieee80211_sub_if_data *sdata =
@@ -2859,7 +3014,8 @@ void ieee80211_sta_work(struct work_stru
return;
if (sdata->vif.type != IEEE80211_IF_TYPE_STA &&
- sdata->vif.type != IEEE80211_IF_TYPE_IBSS) {
+ sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
+ sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT) {
printk(KERN_DEBUG "%s: ieee80211_sta_work: non-STA interface "
"(type=%d)\n", dev->name, sdata->vif.type);
return;
@@ -2869,6 +3025,12 @@ void ieee80211_sta_work(struct work_stru
while ((skb = skb_dequeue(&ifsta->skb_queue)))
ieee80211_sta_rx_queued_mgmt(dev, skb);
+#ifdef CONFIG_MAC80211_MESH
+ if (ifsta->preq_queue_len && time_after(jiffies, ifsta->last_preq +
+ msecs_to_jiffies(ifsta->mshcfg.dot11MeshHWMPpreqMinInterval)))
+ mesh_path_start_discovery(dev);
+#endif
+
if (ifsta->state != IEEE80211_AUTHENTICATE &&
ifsta->state != IEEE80211_ASSOCIATE &&
test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request)) {
@@ -2904,6 +3066,11 @@ void ieee80211_sta_work(struct work_stru
case IEEE80211_IBSS_JOINED:
ieee80211_sta_merge_ibss(dev, ifsta);
break;
+#ifdef CONFIG_MAC80211_MESH
+ case IEEE80211_MESH_UP:
+ ieee80211_mesh_housekeeping(dev, ifsta);
+ break;
+#endif
default:
printk(KERN_DEBUG "ieee80211_sta_work: Unknown state %d\n",
ifsta->state);
@@ -3108,7 +3275,7 @@ static int ieee80211_sta_create_ibss(str
sband = local->hw.wiphy->bands[bss->band];
if (local->hw.conf.beacon_int == 0)
- local->hw.conf.beacon_int = 100;
+ local->hw.conf.beacon_int = 10000;
bss->beacon_int = local->hw.conf.beacon_int;
bss->last_update = jiffies;
bss->capability = WLAN_CAPABILITY_IBSS;
@@ -3397,6 +3564,9 @@ void ieee80211_scan_completed(struct iee
ieee80211_sta_timer((unsigned long)sdata);
}
+ if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT)
+ ieee80211_sta_timer((unsigned long)sdata);
+
netif_wake_queue(sdata->dev);
}
rcu_read_unlock();
@@ -3639,15 +3809,27 @@ ieee80211_sta_scan_result(struct net_dev
memset(&iwe, 0, sizeof(iwe));
iwe.cmd = SIOCGIWESSID;
- iwe.u.data.length = bss->ssid_len;
- iwe.u.data.flags = 1;
- current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
- bss->ssid);
+ if (bss->mesh_cfg) {
+#ifdef CONFIG_MAC80211_MESH
+ iwe.u.data.length = bss->mesh_id_len;
+ iwe.u.data.flags = 1;
+ current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
+ bss->mesh_id);
+#endif
+ } else {
+ iwe.u.data.length = bss->ssid_len;
+ iwe.u.data.flags = 1;
+ current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
+ bss->ssid);
+ }
- if (bss->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
+ if (bss->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS
+ || bss->mesh_cfg)) {
memset(&iwe, 0, sizeof(iwe));
iwe.cmd = SIOCGIWMODE;
- if (bss->capability & WLAN_CAPABILITY_ESS)
+ if (bss->mesh_cfg)
+ iwe.u.mode = IW_MODE_MESH;
+ else if (bss->capability & WLAN_CAPABILITY_ESS)
iwe.u.mode = IW_MODE_MASTER;
else
iwe.u.mode = IW_MODE_ADHOC;
@@ -3736,6 +3918,28 @@ ieee80211_sta_scan_result(struct net_dev
}
}
+ if (bss->mesh_cfg) {
+ char *buf;
+ u8 *cfg = bss->mesh_cfg;
+ buf = kmalloc(200, GFP_ATOMIC);
+ if (buf) {
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = IWEVCUSTOM;
+ sprintf(buf, "Mesh network (version %d)\n"
+ "\t\t\tPath Selection Protocol ID: 0x%02X%02X%02X%02X\n"
+ "\t\t\tPath Selection Metric ID: 0x%02X%02X%02X%02X\n"
+ "\t\t\tCongestion Control Mode ID: 0x%02X%02X%02X%02X\n"
+ "\t\t\tChannel Precedence: 0x%02X%02X%02X%02X",
+ cfg[0], cfg[1], cfg[2], cfg[3], cfg[4], cfg[5], cfg[6],
+ cfg[7], cfg[8], cfg[9], cfg[10], cfg[11], cfg[12],
+ cfg[13], cfg[14], cfg[15], cfg[16]);
+ iwe.u.data.length = strlen(buf);
+ current_ev = iwe_stream_add_point(current_ev, end_buf,
+ &iwe, buf);
+ kfree(buf);
+ }
+ }
+
return current_ev;
}
--
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH 10/18] mac80211: mesh peer link implementation
2008-02-23 14:17 [PATCH 00/18] mac80211 802.11s networking code Johannes Berg
` (8 preceding siblings ...)
2008-02-23 14:17 ` [PATCH 09/18] mac80211: mesh changes to the MLME Johannes Berg
@ 2008-02-23 14:17 ` Johannes Berg
2008-02-23 14:17 ` [PATCH 11/18] mac80211: mesh path table implementation Johannes Berg
` (7 subsequent siblings)
17 siblings, 0 replies; 29+ messages in thread
From: Johannes Berg @ 2008-02-23 14:17 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless, Luis Carlos Cobo
From: Luis Carlos Cobo <luisca@cozybit.com>
This file implements mesh discovery and peer link establishment support using
the mesh peer link table provided in mesh_plinktbl.c.
Secure peer links have not been implemented yet.
Signed-off-by: Luis Carlos Cobo <luisca@cozybit.com>
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
net/mac80211/mesh_plink.c | 755 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 755 insertions(+)
create mode 100644 net/mac80211/mesh_plink.c
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ everything/net/mac80211/mesh_plink.c 2008-02-23 14:38:26.000000000 +0100
@@ -0,0 +1,755 @@
+/*
+ * Copyright (c) 2008 open80211s Ltd.
+ * Author: Luis Carlos Cobo <luisca@cozybit.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "ieee80211_i.h"
+#include "ieee80211_rate.h"
+#include "mesh.h"
+#include <linux/random.h>
+
+#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
+#define mpl_dbg(fmt, args...) printk(KERN_DEBUG fmt, ##args)
+#else
+#define mpl_dbg(fmt, args...) do { (void)(0); } while (0)
+#endif
+
+#define IEEE80211_FC(type, stype) cpu_to_le16(type | stype)
+#define PLINK_GET_FRAME_SUBTYPE(p) (p)
+#define PLINK_GET_LLID(p) (p + 1)
+#define PLINK_GET_PLID(p) (p + 3)
+
+#define mod_plink_timer(s, t) (mod_timer(&s->plink_timer, \
+ jiffies + HZ * t / 1000))
+
+/* Peer link cancel reasons, all subject to ANA approval */
+#define MESH_LINK_CANCELLED 2
+#define MESH_MAX_NEIGHBORS 3
+#define MESH_CAPABILITY_POLICY_VIOLATION 4
+#define MESH_CLOSE_RCVD 5
+#define MESH_MAX_RETRIES 6
+#define MESH_CONFIRM_TIMEOUT 7
+#define MESH_SECURITY_ROLE_NEGOTIATION_DIFFERS 8
+#define MESH_SECURITY_AUTHENTICATION_IMPOSSIBLE 9
+#define MESH_SECURITY_FAILED_VERIFICATION 10
+
+#define dot11MeshMaxRetries(s) (s->u.sta.mshcfg.dot11MeshMaxRetries)
+#define dot11MeshRetryTimeout(s) (s->u.sta.mshcfg.dot11MeshRetryTimeout)
+#define dot11MeshConfirmTimeout(s) (s->u.sta.mshcfg.dot11MeshConfirmTimeout)
+#define dot11MeshHoldingTimeout(s) (s->u.sta.mshcfg.dot11MeshHoldingTimeout)
+#define dot11MeshMaxPeerLinks(s) (s->u.sta.mshcfg.dot11MeshMaxPeerLinks)
+
+enum plink_frame_type {
+ PLINK_OPEN = 0,
+ PLINK_CONFIRM,
+ PLINK_CLOSE
+};
+
+enum plink_event {
+ PLINK_UNDEFINED,
+ OPN_ACPT,
+ OPN_RJCT,
+ OPN_IGNR,
+ CNF_ACPT,
+ CNF_RJCT,
+ CNF_IGNR,
+ CLS_ACPT,
+ CLS_IGNR
+};
+
+static inline
+void mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata)
+{
+ atomic_inc(&sdata->u.sta.mshstats.estab_plinks);
+ mesh_accept_plinks_update(sdata->dev);
+}
+
+static inline
+void mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata)
+{
+ atomic_dec(&sdata->u.sta.mshstats.estab_plinks);
+ mesh_accept_plinks_update(sdata->dev);
+}
+
+/**
+ * mesh_plink_fsm_restart - restart a mesh peer link finite state machine
+ *
+ * @sta: mes peer link to restart
+ *
+ * Locking: this function must be called holding sta->plink_lock
+ */
+static inline void mesh_plink_fsm_restart(struct sta_info *sta)
+{
+ sta->plink_state = LISTEN;
+ sta->llid = sta->plid = sta->reason = sta->plink_retries = 0;
+}
+
+/**
+ * mesh_plink_add - allocate and add a new mesh peer link
+ *
+ * @hw_addr: hardware address (ETH_ALEN length)
+ * @rates: rates the mesh peer supports
+ * @dev: local mesh interface
+ *
+ * The initial state of the new plink is set to LISTEN
+ *
+ * Returns: non-NULL on success, ERR_PTR() on error.
+ */
+struct sta_info *mesh_plink_add(u8 *hw_addr, u64 rates, struct net_device *dev)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct sta_info *sta;
+
+ if (memcmp(hw_addr, dev->dev_addr, ETH_ALEN) == 0)
+ /* never add ourselves as neighbours */
+ return ERR_PTR(-EINVAL);
+
+ if (is_multicast_ether_addr(hw_addr))
+ return ERR_PTR(-EINVAL);
+
+ if (local->num_sta >= MESH_MAX_PLINKS)
+ return ERR_PTR(-ENOSPC);
+
+ sta = sta_info_add(local, dev, hw_addr, GFP_KERNEL);
+ if (IS_ERR(sta))
+ return sta;
+
+ sta->plink_state = LISTEN;
+ spin_lock_init(&sta->plink_lock);
+ init_timer(&sta->plink_timer);
+ sta->flags |= WLAN_STA_AUTHORIZED;
+ sta->supp_rates[local->hw.conf.channel->band] = rates;
+ rate_control_rate_init(sta, local);
+
+ mesh_accept_plinks_update(dev);
+
+ return sta;
+}
+
+/**
+ * mesh_plink_deactivate - deactivate mesh peer link
+ *
+ * @sta: mesh peer link to deactivate
+ *
+ * All mesh paths with this peer as next hop will be flushed
+ *
+ * Locking: the caller must hold sta->plink_lock
+ */
+void mesh_plink_deactivate(struct sta_info *sta)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
+ if (sta->plink_state == ESTAB)
+ mesh_plink_dec_estab_count(sdata);
+ sta->plink_state = BLOCKED;
+ mesh_path_flush_by_nexthop(sta);
+}
+
+static int mesh_plink_frame_tx(struct net_device *dev,
+ enum plink_frame_type action, u8 *da, __le16 llid, __le16 plid,
+ __le16 reason) {
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
+ struct ieee80211_mgmt *mgmt;
+ bool include_plid = false;
+ u8 *pos;
+ int ie_len;
+
+ if (!skb)
+ return -1;
+ skb_reserve(skb, local->hw.extra_tx_headroom);
+ /* 25 is the size of the common mgmt part (24) plus the size of the
+ * common action part (1)
+ */
+ mgmt = (struct ieee80211_mgmt *)
+ skb_put(skb, 25 + sizeof(mgmt->u.action.u.plink_action));
+ memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.plink_action));
+ mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+ IEEE80211_STYPE_ACTION);
+ memcpy(mgmt->da, da, ETH_ALEN);
+ memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
+ /* BSSID is left zeroed, wildcard value */
+ mgmt->u.action.category = PLINK_CATEGORY;
+ mgmt->u.action.u.plink_action.action_code = action;
+
+ if (action == PLINK_CLOSE)
+ mgmt->u.action.u.plink_action.aux = reason;
+ else {
+ mgmt->u.action.u.plink_action.aux = cpu_to_le16(0x0);
+ if (action == PLINK_CONFIRM) {
+ pos = skb_put(skb, 4);
+ /* two-byte status code followed by two-byte AID */
+ memset(pos, 0, 4);
+ }
+ mesh_mgmt_ies_add(skb, dev);
+ }
+
+ /* Add Peer Link Management element */
+ switch (action) {
+ case PLINK_OPEN:
+ ie_len = 3;
+ break;
+ case PLINK_CONFIRM:
+ ie_len = 5;
+ include_plid = true;
+ break;
+ case PLINK_CLOSE:
+ default:
+ if (!plid)
+ ie_len = 5;
+ else {
+ ie_len = 7;
+ include_plid = true;
+ }
+ break;
+ }
+
+ pos = skb_put(skb, 2 + ie_len);
+ *pos++ = WLAN_EID_PEER_LINK;
+ *pos++ = ie_len;
+ *pos++ = action;
+ memcpy(pos, &llid, 2);
+ if (include_plid) {
+ pos += 2;
+ memcpy(pos, &plid, 2);
+ }
+ if (action == PLINK_CLOSE) {
+ pos += 2;
+ memcpy(pos, &reason, 2);
+ }
+
+ ieee80211_sta_tx(dev, skb, 0);
+ return 0;
+}
+
+void mesh_neighbour_update(u8 *hw_addr, u64 rates, struct net_device *dev,
+ bool peer_accepting_plinks)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct sta_info *sta;
+
+ sta = sta_info_get(local, hw_addr);
+ if (!sta) {
+ sta = mesh_plink_add(hw_addr, rates, dev);
+ if (IS_ERR(sta))
+ return;
+ }
+
+ sta->last_rx = jiffies;
+ sta->supp_rates[local->hw.conf.channel->band] = rates;
+ if (peer_accepting_plinks && sta->plink_state == LISTEN &&
+ sdata->u.sta.accepting_plinks &&
+ sdata->u.sta.mshcfg.auto_open_plinks)
+ mesh_plink_open(sta);
+
+ sta_info_put(sta);
+}
+
+static void mesh_plink_timer(unsigned long data)
+{
+ struct sta_info *sta;
+ __le16 llid, plid, reason;
+ struct net_device *dev = NULL;
+ struct ieee80211_sub_if_data *sdata;
+#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
+ DECLARE_MAC_BUF(mac);
+#endif
+
+ sta = (struct sta_info *) data;
+
+ spin_lock_bh(&sta->plink_lock);
+ if (sta->ignore_plink_timer) {
+ sta->ignore_plink_timer = false;
+ spin_unlock_bh(&sta->plink_lock);
+ return;
+ }
+ mpl_dbg("Mesh plink timer for %s fired on state %d\n",
+ print_mac(mac, sta->addr), sta->plink_state);
+ reason = 0;
+ llid = sta->llid;
+ plid = sta->plid;
+ dev = sta->dev;
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ switch (sta->plink_state) {
+ case OPN_RCVD:
+ case OPN_SNT:
+ /* retry timer */
+ if (sta->plink_retries < dot11MeshMaxRetries(sdata)) {
+ u32 rand;
+ mpl_dbg("Mesh plink for %s (retry, timeout): %d %d\n",
+ print_mac(mac, sta->addr),
+ sta->plink_retries, sta->plink_timeout);
+ get_random_bytes(&rand, sizeof(u32));
+ sta->plink_timeout = sta->plink_timeout +
+ rand % sta->plink_timeout;
+ ++sta->plink_retries;
+ if (!mod_plink_timer(sta, sta->plink_timeout))
+ __sta_info_get(sta);
+ spin_unlock_bh(&sta->plink_lock);
+ mesh_plink_frame_tx(dev, PLINK_OPEN, sta->addr, llid,
+ 0, 0);
+ break;
+ }
+ reason = cpu_to_le16(MESH_MAX_RETRIES);
+ /* fall through on else */
+ case CNF_RCVD:
+ /* confirm timer */
+ if (!reason)
+ reason = cpu_to_le16(MESH_CONFIRM_TIMEOUT);
+ sta->plink_state = HOLDING;
+ if (!mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)))
+ __sta_info_get(sta);
+ spin_unlock_bh(&sta->plink_lock);
+ mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, plid,
+ reason);
+ break;
+ case HOLDING:
+ /* holding timer */
+ if (del_timer(&sta->plink_timer))
+ sta_info_put(sta);
+ mesh_plink_fsm_restart(sta);
+ spin_unlock_bh(&sta->plink_lock);
+ break;
+ default:
+ spin_unlock_bh(&sta->plink_lock);
+ break;
+ }
+
+ sta_info_put(sta);
+}
+
+static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout)
+{
+ sta->plink_timer.expires = jiffies + (HZ * timeout / 1000);
+ sta->plink_timer.data = (unsigned long) sta;
+ sta->plink_timer.function = mesh_plink_timer;
+ sta->plink_timeout = timeout;
+ __sta_info_get(sta);
+ add_timer(&sta->plink_timer);
+}
+
+int mesh_plink_open(struct sta_info *sta)
+{
+ __le16 llid;
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
+#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
+ DECLARE_MAC_BUF(mac);
+#endif
+
+ spin_lock_bh(&sta->plink_lock);
+ get_random_bytes(&llid, 2);
+ sta->llid = llid;
+ if (sta->plink_state != LISTEN) {
+ spin_unlock_bh(&sta->plink_lock);
+ sta_info_put(sta);
+ return -EBUSY;
+ }
+ sta->plink_state = OPN_SNT;
+ mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata));
+ spin_unlock_bh(&sta->plink_lock);
+ mpl_dbg("Mesh plink: starting establishment with %s\n",
+ print_mac(mac, sta->addr));
+
+ return mesh_plink_frame_tx(sta->dev, PLINK_OPEN, sta->addr, llid, 0, 0);
+}
+
+void mesh_plink_block(struct sta_info *sta)
+{
+#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
+ DECLARE_MAC_BUF(mac);
+#endif
+
+ spin_lock_bh(&sta->plink_lock);
+ mesh_plink_deactivate(sta);
+ sta->plink_state = BLOCKED;
+ spin_unlock_bh(&sta->plink_lock);
+}
+
+int mesh_plink_close(struct sta_info *sta)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
+ int llid, plid, reason;
+#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
+ DECLARE_MAC_BUF(mac);
+#endif
+
+ mpl_dbg("Mesh plink: closing link with %s\n",
+ print_mac(mac, sta->addr));
+ spin_lock_bh(&sta->plink_lock);
+ sta->reason = cpu_to_le16(MESH_LINK_CANCELLED);
+ reason = sta->reason;
+
+ if (sta->plink_state == LISTEN || sta->plink_state == BLOCKED) {
+ mesh_plink_fsm_restart(sta);
+ spin_unlock_bh(&sta->plink_lock);
+ sta_info_put(sta);
+ return 0;
+ } else if (sta->plink_state == ESTAB) {
+ mesh_plink_deactivate(sta);
+ /* The timer should not be running */
+ if (!mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)))
+ __sta_info_get(sta);
+ } else if (!mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)))
+ sta->ignore_plink_timer = true;
+
+ sta->plink_state = HOLDING;
+ llid = sta->llid;
+ plid = sta->plid;
+ spin_unlock_bh(&sta->plink_lock);
+ mesh_plink_frame_tx(sta->dev, PLINK_CLOSE, sta->addr, llid, plid,
+ reason);
+ return 0;
+}
+
+void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
+ size_t len, struct ieee80211_rx_status *rx_status)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee802_11_elems elems;
+ struct sta_info *sta;
+ enum plink_event event;
+ enum plink_frame_type ftype;
+ size_t baselen;
+ u8 ie_len;
+ u8 *baseaddr;
+ __le16 plid, llid, reason;
+#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
+ DECLARE_MAC_BUF(mac);
+#endif
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ if (is_multicast_ether_addr(mgmt->da)) {
+ mpl_dbg("Mesh plink: ignore frame from multicast address");
+ return;
+ }
+
+ baseaddr = mgmt->u.action.u.plink_action.variable;
+ baselen = (u8 *) mgmt->u.action.u.plink_action.variable - (u8 *) mgmt;
+ if (mgmt->u.action.u.plink_action.action_code == PLINK_CONFIRM) {
+ baseaddr += 4;
+ baselen -= 4;
+ }
+ ieee802_11_parse_elems(baseaddr, len - baselen, &elems);
+ if (!elems.peer_link) {
+ mpl_dbg("Mesh plink: missing necessary peer link ie\n");
+ return;
+ }
+
+ ftype = *((u8 *)PLINK_GET_FRAME_SUBTYPE(elems.peer_link));
+ ie_len = elems.peer_link_len;
+ if ((ftype == PLINK_OPEN && ie_len != 3) ||
+ (ftype == PLINK_CONFIRM && ie_len != 5) ||
+ (ftype == PLINK_CLOSE && ie_len != 5 && ie_len != 7)) {
+ mpl_dbg("Mesh plink: incorrect plink ie length\n");
+ return;
+ }
+
+ if (ftype != PLINK_CLOSE && (!elems.mesh_id || !elems.mesh_config)) {
+ mpl_dbg("Mesh plink: missing necessary ie\n");
+ return;
+ }
+ /* Note the lines below are correct, the llid in the frame is the plid
+ * from the point of view of this host.
+ */
+ memcpy(&plid, PLINK_GET_LLID(elems.peer_link), 2);
+ if (ftype == PLINK_CONFIRM || (ftype == PLINK_CLOSE && ie_len == 7))
+ memcpy(&llid, PLINK_GET_PLID(elems.peer_link), 2);
+
+ sta = sta_info_get(local, mgmt->sa);
+ if (!sta && ftype != PLINK_OPEN) {
+ mpl_dbg("Mesh plink: cls or cnf from unknown peer\n");
+ return;
+ }
+
+ if (sta && sta->plink_state == BLOCKED) {
+ sta_info_put(sta);
+ return;
+ }
+
+ /* Now we will figure out the appropriate event... */
+ event = PLINK_UNDEFINED;
+ if (ftype != PLINK_CLOSE && (!mesh_matches_local(&elems, dev))) {
+ switch (ftype) {
+ case PLINK_OPEN:
+ event = OPN_RJCT;
+ break;
+ case PLINK_CONFIRM:
+ event = CNF_RJCT;
+ break;
+ case PLINK_CLOSE:
+ /* avoid warning */
+ break;
+ }
+ spin_lock_bh(&sta->plink_lock);
+ } else if (!sta) {
+ /* ftype == PLINK_OPEN */
+ u64 rates;
+ if (!mesh_plink_free_count(sdata)) {
+ mpl_dbg("Mesh plink error: no more free plinks\n");
+ return;
+ }
+
+ rates = ieee80211_sta_get_rates(local, &elems, rx_status->band);
+ sta = mesh_plink_add(mgmt->sa, rates, dev);
+ if (IS_ERR(sta)) {
+ mpl_dbg("Mesh plink error: plink table full\n");
+ return;
+ }
+ event = OPN_ACPT;
+ spin_lock_bh(&sta->plink_lock);
+ } else {
+ spin_lock_bh(&sta->plink_lock);
+ switch (ftype) {
+ case PLINK_OPEN:
+ if (!mesh_plink_free_count(sdata) ||
+ (sta->plid && sta->plid != plid))
+ event = OPN_IGNR;
+ else
+ event = OPN_ACPT;
+ break;
+ case PLINK_CONFIRM:
+ if (!mesh_plink_free_count(sdata) ||
+ (sta->llid != llid || sta->plid != plid))
+ event = CNF_IGNR;
+ else
+ event = CNF_ACPT;
+ break;
+ case PLINK_CLOSE:
+ if (sta->plink_state == ESTAB)
+ /* Do not check for llid or plid. This does not
+ * follow the standard but since multiple plinks
+ * per sta are not supported, it is necessary in
+ * order to avoid a livelock when MP A sees an
+ * establish peer link to MP B but MP B does not
+ * see it. This can be caused by a timeout in
+ * B's peer link establishment or B beign
+ * restarted.
+ */
+ event = CLS_ACPT;
+ else if (sta->plid != plid)
+ event = CLS_IGNR;
+ else if (ie_len == 7 && sta->llid != llid)
+ event = CLS_IGNR;
+ else
+ event = CLS_ACPT;
+ break;
+ default:
+ mpl_dbg("Mesh plink: unknown frame subtype\n");
+ spin_unlock_bh(&sta->plink_lock);
+ sta_info_put(sta);
+ return;
+ }
+ }
+
+ mpl_dbg("Mesh plink (peer, state, llid, plid, event): %s %d %d %d %d\n",
+ print_mac(mac, mgmt->sa), sta->plink_state,
+ __le16_to_cpu(sta->llid), __le16_to_cpu(sta->plid),
+ event);
+ reason = 0;
+ switch (sta->plink_state) {
+ /* spin_unlock as soon as state is updated at each case */
+ case LISTEN:
+ switch (event) {
+ case CLS_ACPT:
+ mesh_plink_fsm_restart(sta);
+ spin_unlock_bh(&sta->plink_lock);
+ break;
+ case OPN_ACPT:
+ sta->plink_state = OPN_RCVD;
+ sta->plid = plid;
+ get_random_bytes(&llid, 2);
+ sta->llid = llid;
+ mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata));
+ spin_unlock_bh(&sta->plink_lock);
+ mesh_plink_frame_tx(dev, PLINK_OPEN, sta->addr, llid,
+ 0, 0);
+ mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr,
+ llid, plid, 0);
+ break;
+ default:
+ spin_unlock_bh(&sta->plink_lock);
+ break;
+ }
+ break;
+
+ case OPN_SNT:
+ switch (event) {
+ case OPN_RJCT:
+ case CNF_RJCT:
+ reason = cpu_to_le16(MESH_CAPABILITY_POLICY_VIOLATION);
+ case CLS_ACPT:
+ if (!reason)
+ reason = cpu_to_le16(MESH_CLOSE_RCVD);
+ sta->reason = reason;
+ sta->plink_state = HOLDING;
+ if (!mod_plink_timer(sta,
+ dot11MeshHoldingTimeout(sdata)))
+ sta->ignore_plink_timer = true;
+
+ llid = sta->llid;
+ spin_unlock_bh(&sta->plink_lock);
+ mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid,
+ plid, reason);
+ break;
+ case OPN_ACPT:
+ /* retry timer is left untouched */
+ sta->plink_state = OPN_RCVD;
+ sta->plid = plid;
+ llid = sta->llid;
+ spin_unlock_bh(&sta->plink_lock);
+ mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid,
+ plid, 0);
+ break;
+ case CNF_ACPT:
+ sta->plink_state = CNF_RCVD;
+ if (!mod_plink_timer(sta,
+ dot11MeshConfirmTimeout(sdata)))
+ sta->ignore_plink_timer = true;
+
+ spin_unlock_bh(&sta->plink_lock);
+ break;
+ default:
+ spin_unlock_bh(&sta->plink_lock);
+ break;
+ }
+ break;
+
+ case OPN_RCVD:
+ switch (event) {
+ case OPN_RJCT:
+ case CNF_RJCT:
+ reason = cpu_to_le16(MESH_CAPABILITY_POLICY_VIOLATION);
+ case CLS_ACPT:
+ if (!reason)
+ reason = cpu_to_le16(MESH_CLOSE_RCVD);
+ sta->reason = reason;
+ sta->plink_state = HOLDING;
+ if (!mod_plink_timer(sta,
+ dot11MeshHoldingTimeout(sdata)))
+ sta->ignore_plink_timer = true;
+
+ llid = sta->llid;
+ spin_unlock_bh(&sta->plink_lock);
+ mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid,
+ plid, reason);
+ break;
+ case OPN_ACPT:
+ llid = sta->llid;
+ spin_unlock_bh(&sta->plink_lock);
+ mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid,
+ plid, 0);
+ break;
+ case CNF_ACPT:
+ if (del_timer(&sta->plink_timer))
+ sta_info_put(sta);
+ sta->plink_state = ESTAB;
+ mesh_plink_inc_estab_count(sdata);
+ spin_unlock_bh(&sta->plink_lock);
+ mpl_dbg("Mesh plink with %s ESTABLISHED\n",
+ print_mac(mac, sta->addr));
+ break;
+ default:
+ spin_unlock_bh(&sta->plink_lock);
+ break;
+ }
+ break;
+
+ case CNF_RCVD:
+ switch (event) {
+ case OPN_RJCT:
+ case CNF_RJCT:
+ reason = cpu_to_le16(MESH_CAPABILITY_POLICY_VIOLATION);
+ case CLS_ACPT:
+ if (!reason)
+ reason = cpu_to_le16(MESH_CLOSE_RCVD);
+ sta->reason = reason;
+ sta->plink_state = HOLDING;
+ if (!mod_plink_timer(sta,
+ dot11MeshHoldingTimeout(sdata)))
+ sta->ignore_plink_timer = true;
+
+ llid = sta->llid;
+ spin_unlock_bh(&sta->plink_lock);
+ mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid,
+ plid, reason);
+ case OPN_ACPT:
+ if (del_timer(&sta->plink_timer))
+ sta_info_put(sta);
+ sta->plink_state = ESTAB;
+ mesh_plink_inc_estab_count(sdata);
+ spin_unlock_bh(&sta->plink_lock);
+ mpl_dbg("Mesh plink with %s ESTABLISHED\n",
+ print_mac(mac, sta->addr));
+ mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid,
+ plid, 0);
+ break;
+ default:
+ spin_unlock_bh(&sta->plink_lock);
+ break;
+ }
+ break;
+
+ case ESTAB:
+ switch (event) {
+ case CLS_ACPT:
+ reason = cpu_to_le16(MESH_CLOSE_RCVD);
+ sta->reason = reason;
+ mesh_plink_deactivate(sta);
+ sta->plink_state = HOLDING;
+ llid = sta->llid;
+ if (!mod_plink_timer(sta,
+ dot11MeshHoldingTimeout(sdata)))
+ __sta_info_get(sta);
+ spin_unlock_bh(&sta->plink_lock);
+ mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid,
+ plid, reason);
+ break;
+ case OPN_ACPT:
+ llid = sta->llid;
+ spin_unlock_bh(&sta->plink_lock);
+ mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid,
+ plid, 0);
+ break;
+ default:
+ spin_unlock_bh(&sta->plink_lock);
+ break;
+ }
+ break;
+ case HOLDING:
+ switch (event) {
+ case CLS_ACPT:
+ if (del_timer(&sta->plink_timer)) {
+ sta->ignore_plink_timer = 1;
+ sta_info_put(sta);
+ }
+ mesh_plink_fsm_restart(sta);
+ spin_unlock_bh(&sta->plink_lock);
+ break;
+ case OPN_ACPT:
+ case CNF_ACPT:
+ case OPN_RJCT:
+ case CNF_RJCT:
+ llid = sta->llid;
+ reason = sta->reason;
+ spin_unlock_bh(&sta->plink_lock);
+ mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid,
+ plid, reason);
+ break;
+ default:
+ spin_unlock_bh(&sta->plink_lock);
+ }
+ break;
+ default:
+ /* should not get here, BLOCKED is dealt with at the beggining
+ * of the function
+ */
+ spin_unlock_bh(&sta->plink_lock);
+ break;
+ }
+ sta_info_put(sta);
+}
--
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH 11/18] mac80211: mesh path table implementation
2008-02-23 14:17 [PATCH 00/18] mac80211 802.11s networking code Johannes Berg
` (9 preceding siblings ...)
2008-02-23 14:17 ` [PATCH 10/18] mac80211: mesh peer link implementation Johannes Berg
@ 2008-02-23 14:17 ` Johannes Berg
2008-02-23 14:17 ` [PATCH 12/18] mac80211: code for on-demand Hybrid Wireless Mesh Protocol Johannes Berg
` (6 subsequent siblings)
17 siblings, 0 replies; 29+ messages in thread
From: Johannes Berg @ 2008-02-23 14:17 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless, Luis Carlos Cobo
From: Luis Carlos Cobo <luisca@cozybit.com>
The mesh path table associates destinations with the next hop to reach them. The
table is a hash of linked lists protected by rcu mechanisms. Every mesh path
contains a lock to protect the mesh path state.
Each outgoing mesh frame requires a look up into this table. Therefore, the
table it has been designed so it is not necessary to hold any lock to find the
appropriate next hop.
If the path is determined to be active within a rcu context we can safely
dereference mpath->next_hop->addr, since it holds a reference to the sta
next_hop. After a mesh path has been set active for the first time it next_hop
must always point to a valid sta. If this is not possible the mpath must be
deleted or replaced in a RCU safe fashion.
Signed-off-by: Luis Carlos Cobo <luisca@cozybit.com>
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
net/mac80211/mesh_pathtbl.c | 522 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 522 insertions(+)
create mode 100644 net/mac80211/mesh_pathtbl.c
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ everything/net/mac80211/mesh_pathtbl.c 2008-02-23 14:38:43.000000000 +0100
@@ -0,0 +1,522 @@
+/*
+ * Copyright (c) 2008 open80211s Ltd.
+ * Author: Luis Carlos Cobo <luisca@cozybit.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/list.h>
+#include <linux/netdevice.h>
+#include <linux/random.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <net/mac80211.h>
+#include "ieee80211_i.h"
+#include "mesh.h"
+
+/* There will be initially 2^INIT_PATHS_SIZE_ORDER buckets */
+#define INIT_PATHS_SIZE_ORDER 2
+
+/* Keep the mean chain length below this constant */
+#define MEAN_CHAIN_LEN 2
+
+#define MPATH_EXPIRED(mpath) ((mpath->flags & MESH_PATH_ACTIVE) && \
+ time_after(jiffies, mpath->exp_time) && \
+ !(mpath->flags & MESH_PATH_FIXED))
+
+struct mpath_node {
+ struct hlist_node list;
+ struct rcu_head rcu;
+ /* This indirection allows two different tables to point to the same
+ * mesh_path structure, useful when resizing
+ */
+ struct mesh_path *mpath;
+};
+
+static struct mesh_table *mesh_paths;
+
+/* This lock will have the grow table function as writer and add / delete nodes
+ * as readers. When reading the table (i.e. doing lookups) we are well protected
+ * by RCU
+ */
+static DEFINE_RWLOCK(pathtbl_resize_lock);
+
+/**
+ *
+ * mesh_path_assign_nexthop - update mesh path next hop
+ *
+ * @mpath: mesh path to update
+ * @sta: next hop to assign
+ *
+ * Locking: mpath->state_lock must be held when calling this function
+ */
+void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta)
+{
+ __sta_info_get(sta);
+ if (mpath->next_hop)
+ sta_info_put(mpath->next_hop);
+ mpath->next_hop = sta;
+}
+
+
+/**
+ * mesh_path_lookup - look up a path in the mesh path table
+ * @dst: hardware address (ETH_ALEN length) of destination
+ * @dev: local interface
+ *
+ * Returns: pointer to the mesh path structure, or NULL if not found
+ *
+ * Locking: must be called within a read rcu section.
+ */
+struct mesh_path *mesh_path_lookup(u8 *dst, struct net_device *dev)
+{
+ struct mesh_path *mpath;
+ struct hlist_node *n;
+ struct hlist_head *bucket;
+ struct mesh_table *tbl;
+ struct mpath_node *node;
+
+ tbl = rcu_dereference(mesh_paths);
+
+ bucket = &tbl->hash_buckets[mesh_table_hash(dst, dev, tbl)];
+ hlist_for_each_entry_rcu(node, n, bucket, list) {
+ mpath = node->mpath;
+ if (mpath->dev == dev &&
+ memcmp(dst, mpath->dst, ETH_ALEN) == 0) {
+ if (MPATH_EXPIRED(mpath)) {
+ spin_lock_bh(&mpath->state_lock);
+ if (MPATH_EXPIRED(mpath))
+ mpath->flags &= ~MESH_PATH_ACTIVE;
+ spin_unlock_bh(&mpath->state_lock);
+ }
+ return mpath;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * mesh_path_lookup_by_idx - look up a path in the mesh path table by its index
+ * @idx: index
+ * @dev: local interface
+ *
+ * Returns: pointer to the mesh path structure, or NULL if not found.
+ *
+ * Locking: must be called within a read rcu section.
+ */
+struct mesh_path *mesh_path_lookup_by_idx(int idx, struct net_device *dev)
+{
+ struct mpath_node *node;
+ struct hlist_node *p;
+ int i;
+ int j = 0;
+
+ for_each_mesh_entry(mesh_paths, p, node, i)
+ if (j++ == idx) {
+ if (MPATH_EXPIRED(node->mpath)) {
+ spin_lock_bh(&node->mpath->state_lock);
+ if (MPATH_EXPIRED(node->mpath))
+ node->mpath->flags &= ~MESH_PATH_ACTIVE;
+ spin_unlock_bh(&node->mpath->state_lock);
+ }
+ return node->mpath;
+ }
+
+ return NULL;
+}
+
+/**
+ * mesh_path_add - allocate and add a new path to the mesh path table
+ * @addr: destination address of the path (ETH_ALEN length)
+ * @dev: local interface
+ *
+ * Returns: 0 on sucess
+ *
+ * State: the initial state of the new path is set to 0
+ */
+int mesh_path_add(u8 *dst, struct net_device *dev)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct mesh_path *mpath, *new_mpath;
+ struct mpath_node *node, *new_node;
+ struct hlist_head *bucket;
+ struct hlist_node *n;
+ int grow = 0;
+ int err = 0;
+ u32 hash_idx;
+
+ if (memcmp(dst, dev->dev_addr, ETH_ALEN) == 0)
+ /* never add ourselves as neighbours */
+ return -ENOTSUPP;
+
+ if (is_multicast_ether_addr(dst))
+ return -ENOTSUPP;
+
+ if (atomic_add_unless(&sdata->u.sta.mpaths, 1, MESH_MAX_MPATHS) == 0)
+ return -ENOSPC;
+
+ read_lock(&pathtbl_resize_lock);
+
+ new_mpath = kzalloc(sizeof(struct mesh_path), GFP_KERNEL);
+ if (!new_mpath) {
+ atomic_dec(&sdata->u.sta.mpaths);
+ err = -ENOMEM;
+ goto endadd2;
+ }
+ memcpy(new_mpath->dst, dst, ETH_ALEN);
+ new_mpath->dev = dev;
+ new_mpath->flags = 0;
+ skb_queue_head_init(&new_mpath->frame_queue);
+ new_node = kmalloc(sizeof(struct mpath_node), GFP_KERNEL);
+ new_node->mpath = new_mpath;
+ new_mpath->timer.data = (unsigned long) new_mpath;
+ new_mpath->timer.function = mesh_path_timer;
+ new_mpath->exp_time = jiffies;
+ spin_lock_init(&new_mpath->state_lock);
+ init_timer(&new_mpath->timer);
+
+ hash_idx = mesh_table_hash(dst, dev, mesh_paths);
+ bucket = &mesh_paths->hash_buckets[hash_idx];
+
+ spin_lock(&mesh_paths->hashwlock[hash_idx]);
+
+ hlist_for_each_entry(node, n, bucket, list) {
+ mpath = node->mpath;
+ if (mpath->dev == dev && memcmp(dst, mpath->dst, ETH_ALEN)
+ == 0) {
+ err = -EEXIST;
+ atomic_dec(&sdata->u.sta.mpaths);
+ kfree(new_node);
+ kfree(new_mpath);
+ goto endadd;
+ }
+ }
+
+ hlist_add_head_rcu(&new_node->list, bucket);
+ if (atomic_inc_return(&mesh_paths->entries) >=
+ mesh_paths->mean_chain_len * (mesh_paths->hash_mask + 1))
+ grow = 1;
+
+endadd:
+ spin_unlock(&mesh_paths->hashwlock[hash_idx]);
+endadd2:
+ read_unlock(&pathtbl_resize_lock);
+ if (!err && grow) {
+ struct mesh_table *oldtbl, *newtbl;
+
+ write_lock(&pathtbl_resize_lock);
+ oldtbl = mesh_paths;
+ newtbl = mesh_table_grow(mesh_paths);
+ if (!newtbl) {
+ write_unlock(&pathtbl_resize_lock);
+ return -ENOMEM;
+ }
+ rcu_assign_pointer(mesh_paths, newtbl);
+ synchronize_rcu();
+ mesh_table_free(oldtbl, false);
+ write_unlock(&pathtbl_resize_lock);
+ }
+ return err;
+}
+
+
+/**
+ * mesh_plink_broken - deactivates paths and sends perr when a link breaks
+ *
+ * @sta: broken peer link
+ *
+ * This function must be called from the rate control algorithm if enough
+ * delivery errors suggest that a peer link is no longer usable.
+ */
+void mesh_plink_broken(struct sta_info *sta)
+{
+ struct mesh_path *mpath;
+ struct mpath_node *node;
+ struct hlist_node *p;
+ struct net_device *dev = sta->dev;
+ int i;
+
+ rcu_read_lock();
+ for_each_mesh_entry(mesh_paths, p, node, i) {
+ mpath = node->mpath;
+ spin_lock_bh(&mpath->state_lock);
+ if (mpath->next_hop == sta &&
+ mpath->flags & MESH_PATH_ACTIVE &&
+ !(mpath->flags & MESH_PATH_FIXED)) {
+ mpath->flags &= ~MESH_PATH_ACTIVE;
+ ++mpath->dsn;
+ spin_unlock_bh(&mpath->state_lock);
+ mesh_path_error_tx(mpath->dst,
+ cpu_to_le32(mpath->dsn),
+ dev->broadcast, dev);
+ } else
+ spin_unlock_bh(&mpath->state_lock);
+ }
+ rcu_read_unlock();
+}
+
+/**
+ * mesh_path_flush_by_nexthop - Deletes mesh paths if their next hop matches
+ *
+ * @sta - mesh peer to match
+ *
+ * RCU notes: this function is called when a mesh plink transitions from ESTAB
+ * to any other state, since ESTAB state is the only one that allows path
+ * creation. This will happen before the sta can be freed (since we hold
+ * a reference to it) so any reader in a rcu read block will be protected
+ * against the plink dissapearing.
+ */
+void mesh_path_flush_by_nexthop(struct sta_info *sta)
+{
+ struct mesh_path *mpath;
+ struct mpath_node *node;
+ struct hlist_node *p;
+ int i;
+
+ for_each_mesh_entry(mesh_paths, p, node, i) {
+ mpath = node->mpath;
+ if (mpath->next_hop == sta)
+ mesh_path_del(mpath->dst, mpath->dev);
+ }
+}
+
+void mesh_path_flush(struct net_device *dev)
+{
+ struct mesh_path *mpath;
+ struct mpath_node *node;
+ struct hlist_node *p;
+ int i;
+
+ for_each_mesh_entry(mesh_paths, p, node, i) {
+ mpath = node->mpath;
+ if (mpath->dev == dev)
+ mesh_path_del(mpath->dst, mpath->dev);
+ }
+}
+
+static void mesh_path_node_reclaim(struct rcu_head *rp)
+{
+ struct mpath_node *node = container_of(rp, struct mpath_node, rcu);
+ struct ieee80211_sub_if_data *sdata =
+ IEEE80211_DEV_TO_SUB_IF(node->mpath->dev);
+ if (node->mpath->next_hop)
+ sta_info_put(node->mpath->next_hop);
+ atomic_dec(&sdata->u.sta.mpaths);
+ kfree(node->mpath);
+ kfree(node);
+}
+
+/**
+ * mesh_path_del - delete a mesh path from the table
+ *
+ * @addr: dst address (ETH_ALEN length)
+ * @dev: local interface
+ *
+ * Returns: 0 if succesful
+ *
+ * State: if the path is being resolved, the deletion will be postponed until
+ * the path resolution completes or times out.
+ */
+int mesh_path_del(u8 *addr, struct net_device *dev)
+{
+ struct mesh_path *mpath;
+ struct mpath_node *node;
+ struct hlist_head *bucket;
+ struct hlist_node *n;
+ int hash_idx;
+ int err = 0;
+
+ read_lock(&pathtbl_resize_lock);
+ hash_idx = mesh_table_hash(addr, dev, mesh_paths);
+ bucket = &mesh_paths->hash_buckets[hash_idx];
+
+ spin_lock(&mesh_paths->hashwlock[hash_idx]);
+ hlist_for_each_entry(node, n, bucket, list) {
+ mpath = node->mpath;
+ if (mpath->dev == dev &&
+ memcmp(addr, mpath->dst, ETH_ALEN) == 0) {
+ spin_lock_bh(&mpath->state_lock);
+ if (mpath->flags & MESH_PATH_RESOLVING) {
+ mpath->flags |= MESH_PATH_DELETE;
+ } else {
+ mpath->flags |= MESH_PATH_RESOLVING;
+ hlist_del_rcu(&node->list);
+ call_rcu(&node->rcu, mesh_path_node_reclaim);
+ atomic_dec(&mesh_paths->entries);
+ }
+ spin_unlock_bh(&mpath->state_lock);
+ goto enddel;
+ }
+ }
+
+ err = -ENXIO;
+enddel:
+ spin_unlock(&mesh_paths->hashwlock[hash_idx]);
+ read_unlock(&pathtbl_resize_lock);
+ return err;
+}
+
+/**
+ * mesh_path_tx_pending - sends pending frames in a mesh path queue
+ *
+ * @mpath: mesh path to activate
+ *
+ * Locking: the state_lock of the mpath structure must NOT be held when calling
+ * this function.
+ */
+void mesh_path_tx_pending(struct mesh_path *mpath)
+{
+ struct sk_buff *skb;
+
+ while ((skb = skb_dequeue(&mpath->frame_queue)) &&
+ (mpath->flags & MESH_PATH_ACTIVE))
+ dev_queue_xmit(skb);
+}
+
+/**
+ * mesh_path_discard_frame - discard a frame whose path could not be resolved
+ *
+ * @skb: frame to discard
+ * @dev: network device the frame was to be sent through
+ *
+ * If the frame was beign forwarded from another MP, a PERR frame will be sent
+ * to the precursor.
+ *
+ * Locking: the function must me called within a rcu_read_lock region
+ */
+void mesh_path_discard_frame(struct sk_buff *skb, struct net_device *dev)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct mesh_path *mpath;
+ u32 dsn = 0;
+
+ if (skb->pkt_type == PACKET_OTHERHOST) {
+ struct ieee80211s_hdr *prev_meshhdr;
+ int mshhdrlen;
+ u8 *ra, *da;
+
+ prev_meshhdr = ((struct ieee80211s_hdr *)skb->cb);
+ mshhdrlen = ieee80211_get_mesh_hdrlen(prev_meshhdr);
+ da = skb->data;
+ ra = MESH_PREQ(skb);
+ mpath = mesh_path_lookup(da, dev);
+ if (mpath)
+ dsn = ++mpath->dsn;
+ mesh_path_error_tx(skb->data, cpu_to_le32(dsn), ra, dev);
+ }
+
+ kfree_skb(skb);
+ sdata->u.sta.mshstats.dropped_frames_no_route++;
+}
+
+/**
+ * mesh_path_flush_pending - free the pending queue of a mesh path
+ *
+ * @mpath: mesh path whose queue has to be freed
+ *
+ * Locking: the function must me called withing a rcu_read_lock region
+ */
+void mesh_path_flush_pending(struct mesh_path *mpath)
+{
+ struct ieee80211_sub_if_data *sdata;
+ struct sk_buff *skb;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(mpath->dev);
+
+ while ((skb = skb_dequeue(&mpath->frame_queue)) &&
+ (mpath->flags & MESH_PATH_ACTIVE))
+ mesh_path_discard_frame(skb, mpath->dev);
+}
+
+/**
+ * mesh_path_fix_nexthop - force a specific next hop for a mesh path
+ *
+ * @mpath: the mesh path to modify
+ * @next_hop: the next hop to force
+ *
+ * Locking: this function must be called holding mpath->state_lock
+ */
+void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop)
+{
+ spin_lock_bh(&mpath->state_lock);
+ mesh_path_assign_nexthop(mpath, next_hop);
+ mpath->dsn = 0xffff;
+ mpath->metric = 0;
+ mpath->hop_count = 0;
+ mpath->exp_time = 0;
+ mpath->flags |= MESH_PATH_FIXED;
+ mesh_path_activate(mpath);
+ spin_unlock_bh(&mpath->state_lock);
+ mesh_path_tx_pending(mpath);
+}
+
+static void mesh_path_node_free(struct hlist_node *p, bool free_leafs)
+{
+ struct mesh_path *mpath;
+ struct mpath_node *node = hlist_entry(p, struct mpath_node, list);
+ mpath = node->mpath;
+ hlist_del_rcu(p);
+ synchronize_rcu();
+ if (free_leafs)
+ kfree(mpath);
+ kfree(node);
+}
+
+static void mesh_path_node_copy(struct hlist_node *p, struct mesh_table *newtbl)
+{
+ struct mesh_path *mpath;
+ struct mpath_node *node, *new_node;
+ u32 hash_idx;
+
+ node = hlist_entry(p, struct mpath_node, list);
+ mpath = node->mpath;
+ new_node = kmalloc(sizeof(struct mpath_node), GFP_KERNEL);
+ new_node->mpath = mpath;
+ hash_idx = mesh_table_hash(mpath->dst, mpath->dev, newtbl);
+ hlist_add_head(&new_node->list,
+ &newtbl->hash_buckets[hash_idx]);
+}
+
+int mesh_pathtbl_init(void)
+{
+ mesh_paths = mesh_table_alloc(INIT_PATHS_SIZE_ORDER);
+ mesh_paths->free_node = &mesh_path_node_free;
+ mesh_paths->copy_node = &mesh_path_node_copy;
+ mesh_paths->mean_chain_len = MEAN_CHAIN_LEN;
+ if (!mesh_paths)
+ return -ENOMEM;
+ return 0;
+}
+
+void mesh_path_expire(struct net_device *dev)
+{
+ struct mesh_path *mpath;
+ struct mpath_node *node;
+ struct hlist_node *p;
+ int i;
+
+ read_lock(&pathtbl_resize_lock);
+ for_each_mesh_entry(mesh_paths, p, node, i) {
+ if (node->mpath->dev != dev)
+ continue;
+ mpath = node->mpath;
+ spin_lock_bh(&mpath->state_lock);
+ if ((!(mpath->flags & MESH_PATH_RESOLVING)) &&
+ (!(mpath->flags & MESH_PATH_FIXED)) &&
+ time_after(jiffies,
+ mpath->exp_time + MESH_PATH_EXPIRE)) {
+ spin_unlock_bh(&mpath->state_lock);
+ mesh_path_del(mpath->dst, mpath->dev);
+ } else
+ spin_unlock_bh(&mpath->state_lock);
+ }
+ read_unlock(&pathtbl_resize_lock);
+}
+
+void mesh_pathtbl_unregister(void)
+{
+ mesh_table_free(mesh_paths, true);
+}
--
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH 12/18] mac80211: code for on-demand Hybrid Wireless Mesh Protocol
2008-02-23 14:17 [PATCH 00/18] mac80211 802.11s networking code Johannes Berg
` (10 preceding siblings ...)
2008-02-23 14:17 ` [PATCH 11/18] mac80211: mesh path table implementation Johannes Berg
@ 2008-02-23 14:17 ` Johannes Berg
2008-02-23 14:17 ` [PATCH 13/18] mac80211: mesh statistics and config through debugfs Johannes Berg
` (5 subsequent siblings)
17 siblings, 0 replies; 29+ messages in thread
From: Johannes Berg @ 2008-02-23 14:17 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless, Luis Carlos Cobo
From: Luis Carlos Cobo <luisca@cozybit.com>
This file implements the on-demand Hybrid Wireless Mesh Protocol, at this moment
using hop-count as the metric. When no mesh path exists for a given destination
or the mesh path is not active, frames addressed to that destination will be
queued and a Path Request frame will be sent. Queued frames will be sent when
the path is resolved (usually after reception of a Path Response) or discarded
if discovery times out. Path Requests will also be sent to refresh paths that
are being used and are close to expiring.
Path Errors are sent when a path discovery process triggered by the attempt to
forward a frame originated in a different mesh point times out. Path Errors are
also sent when a peer link is determined to be unreachable because of high error
rates.
Multiple destination support in Path Requests and Path Errors and precursors
have not been implemented yet.
Signed-off-by: Luis Carlos Cobo <luisca@cozybit.com>
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
net/mac80211/mesh_hwmp.c | 862 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 862 insertions(+)
create mode 100644 net/mac80211/mesh_hwmp.c
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ everything/net/mac80211/mesh_hwmp.c 2008-02-23 14:39:01.000000000 +0100
@@ -0,0 +1,862 @@
+/*
+ * Copyright (c) 2008 open80211s Ltd.
+ * Author: Luis Carlos Cobo <luisca@cozybit.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "mesh.h"
+
+#define IEEE80211_FC(type, stype) cpu_to_le16(type | stype)
+
+#define TEST_FRAME_LEN 8192
+#define MAX_METRIC 0xffffffff
+#define ARITH_SHIFT 8
+
+/* Number of frames buffered per destination for unresolved destinations */
+#define MESH_FRAME_QUEUE_LEN 10
+#define MAX_PREQ_QUEUE_LEN 64
+
+/* Destination only */
+#define MP_F_DO 0x1
+/* Reply and forward */
+#define MP_F_RF 0x2
+
+/* HWMP IE processing macros */
+#define AE_F (1<<6)
+#define AE_F_SET(x) (*x & AE_F)
+#define PREQ_IE_FLAGS(x) (*(x))
+#define PREQ_IE_HOPCOUNT(x) (*(x + 1))
+#define PREQ_IE_TTL(x) (*(x + 2))
+#define PREQ_IE_PREQ_ID(x) le32_to_cpu(*((u32 *) (x + 3)))
+#define PREQ_IE_ORIG_ADDR(x) (x + 7)
+#define PREQ_IE_ORIG_DSN(x) le32_to_cpu(*((u32 *) (x + 13)))
+#define PREQ_IE_LIFETIME(x) le32_to_cpu(*((u32 *) \
+ (AE_F_SET(x) ? x + 23 : x + 17)))
+#define PREQ_IE_METRIC(x) le32_to_cpu(*((u32 *) \
+ (AE_F_SET(x) ? x + 27 : x + 21)))
+#define PREQ_IE_DST_F(x) (*(AE_F_SET(x) ? x + 32 : x + 26))
+#define PREQ_IE_DST_ADDR(x) (AE_F_SET(x) ? x + 33 : x + 27)
+#define PREQ_IE_DST_DSN(x) le32_to_cpu(*((u32 *) \
+ (AE_F_SET(x) ? x + 39 : x + 33)))
+
+
+#define PREP_IE_FLAGS(x) PREQ_IE_FLAGS(x)
+#define PREP_IE_HOPCOUNT(x) PREQ_IE_HOPCOUNT(x)
+#define PREP_IE_TTL(x) PREQ_IE_TTL(x)
+#define PREP_IE_ORIG_ADDR(x) (x + 3)
+#define PREP_IE_ORIG_DSN(x) le32_to_cpu(*((u32 *) (x + 9)))
+#define PREP_IE_LIFETIME(x) le32_to_cpu(*((u32 *) \
+ (AE_F_SET(x) ? x + 19 : x + 13)))
+#define PREP_IE_METRIC(x) le32_to_cpu(*((u32 *) \
+ (AE_F_SET(x) ? x + 23 : x + 17)))
+#define PREP_IE_DST_ADDR(x) (AE_F_SET(x) ? x + 27 : x + 21)
+#define PREP_IE_DST_DSN(x) le32_to_cpu(*((u32 *) \
+ (AE_F_SET(x) ? x + 33 : x + 27)))
+
+#define PERR_IE_DST_ADDR(x) (x + 2)
+#define PERR_IE_DST_DSN(x) le32_to_cpu(*((u32 *) (x + 8)))
+
+#define TU_TO_EXP_TIME(x) (jiffies + msecs_to_jiffies(x * 1024 / 1000))
+#define MSEC_TO_TU(x) (x*1000/1024)
+#define DSN_GT(x, y) ((long) (y) - (long) (x) < 0)
+#define DSN_LT(x, y) ((long) (x) - (long) (y) < 0)
+
+#define net_traversal_jiffies(s) \
+ msecs_to_jiffies(s->u.sta.mshcfg.dot11MeshHWMPnetDiameterTraversalTime)
+#define default_lifetime(s) \
+ MSEC_TO_TU(s->u.sta.mshcfg.dot11MeshHWMPactivePathTimeout)
+#define min_preq_int_jiff(s) \
+ (msecs_to_jiffies(s->u.sta.mshcfg.dot11MeshHWMPpreqMinInterval))
+#define max_preq_retries(s) (s->u.sta.mshcfg.dot11MeshHWMPmaxPREQretries)
+#define disc_timeout_jiff(s) \
+ msecs_to_jiffies(sdata->u.sta.mshcfg.min_discovery_timeout)
+
+enum mpath_frame_type {
+ MPATH_PREQ = 0,
+ MPATH_PREP,
+ MPATH_PERR
+};
+
+static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
+ u8 *orig_addr, __le32 orig_dsn, u8 dst_flags, u8 *dst,
+ __le32 dst_dsn, u8 *da, u8 hop_count, u8 ttl, __le32 lifetime,
+ __le32 metric, __le32 preq_id, struct net_device *dev)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
+ struct ieee80211_mgmt *mgmt;
+ u8 *pos;
+ int ie_len;
+
+ if (!skb)
+ return -1;
+ skb_reserve(skb, local->hw.extra_tx_headroom);
+ /* 25 is the size of the common mgmt part (24) plus the size of the
+ * common action part (1)
+ */
+ mgmt = (struct ieee80211_mgmt *)
+ skb_put(skb, 25 + sizeof(mgmt->u.action.u.mesh_action));
+ memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.mesh_action));
+ mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+ IEEE80211_STYPE_ACTION);
+
+ memcpy(mgmt->da, da, ETH_ALEN);
+ memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
+ /* BSSID is left zeroed, wildcard value */
+ mgmt->u.action.category = MESH_PATH_SEL_CATEGORY;
+ mgmt->u.action.u.mesh_action.action_code = action;
+
+ switch (action) {
+ case MPATH_PREQ:
+ ie_len = 37;
+ pos = skb_put(skb, 2 + ie_len);
+ *pos++ = WLAN_EID_PREQ;
+ break;
+ case MPATH_PREP:
+ ie_len = 31;
+ pos = skb_put(skb, 2 + ie_len);
+ *pos++ = WLAN_EID_PREP;
+ break;
+ default:
+ kfree(skb);
+ return -ENOTSUPP;
+ break;
+ }
+ *pos++ = ie_len;
+ *pos++ = flags;
+ *pos++ = hop_count;
+ *pos++ = ttl;
+ if (action == MPATH_PREQ) {
+ memcpy(pos, &preq_id, 4);
+ pos += 4;
+ }
+ memcpy(pos, orig_addr, ETH_ALEN);
+ pos += ETH_ALEN;
+ memcpy(pos, &orig_dsn, 4);
+ pos += 4;
+ memcpy(pos, &lifetime, 4);
+ pos += 4;
+ memcpy(pos, &metric, 4);
+ pos += 4;
+ if (action == MPATH_PREQ) {
+ /* destination count */
+ *pos++ = 1;
+ *pos++ = dst_flags;
+ }
+ memcpy(pos, dst, ETH_ALEN);
+ pos += ETH_ALEN;
+ memcpy(pos, &dst_dsn, 4);
+
+ ieee80211_sta_tx(dev, skb, 0);
+ return 0;
+}
+
+/**
+ * mesh_send_path error - Sends a PERR mesh management frame
+ *
+ * @dst: broken destination
+ * @dst_dsn: dsn of the broken destination
+ * @ra: node this frame is addressed to
+ */
+int mesh_path_error_tx(u8 *dst, __le32 dst_dsn, u8 *ra,
+ struct net_device *dev)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
+ struct ieee80211_mgmt *mgmt;
+ u8 *pos;
+ int ie_len;
+
+ if (!skb)
+ return -1;
+ skb_reserve(skb, local->hw.extra_tx_headroom);
+ /* 25 is the size of the common mgmt part (24) plus the size of the
+ * common action part (1)
+ */
+ mgmt = (struct ieee80211_mgmt *)
+ skb_put(skb, 25 + sizeof(mgmt->u.action.u.mesh_action));
+ memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.mesh_action));
+ mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+ IEEE80211_STYPE_ACTION);
+
+ memcpy(mgmt->da, ra, ETH_ALEN);
+ memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
+ /* BSSID is left zeroed, wildcard value */
+ mgmt->u.action.category = MESH_PATH_SEL_CATEGORY;
+ mgmt->u.action.u.mesh_action.action_code = MPATH_PERR;
+ ie_len = 12;
+ pos = skb_put(skb, 2 + ie_len);
+ *pos++ = WLAN_EID_PERR;
+ *pos++ = ie_len;
+ /* mode flags, reserved */
+ *pos++ = 0;
+ /* number of destinations */
+ *pos++ = 1;
+ memcpy(pos, dst, ETH_ALEN);
+ pos += ETH_ALEN;
+ memcpy(pos, &dst_dsn, 4);
+
+ ieee80211_sta_tx(dev, skb, 0);
+ return 0;
+}
+
+static u32 airtime_link_metric_get(struct ieee80211_local *local,
+ struct sta_info *sta)
+{
+ struct ieee80211_supported_band *sband;
+ /* This should be adjusted for each device */
+ int device_constant = 1 << ARITH_SHIFT;
+ int test_frame_len = TEST_FRAME_LEN << ARITH_SHIFT;
+ int s_unit = 1 << ARITH_SHIFT;
+ int rate, err;
+ u32 tx_time, estimated_retx;
+ u64 result;
+
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
+ if (sta->fail_avg >= 100)
+ return MAX_METRIC;
+ err = (sta->fail_avg << ARITH_SHIFT) / 100;
+
+ /* bitrate is in units of 100 Kbps, while we need rate in units of
+ * 1Mbps. This will be corrected on tx_time computation.
+ */
+ rate = sband->bitrates[sta->txrate_idx].bitrate;
+ tx_time = (device_constant + 10 * test_frame_len / rate);
+ estimated_retx = ((1 << (2 * ARITH_SHIFT)) / (s_unit - err));
+ result = (tx_time * estimated_retx) >> (2 * ARITH_SHIFT) ;
+ return (u32)result;
+}
+
+/**
+ * hwmp_route_info_get - Update routing info to originator and transmitter
+ *
+ * @dev: local mesh interface
+ * @mgmt: mesh management frame
+ * @hwmp_ie: hwmp information element (PREP or PREQ)
+ *
+ * This function updates the path routing information to the originator and the
+ * transmitter of a HWMP PREQ or PREP fram.
+ *
+ * Returns: metric to frame originator or 0 if the frame should not be further
+ * processed
+ *
+ * Notes: this function is the only place (besides user-provided info) where
+ * path routing information is updated.
+ */
+static u32 hwmp_route_info_get(struct net_device *dev,
+ struct ieee80211_mgmt *mgmt,
+ u8 *hwmp_ie)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct mesh_path *mpath;
+ struct sta_info *sta;
+ bool fresh_info;
+ u8 *orig_addr, *ta;
+ u32 orig_dsn, orig_metric;
+ unsigned long orig_lifetime, exp_time;
+ u32 last_hop_metric, new_metric;
+ bool process = true;
+ u8 action = mgmt->u.action.u.mesh_action.action_code;
+
+ rcu_read_lock();
+ sta = sta_info_get(local, mgmt->sa);
+ if (!sta)
+ return 0;
+
+ last_hop_metric = airtime_link_metric_get(local, sta);
+ /* Update and check originator routing info */
+ fresh_info = true;
+
+ switch (action) {
+ case MPATH_PREQ:
+ orig_addr = PREQ_IE_ORIG_ADDR(hwmp_ie);
+ orig_dsn = PREQ_IE_ORIG_DSN(hwmp_ie);
+ orig_lifetime = PREQ_IE_LIFETIME(hwmp_ie);
+ orig_metric = PREQ_IE_METRIC(hwmp_ie);
+ break;
+ case MPATH_PREP:
+ /* Originator here refers to the MP that was the destination in
+ * the Path Request. The draft refers to that MP as the
+ * destination address, even though usually it is the origin of
+ * the PREP frame. We divert from the nomenclature in the draft
+ * so that we can easily use a single function to gather path
+ * information from both PREQ and PREP frames.
+ */
+ orig_addr = PREP_IE_ORIG_ADDR(hwmp_ie);
+ orig_dsn = PREP_IE_ORIG_DSN(hwmp_ie);
+ orig_lifetime = PREP_IE_LIFETIME(hwmp_ie);
+ orig_metric = PREP_IE_METRIC(hwmp_ie);
+ break;
+ default:
+ sta_info_put(sta);
+ return 0;
+ }
+ new_metric = orig_metric + last_hop_metric;
+ if (new_metric < orig_metric)
+ new_metric = MAX_METRIC;
+ exp_time = TU_TO_EXP_TIME(orig_lifetime);
+
+ if (memcmp(orig_addr, dev->dev_addr, ETH_ALEN) == 0) {
+ /* This MP is the originator, we are not interested in this
+ * frame, except for updating transmitter's path info.
+ */
+ process = false;
+ fresh_info = false;
+ } else {
+ mpath = mesh_path_lookup(orig_addr, dev);
+ if (mpath) {
+ spin_lock_bh(&mpath->state_lock);
+ if (mpath->flags & MESH_PATH_FIXED)
+ fresh_info = false;
+ else if ((mpath->flags & MESH_PATH_ACTIVE) &&
+ (mpath->flags & MESH_PATH_DSN_VALID)) {
+ if (DSN_GT(mpath->dsn, orig_dsn) ||
+ (mpath->dsn == orig_dsn &&
+ action == MPATH_PREQ &&
+ new_metric > mpath->metric)) {
+ process = false;
+ fresh_info = false;
+ }
+ }
+ } else {
+ mesh_path_add(orig_addr, dev);
+ mpath = mesh_path_lookup(orig_addr, dev);
+ if (!mpath) {
+ rcu_read_unlock();
+ sta_info_put(sta);
+ return 0;
+ }
+ spin_lock_bh(&mpath->state_lock);
+ }
+
+ if (fresh_info) {
+ mesh_path_assign_nexthop(mpath, sta);
+ mpath->flags |= MESH_PATH_DSN_VALID;
+ mpath->metric = new_metric;
+ mpath->dsn = orig_dsn;
+ mpath->exp_time = time_after(mpath->exp_time, exp_time)
+ ? mpath->exp_time : exp_time;
+ mesh_path_activate(mpath);
+ spin_unlock_bh(&mpath->state_lock);
+ mesh_path_tx_pending(mpath);
+ /* draft says preq_id should be saved to, but there does
+ * not seem to be any use for it, skipping by now
+ */
+ } else
+ spin_unlock_bh(&mpath->state_lock);
+ }
+
+ /* Update and check transmitter routing info */
+ ta = mgmt->sa;
+ if (memcmp(orig_addr, ta, ETH_ALEN) == 0)
+ fresh_info = false;
+ else {
+ fresh_info = true;
+
+ mpath = mesh_path_lookup(ta, dev);
+ if (mpath) {
+ spin_lock_bh(&mpath->state_lock);
+ if ((mpath->flags & MESH_PATH_FIXED) ||
+ ((mpath->flags & MESH_PATH_ACTIVE) &&
+ (last_hop_metric > mpath->metric)))
+ fresh_info = false;
+ } else {
+ mesh_path_add(ta, dev);
+ mpath = mesh_path_lookup(ta, dev);
+ if (!mpath) {
+ rcu_read_unlock();
+ sta_info_put(sta);
+ return 0;
+ }
+ spin_lock_bh(&mpath->state_lock);
+ }
+
+ if (fresh_info) {
+ mesh_path_assign_nexthop(mpath, sta);
+ mpath->flags &= ~MESH_PATH_DSN_VALID;
+ mpath->metric = last_hop_metric;
+ mpath->exp_time = time_after(mpath->exp_time, exp_time)
+ ? mpath->exp_time : exp_time;
+ mesh_path_activate(mpath);
+ spin_unlock_bh(&mpath->state_lock);
+ mesh_path_tx_pending(mpath);
+ } else
+ spin_unlock_bh(&mpath->state_lock);
+ }
+
+ sta_info_put(sta);
+ rcu_read_unlock();
+
+ return process ? new_metric : 0;
+}
+
+static void hwmp_preq_frame_process(struct net_device *dev,
+ struct ieee80211_mgmt *mgmt,
+ u8 *preq_elem, u32 metric) {
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+ struct mesh_path *mpath;
+ u8 *dst_addr, *orig_addr;
+ u8 dst_flags, ttl;
+ u32 orig_dsn, dst_dsn, lifetime;
+ bool reply = false;
+ bool forward = true;
+
+ /* Update destination DSN, if present */
+ dst_addr = PREQ_IE_DST_ADDR(preq_elem);
+ orig_addr = PREQ_IE_ORIG_ADDR(preq_elem);
+ dst_dsn = PREQ_IE_DST_DSN(preq_elem);
+ orig_dsn = PREQ_IE_ORIG_DSN(preq_elem);
+ dst_flags = PREQ_IE_DST_F(preq_elem);
+
+ if (memcmp(dst_addr, dev->dev_addr, ETH_ALEN) == 0) {
+ forward = false;
+ reply = true;
+ metric = 0;
+ if (time_after(jiffies, ifsta->last_dsn_update +
+ net_traversal_jiffies(sdata)) ||
+ time_before(jiffies, ifsta->last_dsn_update)) {
+ dst_dsn = ++ifsta->dsn;
+ ifsta->last_dsn_update = jiffies;
+ }
+ } else {
+ rcu_read_lock();
+ mpath = mesh_path_lookup(dst_addr, dev);
+ if (mpath) {
+ if ((!(mpath->flags & MESH_PATH_DSN_VALID)) ||
+ DSN_LT(mpath->dsn, dst_dsn)) {
+ mpath->dsn = dst_dsn;
+ mpath->flags &= MESH_PATH_DSN_VALID;
+ } else if ((!(dst_flags & MP_F_DO)) &&
+ (mpath->flags & MESH_PATH_ACTIVE)) {
+ reply = true;
+ metric = mpath->metric;
+ dst_dsn = mpath->dsn;
+ if (dst_flags & MP_F_RF)
+ dst_flags |= MP_F_DO;
+ else
+ forward = false;
+ }
+ }
+ rcu_read_unlock();
+ }
+
+ if (reply) {
+ lifetime = PREQ_IE_LIFETIME(preq_elem);
+ ttl = ifsta->mshcfg.dot11MeshTTL;
+ if (ttl != 0)
+ mesh_path_sel_frame_tx(MPATH_PREP, 0, dst_addr,
+ __cpu_to_le32(dst_dsn), 0, orig_addr,
+ __cpu_to_le32(orig_dsn), mgmt->sa, 0, ttl,
+ __cpu_to_le32(lifetime), __cpu_to_le32(metric),
+ 0, dev);
+ else
+ ifsta->mshstats.dropped_frames_ttl++;
+ }
+
+ if (forward) {
+ u32 preq_id;
+ u8 hopcount, flags;
+
+ ttl = PREQ_IE_TTL(preq_elem);
+ lifetime = PREQ_IE_LIFETIME(preq_elem);
+ if (ttl <= 1) {
+ ifsta->mshstats.dropped_frames_ttl++;
+ return;
+ }
+ --ttl;
+ flags = PREQ_IE_FLAGS(preq_elem);
+ preq_id = PREQ_IE_PREQ_ID(preq_elem);
+ hopcount = PREQ_IE_HOPCOUNT(preq_elem) + 1;
+ mesh_path_sel_frame_tx(MPATH_PREQ, flags, orig_addr,
+ __cpu_to_le32(orig_dsn), dst_flags, dst_addr,
+ __cpu_to_le32(dst_dsn), dev->broadcast,
+ hopcount, ttl, __cpu_to_le32(lifetime),
+ __cpu_to_le32(metric), __cpu_to_le32(preq_id),
+ dev);
+ ifsta->mshstats.fwded_frames++;
+ }
+}
+
+
+static void hwmp_prep_frame_process(struct net_device *dev,
+ struct ieee80211_mgmt *mgmt,
+ u8 *prep_elem, u32 metric)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct mesh_path *mpath;
+ u8 *dst_addr, *orig_addr;
+ u8 ttl, hopcount, flags;
+ u8 next_hop[ETH_ALEN];
+ u32 dst_dsn, orig_dsn, lifetime;
+
+ /* Note that we divert from the draft nomenclature and denominate
+ * destination to what the draft refers to as origininator. So in this
+ * function destnation refers to the final destination of the PREP,
+ * which corresponds with the originator of the PREQ which this PREP
+ * replies
+ */
+ dst_addr = PREP_IE_DST_ADDR(prep_elem);
+ if (memcmp(dst_addr, dev->dev_addr, ETH_ALEN) == 0)
+ /* destination, no forwarding required */
+ return;
+
+ ttl = PREP_IE_TTL(prep_elem);
+ if (ttl <= 1) {
+ sdata->u.sta.mshstats.dropped_frames_ttl++;
+ return;
+ }
+
+ rcu_read_lock();
+ mpath = mesh_path_lookup(dst_addr, dev);
+ if (mpath)
+ spin_lock_bh(&mpath->state_lock);
+ else
+ goto fail;
+ if (!(mpath->flags & MESH_PATH_ACTIVE)) {
+ spin_unlock_bh(&mpath->state_lock);
+ goto fail;
+ }
+ memcpy(next_hop, mpath->next_hop->addr, ETH_ALEN);
+ spin_unlock_bh(&mpath->state_lock);
+ --ttl;
+ flags = PREP_IE_FLAGS(prep_elem);
+ lifetime = PREP_IE_LIFETIME(prep_elem);
+ hopcount = PREP_IE_HOPCOUNT(prep_elem) + 1;
+ orig_addr = PREP_IE_ORIG_ADDR(prep_elem);
+ dst_dsn = PREP_IE_DST_DSN(prep_elem);
+ orig_dsn = PREP_IE_ORIG_DSN(prep_elem);
+
+ mesh_path_sel_frame_tx(MPATH_PREP, flags, orig_addr,
+ __cpu_to_le32(orig_dsn), 0, dst_addr,
+ __cpu_to_le32(dst_dsn), mpath->next_hop->addr, hopcount, ttl,
+ __cpu_to_le32(lifetime), __cpu_to_le32(metric),
+ 0, dev);
+ rcu_read_unlock();
+ sdata->u.sta.mshstats.fwded_frames++;
+ return;
+
+fail:
+ rcu_read_unlock();
+ sdata->u.sta.mshstats.dropped_frames_no_route++;
+ return;
+}
+
+static void hwmp_perr_frame_process(struct net_device *dev,
+ struct ieee80211_mgmt *mgmt, u8 *perr_elem)
+{
+ struct mesh_path *mpath;
+ u8 *ta, *dst_addr;
+ u32 dst_dsn;
+
+ ta = mgmt->sa;
+ dst_addr = PERR_IE_DST_ADDR(perr_elem);
+ dst_dsn = PERR_IE_DST_DSN(perr_elem);
+ rcu_read_lock();
+ mpath = mesh_path_lookup(dst_addr, dev);
+ if (mpath) {
+ spin_lock_bh(&mpath->state_lock);
+ if (mpath->flags & MESH_PATH_ACTIVE &&
+ memcmp(ta, mpath->next_hop->addr, ETH_ALEN) == 0 &&
+ (!(mpath->flags & MESH_PATH_DSN_VALID) ||
+ DSN_GT(dst_dsn, mpath->dsn))) {
+ mpath->flags &= ~MESH_PATH_ACTIVE;
+ mpath->dsn = dst_dsn;
+ spin_unlock_bh(&mpath->state_lock);
+ mesh_path_error_tx(dst_addr, dst_dsn, dev->broadcast,
+ dev);
+ } else
+ spin_unlock_bh(&mpath->state_lock);
+ }
+ rcu_read_unlock();
+}
+
+
+
+void mesh_rx_path_sel_frame(struct net_device *dev,
+ struct ieee80211_mgmt *mgmt,
+ size_t len)
+{
+ struct ieee802_11_elems elems;
+ size_t baselen;
+ u32 last_hop_metric;
+
+ baselen = (u8 *) mgmt->u.action.u.mesh_action.variable - (u8 *) mgmt;
+ ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable,
+ len - baselen, &elems);
+
+ switch (mgmt->u.action.u.mesh_action.action_code) {
+ case MPATH_PREQ:
+ if (!elems.preq || elems.preq_len != 37)
+ /* Right now we support just 1 destination and no AE */
+ return;
+ last_hop_metric = hwmp_route_info_get(dev, mgmt, elems.preq);
+ if (!last_hop_metric)
+ return;
+ hwmp_preq_frame_process(dev, mgmt, elems.preq, last_hop_metric);
+ break;
+ case MPATH_PREP:
+ if (!elems.prep || elems.prep_len != 31)
+ /* Right now we support no AE */
+ return;
+ last_hop_metric = hwmp_route_info_get(dev, mgmt, elems.prep);
+ if (!last_hop_metric)
+ return;
+ hwmp_prep_frame_process(dev, mgmt, elems.prep, last_hop_metric);
+ break;
+ case MPATH_PERR:
+ if (!elems.perr || elems.perr_len != 12)
+ /* Right now we support only one destination per PERR */
+ return;
+ hwmp_perr_frame_process(dev, mgmt, elems.perr);
+ default:
+ return;
+ }
+
+}
+
+/**
+ * mesh_queue_preq - queue a PREQ to a given destination
+ *
+ * @mpath: mesh path to discover
+ * @flags: special attributes of the PREQ to be sent
+ *
+ * Locking: the function must be called from within a rcu read lock block.
+ *
+ */
+static void mesh_queue_preq(struct mesh_path *mpath, u8 flags)
+{
+ struct ieee80211_sub_if_data *sdata =
+ IEEE80211_DEV_TO_SUB_IF(mpath->dev);
+ struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+ struct mesh_preq_queue *preq_node;
+
+ preq_node = kmalloc(sizeof(struct mesh_preq_queue), GFP_KERNEL);
+ if (!preq_node) {
+ printk(KERN_DEBUG "Mesh HWMP: could not allocate PREQ node\n");
+ return;
+ }
+
+ spin_lock(&ifsta->mesh_preq_queue_lock);
+ if (ifsta->preq_queue_len == MAX_PREQ_QUEUE_LEN) {
+ spin_unlock(&ifsta->mesh_preq_queue_lock);
+ kfree(preq_node);
+ if (printk_ratelimit())
+ printk(KERN_DEBUG "Mesh HWMP: PREQ node queue full\n");
+ return;
+ }
+
+ memcpy(preq_node->dst, mpath->dst, ETH_ALEN);
+ preq_node->flags = flags;
+
+ list_add_tail(&preq_node->list, &ifsta->preq_queue.list);
+ ++ifsta->preq_queue_len;
+ spin_unlock(&ifsta->mesh_preq_queue_lock);
+
+ if (time_after(jiffies, ifsta->last_preq + min_preq_int_jiff(sdata)))
+ queue_work(sdata->local->hw.workqueue, &ifsta->work);
+
+ else if (time_before(jiffies, ifsta->last_preq)) {
+ /* avoid long wait if did not send preqs for a long time
+ * and jiffies wrapped around
+ */
+ ifsta->last_preq = jiffies - min_preq_int_jiff(sdata) - 1;
+ queue_work(sdata->local->hw.workqueue, &ifsta->work);
+ } else
+ mod_timer(&ifsta->mesh_path_timer, ifsta->last_preq +
+ min_preq_int_jiff(sdata));
+}
+
+/**
+ * mesh_path_start_discovery - launch a path discovery from the PREQ queue
+ *
+ * @dev: local mesh interface
+ */
+void mesh_path_start_discovery(struct net_device *dev)
+{
+ struct ieee80211_sub_if_data *sdata =
+ IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+ struct mesh_preq_queue *preq_node;
+ struct mesh_path *mpath;
+ u8 ttl, dst_flags;
+ u32 lifetime;
+
+ spin_lock(&ifsta->mesh_preq_queue_lock);
+ if (!ifsta->preq_queue_len ||
+ time_before(jiffies, ifsta->last_preq +
+ min_preq_int_jiff(sdata))) {
+ spin_unlock(&ifsta->mesh_preq_queue_lock);
+ return;
+ }
+
+ preq_node = list_first_entry(&ifsta->preq_queue.list,
+ struct mesh_preq_queue, list);
+ list_del(&preq_node->list);
+ --ifsta->preq_queue_len;
+ spin_unlock(&ifsta->mesh_preq_queue_lock);
+
+ rcu_read_lock();
+ mpath = mesh_path_lookup(preq_node->dst, dev);
+ if (!mpath)
+ goto enddiscovery;
+
+ spin_lock_bh(&mpath->state_lock);
+ if (preq_node->flags & PREQ_Q_F_START) {
+ if (mpath->flags & MESH_PATH_RESOLVING) {
+ spin_unlock_bh(&mpath->state_lock);
+ goto enddiscovery;
+ } else {
+ mpath->flags &= ~MESH_PATH_RESOLVED;
+ mpath->flags |= MESH_PATH_RESOLVING;
+ mpath->discovery_retries = 0;
+ mpath->discovery_timeout = disc_timeout_jiff(sdata);
+ }
+ } else if (!(mpath->flags & MESH_PATH_RESOLVING) ||
+ mpath->flags & MESH_PATH_RESOLVED) {
+ mpath->flags &= ~MESH_PATH_RESOLVING;
+ spin_unlock_bh(&mpath->state_lock);
+ goto enddiscovery;
+ }
+
+ ifsta->last_preq = jiffies;
+
+ if (time_after(jiffies, ifsta->last_dsn_update +
+ net_traversal_jiffies(sdata)) ||
+ time_before(jiffies, ifsta->last_dsn_update)) {
+ ++ifsta->dsn;
+ sdata->u.sta.last_dsn_update = jiffies;
+ }
+ lifetime = default_lifetime(sdata);
+ ttl = sdata->u.sta.mshcfg.dot11MeshTTL;
+ if (ttl == 0) {
+ sdata->u.sta.mshstats.dropped_frames_ttl++;
+ spin_unlock_bh(&mpath->state_lock);
+ goto enddiscovery;
+ }
+
+ if (preq_node->flags & PREQ_Q_F_REFRESH)
+ dst_flags = MP_F_DO;
+ else
+ dst_flags = MP_F_RF;
+
+ spin_unlock_bh(&mpath->state_lock);
+ mesh_path_sel_frame_tx(MPATH_PREQ, 0, dev->dev_addr,
+ __cpu_to_le32(ifsta->dsn), dst_flags, mpath->dst,
+ __cpu_to_le32(mpath->dsn), dev->broadcast, 0,
+ ttl, __cpu_to_le32(lifetime), 0,
+ __cpu_to_le32(ifsta->preq_id++), dev);
+ mod_timer(&mpath->timer, jiffies + mpath->discovery_timeout);
+
+enddiscovery:
+ rcu_read_unlock();
+ kfree(preq_node);
+}
+
+/**
+ * ieee80211s_lookup_nexthop - put the appropriate next hop on a mesh frame
+ *
+ * @next_hop: output argument for next hop address
+ * @skb: frame to be sent
+ * @dev: network device the frame will be sent through
+ *
+ * Returns: 0 if the next hop was found. Nonzero otherwise. If no next hop is
+ * found, the function will start a path discovery and queue the frame so it is
+ * sent when the path is resolved. This means the caller must not free the skb
+ * in this case.
+ */
+int mesh_nexthop_lookup(u8 *next_hop, struct sk_buff *skb,
+ struct net_device *dev)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct sk_buff *skb_to_free = NULL;
+ struct mesh_path *mpath;
+ int err = 0;
+
+ rcu_read_lock();
+ mpath = mesh_path_lookup(skb->data, dev);
+
+ if (!mpath) {
+ mesh_path_add(skb->data, dev);
+ mpath = mesh_path_lookup(skb->data, dev);
+ if (!mpath) {
+ dev_kfree_skb(skb);
+ sdata->u.sta.mshstats.dropped_frames_no_route++;
+ err = -ENOSPC;
+ goto endlookup;
+ }
+ }
+
+ if (mpath->flags & MESH_PATH_ACTIVE) {
+ if (time_after(jiffies, mpath->exp_time -
+ msecs_to_jiffies(sdata->u.sta.mshcfg.path_refresh_time))
+ && skb->pkt_type != PACKET_OTHERHOST
+ && !(mpath->flags & MESH_PATH_RESOLVING)
+ && !(mpath->flags & MESH_PATH_FIXED)) {
+ mesh_queue_preq(mpath,
+ PREQ_Q_F_START | PREQ_Q_F_REFRESH);
+ }
+ memcpy(next_hop, mpath->next_hop->addr,
+ ETH_ALEN);
+ } else {
+ if (!(mpath->flags & MESH_PATH_RESOLVING)) {
+ /* Start discovery only if it is not running yet */
+ mesh_queue_preq(mpath, PREQ_Q_F_START);
+ }
+
+ if (skb_queue_len(&mpath->frame_queue) >=
+ MESH_FRAME_QUEUE_LEN) {
+ skb_to_free = mpath->frame_queue.next;
+ skb_unlink(skb_to_free, &mpath->frame_queue);
+ }
+
+ skb_queue_tail(&mpath->frame_queue, skb);
+ if (skb_to_free)
+ mesh_path_discard_frame(skb_to_free, dev);
+ err = -ENOENT;
+ }
+
+endlookup:
+ rcu_read_unlock();
+ return err;
+}
+
+void mesh_path_timer(unsigned long data)
+{
+ struct ieee80211_sub_if_data *sdata;
+ struct mesh_path *mpath;
+ bool delete = false;
+
+ rcu_read_lock();
+ mpath = (struct mesh_path *) data;
+ mpath = rcu_dereference(mpath);
+ if (!mpath)
+ goto endmpathtimer;
+ spin_lock_bh(&mpath->state_lock);
+ sdata = IEEE80211_DEV_TO_SUB_IF(mpath->dev);
+ if (mpath->flags & MESH_PATH_DELETE) {
+ mpath->flags = 0;
+ delete = true;
+ } else if (mpath->flags & MESH_PATH_RESOLVED ||
+ (!(mpath->flags & MESH_PATH_RESOLVING)))
+ mpath->flags &= ~(MESH_PATH_RESOLVING | MESH_PATH_RESOLVED);
+ else if (mpath->discovery_retries < max_preq_retries(sdata)) {
+ ++mpath->discovery_retries;
+ mpath->discovery_timeout *= 2;
+ mesh_queue_preq(mpath, 0);
+ } else {
+ mpath->flags = 0;
+ mpath->exp_time = jiffies;
+ mesh_path_flush_pending(mpath);
+ }
+
+ spin_unlock_bh(&mpath->state_lock);
+endmpathtimer:
+ rcu_read_unlock();
+ if (delete)
+ mesh_path_del(mpath->dst, mpath->dev);
+}
--
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH 13/18] mac80211: mesh statistics and config through debugfs
2008-02-23 14:17 [PATCH 00/18] mac80211 802.11s networking code Johannes Berg
` (11 preceding siblings ...)
2008-02-23 14:17 ` [PATCH 12/18] mac80211: code for on-demand Hybrid Wireless Mesh Protocol Johannes Berg
@ 2008-02-23 14:17 ` Johannes Berg
2008-03-28 6:16 ` Andrew Morton
2008-03-28 6:38 ` Andrew Morton
2008-02-23 14:17 ` [PATCH 14/18] mac80211: mesh path and mesh peer configuration Johannes Berg
` (4 subsequent siblings)
17 siblings, 2 replies; 29+ messages in thread
From: Johannes Berg @ 2008-02-23 14:17 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless, Luis Carlos Cobo
From: Luis Carlos Cobo <luisca@cozybit.com>
This patch contains the debugfs code for mesh statistics and configuration
parameters. Please note that generic support for r/w debugfs attributes has been
added.
Signed-off-by: Luis Carlos Cobo <luisca@cozybit.com>
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
net/mac80211/debugfs_netdev.c | 197 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 197 insertions(+)
--- everything.orig/net/mac80211/debugfs_netdev.c 2008-02-23 13:55:35.000000000 +0100
+++ everything/net/mac80211/debugfs_netdev.c 2008-02-23 14:39:11.000000000 +0100
@@ -39,6 +39,29 @@ static ssize_t ieee80211_if_read(
return ret;
}
+#ifdef CONFIG_MAC80211_MESH
+static ssize_t ieee80211_if_write(
+ struct ieee80211_sub_if_data *sdata,
+ char const __user *userbuf,
+ size_t count, loff_t *ppos,
+ int (*format)(struct ieee80211_sub_if_data *, char *))
+{
+ char buf[10];
+ int buf_size;
+
+ memset(buf, 0x00, sizeof(buf));
+ buf_size = min(count, (sizeof(buf)-1));
+ read_lock(&dev_base_lock);
+ if (copy_from_user(buf, userbuf, buf_size))
+ goto endwrite;
+ if (sdata->dev->reg_state == NETREG_REGISTERED)
+ (*format)(sdata, buf);
+endwrite:
+ read_unlock(&dev_base_lock);
+ return count;
+}
+#endif
+
#define IEEE80211_IF_FMT(name, field, format_string) \
static ssize_t ieee80211_if_fmt_##name( \
const struct ieee80211_sub_if_data *sdata, char *buf, \
@@ -46,6 +69,19 @@ static ssize_t ieee80211_if_fmt_##name(
{ \
return scnprintf(buf, buflen, format_string, sdata->field); \
}
+#define IEEE80211_IF_WFMT(name, field, type) \
+static int ieee80211_if_wfmt_##name( \
+ struct ieee80211_sub_if_data *sdata, char *buf) \
+{ \
+ unsigned long tmp; \
+ char *endp; \
+ \
+ tmp = simple_strtoul(buf, &endp, 0); \
+ if ((endp == buf) || ((type)tmp != tmp)) \
+ return -EINVAL; \
+ sdata->field = tmp; \
+ return 0; \
+}
#define IEEE80211_IF_FMT_DEC(name, field) \
IEEE80211_IF_FMT(name, field, "%d\n")
#define IEEE80211_IF_FMT_HEX(name, field) \
@@ -88,6 +124,34 @@ static const struct file_operations name
IEEE80211_IF_FMT_##format(name, field) \
__IEEE80211_IF_FILE(name)
+#define __IEEE80211_IF_WFILE(name) \
+static ssize_t ieee80211_if_read_##name(struct file *file, \
+ char __user *userbuf, \
+ size_t count, loff_t *ppos) \
+{ \
+ return ieee80211_if_read(file->private_data, \
+ userbuf, count, ppos, \
+ ieee80211_if_fmt_##name); \
+} \
+static ssize_t ieee80211_if_write_##name(struct file *file, \
+ const char __user *userbuf, \
+ size_t count, loff_t *ppos) \
+{ \
+ return ieee80211_if_write(file->private_data, \
+ userbuf, count, ppos, \
+ ieee80211_if_wfmt_##name); \
+} \
+static const struct file_operations name##_ops = { \
+ .read = ieee80211_if_read_##name, \
+ .write = ieee80211_if_write_##name, \
+ .open = mac80211_open_file_generic, \
+}
+
+#define IEEE80211_IF_WFILE(name, field, format, type) \
+ IEEE80211_IF_FMT_##format(name, field) \
+ IEEE80211_IF_WFMT(name, field, type) \
+ __IEEE80211_IF_WFILE(name)
+
/* common attributes */
IEEE80211_IF_FILE(channel_use, channel_use, DEC);
IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC);
@@ -106,6 +170,7 @@ IEEE80211_IF_FILE(assoc_tries, u.sta.ass
IEEE80211_IF_FILE(auth_algs, u.sta.auth_algs, HEX);
IEEE80211_IF_FILE(auth_alg, u.sta.auth_alg, DEC);
IEEE80211_IF_FILE(auth_transaction, u.sta.auth_transaction, DEC);
+IEEE80211_IF_FILE(num_beacons_sta, u.sta.num_beacons, DEC);
static ssize_t ieee80211_if_fmt_flags(
const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
@@ -139,6 +204,42 @@ __IEEE80211_IF_FILE(num_buffered_multica
/* WDS attributes */
IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC);
+#ifdef CONFIG_MAC80211_MESH
+/* Mesh stats attributes */
+IEEE80211_IF_FILE(fwded_frames, u.sta.mshstats.fwded_frames, DEC);
+IEEE80211_IF_FILE(dropped_frames_ttl, u.sta.mshstats.dropped_frames_ttl, DEC);
+IEEE80211_IF_FILE(dropped_frames_no_route,
+ u.sta.mshstats.dropped_frames_no_route, DEC);
+IEEE80211_IF_FILE(estab_plinks, u.sta.mshstats.estab_plinks, ATOMIC);
+
+/* Mesh parameters */
+IEEE80211_IF_WFILE(dot11MeshMaxRetries,
+ u.sta.mshcfg.dot11MeshMaxRetries, DEC, u8);
+IEEE80211_IF_WFILE(dot11MeshRetryTimeout,
+ u.sta.mshcfg.dot11MeshRetryTimeout, DEC, u16);
+IEEE80211_IF_WFILE(dot11MeshConfirmTimeout,
+ u.sta.mshcfg.dot11MeshConfirmTimeout, DEC, u16);
+IEEE80211_IF_WFILE(dot11MeshHoldingTimeout,
+ u.sta.mshcfg.dot11MeshHoldingTimeout, DEC, u16);
+IEEE80211_IF_WFILE(dot11MeshTTL, u.sta.mshcfg.dot11MeshTTL, DEC, u8);
+IEEE80211_IF_WFILE(auto_open_plinks, u.sta.mshcfg.auto_open_plinks, DEC, bool);
+IEEE80211_IF_WFILE(dot11MeshMaxPeerLinks,
+ u.sta.mshcfg.dot11MeshMaxPeerLinks, DEC, u16);
+IEEE80211_IF_WFILE(dot11MeshHWMPactivePathTimeout,
+ u.sta.mshcfg.dot11MeshHWMPactivePathTimeout, DEC, u32);
+IEEE80211_IF_WFILE(dot11MeshHWMPpreqMinInterval,
+ u.sta.mshcfg.dot11MeshHWMPpreqMinInterval, DEC, u16);
+IEEE80211_IF_WFILE(dot11MeshHWMPnetDiameterTraversalTime,
+ u.sta.mshcfg.dot11MeshHWMPnetDiameterTraversalTime, DEC, u16);
+IEEE80211_IF_WFILE(dot11MeshHWMPmaxPREQretries,
+ u.sta.mshcfg.dot11MeshHWMPmaxPREQretries, DEC, u8);
+IEEE80211_IF_WFILE(path_refresh_time,
+ u.sta.mshcfg.path_refresh_time, DEC, u32);
+IEEE80211_IF_WFILE(min_discovery_timeout,
+ u.sta.mshcfg.min_discovery_timeout, DEC, u16);
+#endif
+
+
#define DEBUGFS_ADD(name, type)\
sdata->debugfs.type.name = debugfs_create_file(#name, 0444,\
sdata->debugfsdir, sdata, &name##_ops);
@@ -161,6 +262,7 @@ static void add_sta_files(struct ieee802
DEBUGFS_ADD(auth_alg, sta);
DEBUGFS_ADD(auth_transaction, sta);
DEBUGFS_ADD(flags, sta);
+ DEBUGFS_ADD(num_beacons_sta, sta);
}
static void add_ap_files(struct ieee80211_sub_if_data *sdata)
@@ -192,12 +294,57 @@ static void add_monitor_files(struct iee
{
}
+#ifdef CONFIG_MAC80211_MESH
+#define MESHSTATS_ADD(name)\
+ sdata->mesh_stats.name = debugfs_create_file(#name, 0444,\
+ sdata->mesh_stats_dir, sdata, &name##_ops);
+
+static void add_mesh_stats(struct ieee80211_sub_if_data *sdata)
+{
+ sdata->mesh_stats_dir = debugfs_create_dir("mesh_stats",
+ sdata->debugfsdir);
+ MESHSTATS_ADD(fwded_frames);
+ MESHSTATS_ADD(dropped_frames_ttl);
+ MESHSTATS_ADD(dropped_frames_no_route);
+ MESHSTATS_ADD(estab_plinks);
+}
+
+#define MESHPARAMS_ADD(name)\
+ sdata->mesh_config.name = debugfs_create_file(#name, 0644,\
+ sdata->mesh_config_dir, sdata, &name##_ops);
+
+static void add_mesh_config(struct ieee80211_sub_if_data *sdata)
+{
+ sdata->mesh_config_dir = debugfs_create_dir("mesh_config",
+ sdata->debugfsdir);
+ MESHPARAMS_ADD(dot11MeshMaxRetries);
+ MESHPARAMS_ADD(dot11MeshRetryTimeout);
+ MESHPARAMS_ADD(dot11MeshConfirmTimeout);
+ MESHPARAMS_ADD(dot11MeshHoldingTimeout);
+ MESHPARAMS_ADD(dot11MeshTTL);
+ MESHPARAMS_ADD(auto_open_plinks);
+ MESHPARAMS_ADD(dot11MeshMaxPeerLinks);
+ MESHPARAMS_ADD(dot11MeshHWMPactivePathTimeout);
+ MESHPARAMS_ADD(dot11MeshHWMPpreqMinInterval);
+ MESHPARAMS_ADD(dot11MeshHWMPnetDiameterTraversalTime);
+ MESHPARAMS_ADD(dot11MeshHWMPmaxPREQretries);
+ MESHPARAMS_ADD(path_refresh_time);
+ MESHPARAMS_ADD(min_discovery_timeout);
+}
+#endif
+
static void add_files(struct ieee80211_sub_if_data *sdata)
{
if (!sdata->debugfsdir)
return;
switch (sdata->vif.type) {
+ case IEEE80211_IF_TYPE_MESH_POINT:
+#ifdef CONFIG_MAC80211_MESH
+ add_mesh_stats(sdata);
+ add_mesh_config(sdata);
+#endif
+ /* fall through */
case IEEE80211_IF_TYPE_STA:
case IEEE80211_IF_TYPE_IBSS:
add_sta_files(sdata);
@@ -243,6 +390,7 @@ static void del_sta_files(struct ieee802
DEBUGFS_DEL(auth_alg, sta);
DEBUGFS_DEL(auth_transaction, sta);
DEBUGFS_DEL(flags, sta);
+ DEBUGFS_DEL(num_beacons_sta, sta);
}
static void del_ap_files(struct ieee80211_sub_if_data *sdata)
@@ -274,12 +422,61 @@ static void del_monitor_files(struct iee
{
}
+#ifdef CONFIG_MAC80211_MESH
+#define MESHSTATS_DEL(name) \
+ do { \
+ debugfs_remove(sdata->mesh_stats.name); \
+ sdata->mesh_stats.name = NULL; \
+ } while (0)
+
+static void del_mesh_stats(struct ieee80211_sub_if_data *sdata)
+{
+ MESHSTATS_DEL(fwded_frames);
+ MESHSTATS_DEL(dropped_frames_ttl);
+ MESHSTATS_DEL(dropped_frames_no_route);
+ MESHSTATS_DEL(estab_plinks);
+ debugfs_remove(sdata->mesh_stats_dir);
+ sdata->mesh_stats_dir = NULL;
+}
+
+#define MESHPARAMS_DEL(name) \
+ do { \
+ debugfs_remove(sdata->mesh_config.name); \
+ sdata->mesh_config.name = NULL; \
+ } while (0)
+
+static void del_mesh_config(struct ieee80211_sub_if_data *sdata)
+{
+ MESHPARAMS_DEL(dot11MeshMaxRetries);
+ MESHPARAMS_DEL(dot11MeshRetryTimeout);
+ MESHPARAMS_DEL(dot11MeshConfirmTimeout);
+ MESHPARAMS_DEL(dot11MeshHoldingTimeout);
+ MESHPARAMS_DEL(dot11MeshTTL);
+ MESHPARAMS_DEL(auto_open_plinks);
+ MESHPARAMS_DEL(dot11MeshMaxPeerLinks);
+ MESHPARAMS_DEL(dot11MeshHWMPactivePathTimeout);
+ MESHPARAMS_DEL(dot11MeshHWMPpreqMinInterval);
+ MESHPARAMS_DEL(dot11MeshHWMPnetDiameterTraversalTime);
+ MESHPARAMS_DEL(dot11MeshHWMPmaxPREQretries);
+ MESHPARAMS_DEL(path_refresh_time);
+ MESHPARAMS_DEL(min_discovery_timeout);
+ debugfs_remove(sdata->mesh_config_dir);
+ sdata->mesh_config_dir = NULL;
+}
+#endif
+
static void del_files(struct ieee80211_sub_if_data *sdata, int type)
{
if (!sdata->debugfsdir)
return;
switch (type) {
+ case IEEE80211_IF_TYPE_MESH_POINT:
+#ifdef CONFIG_MAC80211_MESH
+ del_mesh_stats(sdata);
+ del_mesh_config(sdata);
+#endif
+ /* fall through */
case IEEE80211_IF_TYPE_STA:
case IEEE80211_IF_TYPE_IBSS:
del_sta_files(sdata);
--
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH 14/18] mac80211: mesh path and mesh peer configuration
2008-02-23 14:17 [PATCH 00/18] mac80211 802.11s networking code Johannes Berg
` (12 preceding siblings ...)
2008-02-23 14:17 ` [PATCH 13/18] mac80211: mesh statistics and config through debugfs Johannes Berg
@ 2008-02-23 14:17 ` Johannes Berg
2008-02-23 14:17 ` [PATCH 15/18] mac80211: complete the mesh (interface handling) code Johannes Berg
` (3 subsequent siblings)
17 siblings, 0 replies; 29+ messages in thread
From: Johannes Berg @ 2008-02-23 14:17 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless, Luis Carlos Cobo
From: Luis Carlos Cobo <luisca@cozybit.com>
This adds code to allow adding mesh interfaces and configuring
mesh peers etc. Also, it adds code for station dumping.
Signed-off-by: Luis Carlos Cobo <luisca@cozybit.com>
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
net/mac80211/cfg.c | 269 +++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 259 insertions(+), 10 deletions(-)
--- everything.orig/net/mac80211/cfg.c 2008-02-23 14:42:23.000000000 +0100
+++ everything/net/mac80211/cfg.c 2008-02-23 14:42:40.000000000 +0100
@@ -15,6 +15,11 @@
#include "ieee80211_i.h"
#include "cfg.h"
#include "ieee80211_rate.h"
+#ifdef CONFIG_MAC80211_MESH
+#include "mesh.h"
+#endif
+
+#define DEFAULT_RATES 0
static enum ieee80211_if_types
nl80211_type_to_mac80211_type(enum nl80211_iftype type)
@@ -28,6 +33,10 @@ nl80211_type_to_mac80211_type(enum nl802
return IEEE80211_IF_TYPE_STA;
case NL80211_IFTYPE_MONITOR:
return IEEE80211_IF_TYPE_MNTR;
+#ifdef CONFIG_MAC80211_MESH
+ case NL80211_IFTYPE_MESH_POINT:
+ return IEEE80211_IF_TYPE_MESH_POINT;
+#endif
default:
return IEEE80211_IF_TYPE_INVALID;
}
@@ -110,6 +119,15 @@ static int ieee80211_change_iface(struct
ieee80211_if_reinit(dev);
ieee80211_if_set_type(dev, itype);
+#ifdef CONFIG_MAC80211_MESH
+ if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT &&
+ params->mesh_id_len) {
+ sdata->u.sta.mesh_id_len = params->mesh_id_len;
+ memcpy(sdata->u.sta.mesh_id, params->mesh_id,
+ params->mesh_id_len);
+ }
+#endif
+
if (sdata->vif.type != IEEE80211_IF_TYPE_MNTR || !flags)
return 0;
@@ -286,6 +304,51 @@ static int ieee80211_config_default_key(
return 0;
}
+static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
+{
+#ifdef CONFIG_MAC80211_MESH
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
+#endif
+
+ sinfo->filled = STATION_INFO_INACTIVE_TIME |
+ STATION_INFO_RX_BYTES |
+ STATION_INFO_TX_BYTES;
+
+ sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx);
+ sinfo->rx_bytes = sta->rx_bytes;
+ sinfo->tx_bytes = sta->tx_bytes;
+
+#ifdef CONFIG_MAC80211_MESH
+ if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) {
+ sinfo->filled |= STATION_INFO_LLID |
+ STATION_INFO_PLID |
+ STATION_INFO_PLINK_STATE;
+
+ sinfo->llid = le16_to_cpu(sta->llid);
+ sinfo->plid = le16_to_cpu(sta->plid);
+ sinfo->plink_state = sta->plink_state;
+ }
+#endif
+}
+
+
+static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev,
+ int idx, u8 *mac, struct station_info *sinfo)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct sta_info *sta;
+
+ sta = sta_info_get_by_idx(local, idx, dev);
+ if (!sta)
+ return -ENOENT;
+
+ memcpy(mac, sta->addr, ETH_ALEN);
+ sta_set_sinfo(sta, sinfo);
+ sta_info_put(sta);
+
+ return 0;
+}
+
static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
u8 *mac, struct station_info *sinfo)
{
@@ -297,15 +360,7 @@ static int ieee80211_get_station(struct
return -ENOENT;
/* XXX: verify sta->dev == dev */
-
- sinfo->filled = STATION_INFO_INACTIVE_TIME |
- STATION_INFO_RX_BYTES |
- STATION_INFO_TX_BYTES;
-
- sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx);
- sinfo->rx_bytes = sta->rx_bytes;
- sinfo->tx_bytes = sta->tx_bytes;
-
+ sta_set_sinfo(sta, sinfo);
sta_info_put(sta);
return 0;
@@ -514,6 +569,9 @@ static void sta_apply_parameters(struct
u32 rates;
int i, j;
struct ieee80211_supported_band *sband;
+#ifdef CONFIG_MAC80211_MESH
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
+#endif
if (params->station_flags & STATION_FLAG_CHANGED) {
sta->flags &= ~WLAN_STA_AUTHORIZED;
@@ -551,6 +609,19 @@ static void sta_apply_parameters(struct
}
sta->supp_rates[local->oper_channel->band] = rates;
}
+
+#ifdef CONFIG_MAC80211_MESH
+ if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT &&
+ params->plink_action)
+ switch (params->plink_action) {
+ case PLINK_ACTION_OPEN:
+ mesh_plink_open(sta);
+ break;
+ case PLINK_ACTION_BLOCK:
+ mesh_plink_block(sta);
+ break;
+ }
+#endif
}
static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
@@ -573,7 +644,13 @@ static int ieee80211_add_station(struct
} else
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- sta = sta_info_add(local, dev, mac, GFP_KERNEL);
+#ifdef CONFIG_MAC80211_MESH
+ if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT)
+ sta = mesh_plink_add(mac, DEFAULT_RATES, dev);
+ else
+#endif
+ sta = sta_info_add(local, dev, mac, GFP_KERNEL);
+
if (IS_ERR(sta))
return PTR_ERR(sta);
@@ -645,6 +722,170 @@ static int ieee80211_change_station(stru
return 0;
}
+#ifdef CONFIG_MAC80211_MESH
+static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev,
+ u8 *dst, u8 *next_hop)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct mesh_path *mpath;
+ struct sta_info *sta;
+ int err;
+
+ if (!netif_running(dev))
+ return -ENETDOWN;
+
+ if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)
+ return -ENOTSUPP;
+
+ sta = sta_info_get(local, next_hop);
+ if (!sta)
+ return -ENOENT;
+
+ err = mesh_path_add(dst, dev);
+ if (err)
+ return err;
+
+ rcu_read_lock();
+ mpath = mesh_path_lookup(dst, dev);
+ if (!mpath) {
+ rcu_read_unlock();
+ sta_info_put(sta);
+ return -ENXIO;
+ }
+ mesh_path_fix_nexthop(mpath, sta);
+ sta_info_put(sta);
+ rcu_read_unlock();
+ return 0;
+}
+
+static int ieee80211_del_mpath(struct wiphy *wiphy, struct net_device *dev,
+ u8 *dst)
+{
+ if (dst)
+ return mesh_path_del(dst, dev);
+
+ mesh_path_flush(dev);
+ return 0;
+}
+
+static int ieee80211_change_mpath(struct wiphy *wiphy,
+ struct net_device *dev,
+ u8 *dst, u8 *next_hop)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct mesh_path *mpath;
+ struct sta_info *sta;
+
+ if (!netif_running(dev))
+ return -ENETDOWN;
+
+ if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)
+ return -ENOTSUPP;
+
+ sta = sta_info_get(local, next_hop);
+ if (!sta)
+ return -ENOENT;
+
+ rcu_read_lock();
+ mpath = mesh_path_lookup(dst, dev);
+ if (!mpath) {
+ rcu_read_unlock();
+ sta_info_put(sta);
+ return -ENOENT;
+ }
+
+ mesh_path_fix_nexthop(mpath, sta);
+ sta_info_put(sta);
+ rcu_read_unlock();
+ return 0;
+}
+
+static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop,
+ struct mpath_info *pinfo)
+{
+ if (mpath->next_hop)
+ memcpy(next_hop, mpath->next_hop->addr, ETH_ALEN);
+ else
+ memset(next_hop, 0, ETH_ALEN);
+
+ pinfo->filled = MPATH_INFO_FRAME_QLEN |
+ MPATH_INFO_DSN |
+ MPATH_INFO_METRIC |
+ MPATH_INFO_EXPTIME |
+ MPATH_INFO_DISCOVERY_TIMEOUT |
+ MPATH_INFO_DISCOVERY_RETRIES |
+ MPATH_INFO_FLAGS;
+
+ pinfo->frame_qlen = mpath->frame_queue.qlen;
+ pinfo->dsn = mpath->dsn;
+ pinfo->metric = mpath->metric;
+ if (time_before(jiffies, mpath->exp_time))
+ pinfo->exptime = jiffies_to_msecs(mpath->exp_time - jiffies);
+ pinfo->discovery_timeout =
+ jiffies_to_msecs(mpath->discovery_timeout);
+ pinfo->discovery_retries = mpath->discovery_retries;
+ pinfo->flags = 0;
+ if (mpath->flags & MESH_PATH_ACTIVE)
+ pinfo->flags |= NL80211_MPATH_FLAG_ACTIVE;
+ if (mpath->flags & MESH_PATH_RESOLVING)
+ pinfo->flags |= NL80211_MPATH_FLAG_RESOLVING;
+ if (mpath->flags & MESH_PATH_DSN_VALID)
+ pinfo->flags |= NL80211_MPATH_FLAG_DSN_VALID;
+ if (mpath->flags & MESH_PATH_FIXED)
+ pinfo->flags |= NL80211_MPATH_FLAG_FIXED;
+ if (mpath->flags & MESH_PATH_RESOLVING)
+ pinfo->flags |= NL80211_MPATH_FLAG_RESOLVING;
+
+ pinfo->flags = mpath->flags;
+}
+
+static int ieee80211_get_mpath(struct wiphy *wiphy, struct net_device *dev,
+ u8 *dst, u8 *next_hop, struct mpath_info *pinfo)
+
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct mesh_path *mpath;
+
+ if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)
+ return -ENOTSUPP;
+
+ rcu_read_lock();
+ mpath = mesh_path_lookup(dst, dev);
+ if (!mpath) {
+ rcu_read_unlock();
+ return -ENOENT;
+ }
+ memcpy(dst, mpath->dst, ETH_ALEN);
+ mpath_set_pinfo(mpath, next_hop, pinfo);
+ rcu_read_unlock();
+ return 0;
+}
+
+static int ieee80211_dump_mpath(struct wiphy *wiphy, struct net_device *dev,
+ int idx, u8 *dst, u8 *next_hop,
+ struct mpath_info *pinfo)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct mesh_path *mpath;
+
+ if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)
+ return -ENOTSUPP;
+
+ rcu_read_lock();
+ mpath = mesh_path_lookup_by_idx(idx, dev);
+ if (!mpath) {
+ rcu_read_unlock();
+ return -ENOENT;
+ }
+ memcpy(dst, mpath->dst, ETH_ALEN);
+ mpath_set_pinfo(mpath, next_hop, pinfo);
+ rcu_read_unlock();
+ return 0;
+}
+#endif
+
struct cfg80211_ops mac80211_config_ops = {
.add_virtual_intf = ieee80211_add_iface,
.del_virtual_intf = ieee80211_del_iface,
@@ -660,4 +901,12 @@ struct cfg80211_ops mac80211_config_ops
.del_station = ieee80211_del_station,
.change_station = ieee80211_change_station,
.get_station = ieee80211_get_station,
+ .dump_station = ieee80211_dump_station,
+#ifdef CONFIG_MAC80211_MESH
+ .add_mpath = ieee80211_add_mpath,
+ .del_mpath = ieee80211_del_mpath,
+ .change_mpath = ieee80211_change_mpath,
+ .get_mpath = ieee80211_get_mpath,
+ .dump_mpath = ieee80211_dump_mpath,
+#endif
};
--
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH 15/18] mac80211: complete the mesh (interface handling) code
2008-02-23 14:17 [PATCH 00/18] mac80211 802.11s networking code Johannes Berg
` (13 preceding siblings ...)
2008-02-23 14:17 ` [PATCH 14/18] mac80211: mesh path and mesh peer configuration Johannes Berg
@ 2008-02-23 14:17 ` Johannes Berg
2008-02-23 14:17 ` [PATCH 16/18] mac80211: clean up mesh code Johannes Berg
` (2 subsequent siblings)
17 siblings, 0 replies; 29+ messages in thread
From: Johannes Berg @ 2008-02-23 14:17 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless, Luis Carlos Cobo
From: Luis Carlos Cobo <luisca@cozybit.com>
This completes the mesh interface handling code and a few other
bits about the mac80211 module.
Signed-off-by: Luis Carlos Cobo <luisca@cozybit.com>
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
net/mac80211/ieee80211.c | 28 +++++++++++++++++++++++++++-
1 file changed, 27 insertions(+), 1 deletion(-)
--- everything.orig/net/mac80211/ieee80211.c 2008-02-23 14:53:02.000000000 +0100
+++ everything/net/mac80211/ieee80211.c 2008-02-23 14:53:32.000000000 +0100
@@ -26,6 +26,9 @@
#include "ieee80211_i.h"
#include "ieee80211_rate.h"
+#ifdef CONFIG_MAC80211_MESH
+#include "mesh.h"
+#endif
#include "wep.h"
#include "wme.h"
#include "aes_ccm.h"
@@ -138,9 +141,15 @@ static void ieee80211_master_set_multica
static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
{
+ int meshhdrlen;
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ meshhdrlen = (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) ? 5 : 0;
+
/* FIX: what would be proper limits for MTU?
* This interface uses 802.3 frames. */
- if (new_mtu < 256 || new_mtu > IEEE80211_MAX_DATA_LEN - 24 - 6) {
+ if (new_mtu < 256 ||
+ new_mtu > IEEE80211_MAX_DATA_LEN - 24 - 6 - meshhdrlen) {
printk(KERN_WARNING "%s: invalid MTU %d\n",
dev->name, new_mtu);
return -EINVAL;
@@ -441,6 +450,9 @@ static int ieee80211_stop(struct net_dev
ieee80211_configure_filter(local);
netif_tx_unlock_bh(local->mdev);
break;
+ case IEEE80211_IF_TYPE_MESH_POINT:
+ sta_info_flush(local, dev);
+ /* fall through */
case IEEE80211_IF_TYPE_STA:
case IEEE80211_IF_TYPE_IBSS:
sdata->u.sta.state = IEEE80211_DISABLED;
@@ -926,6 +938,11 @@ static int __ieee80211_if_config(struct
conf.bssid = sdata->u.sta.bssid;
conf.ssid = sdata->u.sta.ssid;
conf.ssid_len = sdata->u.sta.ssid_len;
+#ifdef CONFIG_MAC80211_MESH
+ } else if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) {
+ conf.beacon = beacon;
+ ieee80211_start_mesh(dev);
+#endif
} else if (sdata->vif.type == IEEE80211_IF_TYPE_AP) {
conf.ssid = sdata->u.ap.ssid;
conf.ssid_len = sdata->u.ap.ssid_len;
@@ -938,6 +955,11 @@ static int __ieee80211_if_config(struct
int ieee80211_if_config(struct net_device *dev)
{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT &&
+ (local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE))
+ return ieee80211_if_config_beacon(dev);
return __ieee80211_if_config(dev, NULL, NULL);
}
@@ -1802,6 +1824,10 @@ static void __exit ieee80211_exit(void)
rc80211_simple_exit();
rc80211_pid_exit();
+#ifdef CONFIG_MAC80211_MESH
+ if (mesh_allocated)
+ ieee80211s_stop();
+#endif
ieee80211_wme_unregister();
ieee80211_debugfs_netdev_exit();
}
--
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH 16/18] mac80211: clean up mesh code
2008-02-23 14:17 [PATCH 00/18] mac80211 802.11s networking code Johannes Berg
` (14 preceding siblings ...)
2008-02-23 14:17 ` [PATCH 15/18] mac80211: complete the mesh (interface handling) code Johannes Berg
@ 2008-02-23 14:17 ` Johannes Berg
2008-02-23 14:17 ` [PATCH 17/18] mac80211: mesh hwmp locking fixes Johannes Berg
2008-02-23 14:17 ` [PATCH 18/18] mac80211: enable mesh in Kconfig Johannes Berg
17 siblings, 0 replies; 29+ messages in thread
From: Johannes Berg @ 2008-02-23 14:17 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless, Luis Carlos Cobo
Various cleanups, reducing the #ifdef mess and other things.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
include/net/mac80211.h | 8 ++
net/mac80211/cfg.c | 32 +++-------
net/mac80211/ieee80211.c | 9 ---
net/mac80211/ieee80211_i.h | 56 ++++++++++++++++--
net/mac80211/ieee80211_iface.c | 66 +++-------------------
net/mac80211/ieee80211_sta.c | 72 ++++++++++--------------
net/mac80211/mesh.c | 67 ++++++++++++++++++++++
net/mac80211/mesh.h | 13 +++-
net/mac80211/mesh_plink.c | 28 +++++++--
net/mac80211/rc80211_pid_algo.c | 3 -
net/mac80211/rx.c | 28 ++++-----
net/mac80211/sta_info.c | 13 ----
net/mac80211/sta_info.h | 2
net/mac80211/tx.c | 120 +++++++++++++++++-----------------------
net/mac80211/util.c | 32 ----------
15 files changed, 277 insertions(+), 272 deletions(-)
--- everything.orig/net/mac80211/cfg.c 2008-02-23 14:58:19.000000000 +0100
+++ everything/net/mac80211/cfg.c 2008-02-23 14:59:28.000000000 +0100
@@ -15,9 +15,7 @@
#include "ieee80211_i.h"
#include "cfg.h"
#include "ieee80211_rate.h"
-#ifdef CONFIG_MAC80211_MESH
#include "mesh.h"
-#endif
#define DEFAULT_RATES 0
@@ -119,14 +117,10 @@ static int ieee80211_change_iface(struct
ieee80211_if_reinit(dev);
ieee80211_if_set_type(dev, itype);
-#ifdef CONFIG_MAC80211_MESH
- if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT &&
- params->mesh_id_len) {
- sdata->u.sta.mesh_id_len = params->mesh_id_len;
- memcpy(sdata->u.sta.mesh_id, params->mesh_id,
- params->mesh_id_len);
- }
-#endif
+ if (ieee80211_vif_is_mesh(&sdata->vif) && params->mesh_id_len)
+ ieee80211_if_sta_set_mesh_id(&sdata->u.sta,
+ params->mesh_id_len,
+ params->mesh_id);
if (sdata->vif.type != IEEE80211_IF_TYPE_MNTR || !flags)
return 0;
@@ -306,9 +300,7 @@ static int ieee80211_config_default_key(
static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
{
-#ifdef CONFIG_MAC80211_MESH
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
-#endif
sinfo->filled = STATION_INFO_INACTIVE_TIME |
STATION_INFO_RX_BYTES |
@@ -318,8 +310,8 @@ static void sta_set_sinfo(struct sta_inf
sinfo->rx_bytes = sta->rx_bytes;
sinfo->tx_bytes = sta->tx_bytes;
+ if (ieee80211_vif_is_mesh(&sdata->vif)) {
#ifdef CONFIG_MAC80211_MESH
- if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) {
sinfo->filled |= STATION_INFO_LLID |
STATION_INFO_PLID |
STATION_INFO_PLINK_STATE;
@@ -327,8 +319,8 @@ static void sta_set_sinfo(struct sta_inf
sinfo->llid = le16_to_cpu(sta->llid);
sinfo->plid = le16_to_cpu(sta->plid);
sinfo->plink_state = sta->plink_state;
- }
#endif
+ }
}
@@ -569,9 +561,7 @@ static void sta_apply_parameters(struct
u32 rates;
int i, j;
struct ieee80211_supported_band *sband;
-#ifdef CONFIG_MAC80211_MESH
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
-#endif
if (params->station_flags & STATION_FLAG_CHANGED) {
sta->flags &= ~WLAN_STA_AUTHORIZED;
@@ -610,9 +600,7 @@ static void sta_apply_parameters(struct
sta->supp_rates[local->oper_channel->band] = rates;
}
-#ifdef CONFIG_MAC80211_MESH
- if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT &&
- params->plink_action)
+ if (ieee80211_vif_is_mesh(&sdata->vif) && params->plink_action) {
switch (params->plink_action) {
case PLINK_ACTION_OPEN:
mesh_plink_open(sta);
@@ -621,7 +609,7 @@ static void sta_apply_parameters(struct
mesh_plink_block(sta);
break;
}
-#endif
+ }
}
static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
@@ -644,11 +632,9 @@ static int ieee80211_add_station(struct
} else
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-#ifdef CONFIG_MAC80211_MESH
- if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT)
+ if (ieee80211_vif_is_mesh(&sdata->vif))
sta = mesh_plink_add(mac, DEFAULT_RATES, dev);
else
-#endif
sta = sta_info_add(local, dev, mac, GFP_KERNEL);
if (IS_ERR(sta))
--- everything.orig/net/mac80211/ieee80211.c 2008-02-23 14:58:20.000000000 +0100
+++ everything/net/mac80211/ieee80211.c 2008-02-23 14:59:28.000000000 +0100
@@ -26,9 +26,7 @@
#include "ieee80211_i.h"
#include "ieee80211_rate.h"
-#ifdef CONFIG_MAC80211_MESH
#include "mesh.h"
-#endif
#include "wep.h"
#include "wme.h"
#include "aes_ccm.h"
@@ -938,11 +936,9 @@ static int __ieee80211_if_config(struct
conf.bssid = sdata->u.sta.bssid;
conf.ssid = sdata->u.sta.ssid;
conf.ssid_len = sdata->u.sta.ssid_len;
-#ifdef CONFIG_MAC80211_MESH
- } else if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) {
+ } else if (ieee80211_vif_is_mesh(&sdata->vif)) {
conf.beacon = beacon;
ieee80211_start_mesh(dev);
-#endif
} else if (sdata->vif.type == IEEE80211_IF_TYPE_AP) {
conf.ssid = sdata->u.ap.ssid;
conf.ssid_len = sdata->u.ap.ssid_len;
@@ -1824,10 +1820,9 @@ static void __exit ieee80211_exit(void)
rc80211_simple_exit();
rc80211_pid_exit();
-#ifdef CONFIG_MAC80211_MESH
if (mesh_allocated)
ieee80211s_stop();
-#endif
+
ieee80211_wme_unregister();
ieee80211_debugfs_netdev_exit();
}
--- everything.orig/net/mac80211/ieee80211_iface.c 2008-02-23 14:57:46.000000000 +0100
+++ everything/net/mac80211/ieee80211_iface.c 2008-02-23 14:59:28.000000000 +0100
@@ -15,9 +15,7 @@
#include "ieee80211_i.h"
#include "sta_info.h"
#include "debugfs_netdev.h"
-#ifdef CONFIG_MAC80211_MESH
#include "mesh.h"
-#endif
void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata)
{
@@ -82,14 +80,11 @@ int ieee80211_if_add(struct net_device *
ieee80211_debugfs_add_netdev(sdata);
ieee80211_if_set_type(ndev, type);
-#ifdef CONFIG_MAC80211_MESH
- if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT &&
- params && params->mesh_id_len) {
- sdata->u.sta.mesh_id_len = params->mesh_id_len;
- memcpy(sdata->u.sta.mesh_id, params->mesh_id,
- params->mesh_id_len);
- }
-#endif
+ if (ieee80211_vif_is_mesh(&sdata->vif) &&
+ params && params->mesh_id_len)
+ ieee80211_if_sta_set_mesh_id(&sdata->u.sta,
+ params->mesh_id_len,
+ params->mesh_id);
/* we're under RTNL so all this is fine */
if (unlikely(local->reg_state == IEEE80211_DEV_UNREGISTERED)) {
@@ -170,47 +165,8 @@ void ieee80211_if_set_type(struct net_de
msdata = IEEE80211_DEV_TO_SUB_IF(sdata->local->mdev);
sdata->bss = &msdata->u.ap;
-#ifdef CONFIG_MAC80211_MESH
- if (type == IEEE80211_IF_TYPE_MESH_POINT) {
- ifsta->mshcfg.dot11MeshRetryTimeout = MESH_RET_T;
- ifsta->mshcfg.dot11MeshConfirmTimeout = MESH_CONF_T;
- ifsta->mshcfg.dot11MeshHoldingTimeout = MESH_HOLD_T;
- ifsta->mshcfg.dot11MeshMaxRetries = MESH_MAX_RETR;
- ifsta->mshcfg.dot11MeshTTL = MESH_TTL;
- ifsta->mshcfg.auto_open_plinks = true;
- ifsta->mshcfg.dot11MeshMaxPeerLinks =
- MESH_MAX_ESTAB_PLINKS;
- ifsta->mshcfg.dot11MeshHWMPactivePathTimeout =
- MESH_PATH_TIMEOUT;
- ifsta->mshcfg.dot11MeshHWMPpreqMinInterval =
- MESH_PREQ_MIN_INT;
- ifsta->mshcfg.dot11MeshHWMPnetDiameterTraversalTime =
- MESH_DIAM_TRAVERSAL_TIME;
- ifsta->mshcfg.dot11MeshHWMPmaxPREQretries =
- MESH_MAX_PREQ_RETRIES;
- ifsta->mshcfg.path_refresh_time =
- MESH_PATH_REFRESH_TIME;
- ifsta->mshcfg.min_discovery_timeout =
- MESH_MIN_DISCOVERY_TIMEOUT;
- ifsta->accepting_plinks = true;
- ifsta->preq_id = 0;
- ifsta->dsn = 0;
- atomic_set(&ifsta->mpaths, 0);
- mesh_rmc_init(dev);
- ifsta->last_preq = jiffies;
- /* Allocate all mesh structures when creating the first
- * mesh interface.
- */
- if (!mesh_allocated)
- ieee80211s_init();
- mesh_ids_set_default(ifsta);
- setup_timer(&ifsta->mesh_path_timer,
- ieee80211_mesh_path_timer,
- (unsigned long) sdata);
- INIT_LIST_HEAD(&ifsta->preq_queue.list);
- spin_lock_init(&ifsta->mesh_preq_queue_lock);
- }
-#endif
+ if (ieee80211_vif_is_mesh(&sdata->vif))
+ ieee80211_mesh_init_sdata(sdata);
break;
}
case IEEE80211_IF_TYPE_MNTR:
@@ -240,6 +196,10 @@ void ieee80211_if_reinit(struct net_devi
ieee80211_if_sdata_deinit(sdata);
+ /* Need to handle mesh specially to allow eliding the function call */
+ if (ieee80211_vif_is_mesh(&sdata->vif))
+ mesh_rmc_free(dev);
+
switch (sdata->vif.type) {
case IEEE80211_IF_TYPE_INVALID:
/* cannot happen */
@@ -288,10 +248,6 @@ void ieee80211_if_reinit(struct net_devi
}
break;
case IEEE80211_IF_TYPE_MESH_POINT:
-#ifdef CONFIG_MAC80211_MESH
- mesh_rmc_free(dev);
-#endif
- /* fall through */
case IEEE80211_IF_TYPE_STA:
case IEEE80211_IF_TYPE_IBSS:
kfree(sdata->u.sta.extra_ie);
--- everything.orig/net/mac80211/ieee80211_sta.c 2008-02-23 14:58:14.000000000 +0100
+++ everything/net/mac80211/ieee80211_sta.c 2008-02-23 14:59:28.000000000 +0100
@@ -31,9 +31,7 @@
#include "ieee80211_i.h"
#include "ieee80211_rate.h"
#include "ieee80211_led.h"
-#ifdef CONFIG_MAC80211_MESH
#include "mesh.h"
-#endif
#define IEEE80211_AUTH_TIMEOUT (HZ / 5)
#define IEEE80211_AUTH_MAX_TRIES 3
@@ -1896,12 +1894,13 @@ static void __ieee80211_rx_bss_hash_add(
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
u8 hash_idx;
-#ifdef CONFIG_MAC80211_MESH
- if (bss->mesh_cfg)
- hash_idx = mesh_id_hash(bss->mesh_id, bss->mesh_id_len);
+
+ if (bss_mesh_cfg(bss))
+ hash_idx = mesh_id_hash(bss_mesh_id(bss),
+ bss_mesh_id_len(bss));
else
-#endif
hash_idx = STA_HASH(bss->bssid);
+
bss->hnext = local->sta_bss_hash[hash_idx];
local->sta_bss_hash[hash_idx] = bss;
}
@@ -1966,7 +1965,8 @@ ieee80211_rx_bss_get(struct net_device *
spin_lock_bh(&local->sta_bss_lock);
bss = local->sta_bss_hash[STA_HASH(bssid)];
while (bss) {
- if (!bss->mesh_cfg && !memcmp(bss->bssid, bssid, ETH_ALEN) &&
+ if (!bss_mesh_cfg(bss) &&
+ !memcmp(bss->bssid, bssid, ETH_ALEN) &&
bss->freq == freq &&
bss->ssid_len == ssid_len &&
(ssid_len == 0 || !memcmp(bss->ssid, ssid, ssid_len))) {
@@ -1990,8 +1990,8 @@ ieee80211_rx_mesh_bss_get(struct net_dev
spin_lock_bh(&local->sta_bss_lock);
bss = local->sta_bss_hash[mesh_id_hash(mesh_id, mesh_id_len)];
while (bss) {
- if (bss->mesh_cfg &&
- !memcmp(bss->mesh_cfg, mesh_cfg, MESH_CFG_CMP_LEN) &&
+ if (bss_mesh_cfg(bss) &&
+ !memcmp(bss_mesh_cfg(bss), mesh_cfg, MESH_CFG_CMP_LEN) &&
bss->freq == freq &&
mesh_id_len == bss->mesh_id_len &&
(mesh_id_len == 0 || !memcmp(bss->mesh_id, mesh_id,
@@ -2052,10 +2052,8 @@ static void ieee80211_rx_bss_free(struct
kfree(bss->rsn_ie);
kfree(bss->wmm_ie);
kfree(bss->ht_ie);
-#ifdef CONFIG_MAC80211_MESH
- kfree(bss->mesh_id);
- kfree(bss->mesh_cfg);
-#endif
+ kfree(bss_mesh_id(bss));
+ kfree(bss_mesh_cfg(bss));
kfree(bss);
}
@@ -2321,16 +2319,14 @@ static void ieee80211_rx_bss_info(struct
beacon_timestamp = le64_to_cpu(mgmt->u.beacon.timestamp);
ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems);
-#ifdef CONFIG_MAC80211_MESH
- if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT && elems.mesh_id
- && elems.mesh_config)
- if (mesh_matches_local(&elems, dev)) {
- u64 rates = ieee80211_sta_get_rates(local, &elems,
- rx_status->band);
- mesh_neighbour_update(mgmt->sa, rates, dev,
- mesh_peer_accepts_plinks(&elems, dev));
- }
-#endif
+ if (ieee80211_vif_is_mesh(&sdata->vif) && elems.mesh_id &&
+ elems.mesh_config && mesh_matches_local(&elems, dev)) {
+ u64 rates = ieee80211_sta_get_rates(local, &elems,
+ rx_status->band);
+
+ mesh_neighbour_update(mgmt->sa, rates, dev,
+ mesh_peer_accepts_plinks(&elems, dev));
+ }
if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && elems.supp_rates &&
memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0 &&
@@ -2711,9 +2707,7 @@ static void ieee80211_rx_mgmt_action(str
size_t len,
struct ieee80211_rx_status *rx_status)
{
-#ifdef CONFIG_MAC80211_MESH
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-#endif
if (len < IEEE80211_MIN_ACTION_SIZE)
return;
@@ -2746,17 +2740,14 @@ static void ieee80211_rx_mgmt_action(str
break;
}
break;
-#ifdef CONFIG_MAC80211_MESH
case PLINK_CATEGORY:
- if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT)
+ if (ieee80211_vif_is_mesh(&sdata->vif))
mesh_rx_plink_frame(dev, mgmt, len, rx_status);
break;
-
case MESH_PATH_SEL_CATEGORY:
- if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT)
+ if (ieee80211_vif_is_mesh(&sdata->vif))
mesh_rx_path_sel_frame(dev, mgmt, len);
break;
-#endif
default:
if (net_ratelimit())
printk(KERN_DEBUG "%s: Rx unknown action frame - "
@@ -3026,8 +3017,9 @@ void ieee80211_sta_work(struct work_stru
ieee80211_sta_rx_queued_mgmt(dev, skb);
#ifdef CONFIG_MAC80211_MESH
- if (ifsta->preq_queue_len && time_after(jiffies, ifsta->last_preq +
- msecs_to_jiffies(ifsta->mshcfg.dot11MeshHWMPpreqMinInterval)))
+ if (ifsta->preq_queue_len &&
+ time_after(jiffies,
+ ifsta->last_preq + msecs_to_jiffies(ifsta->mshcfg.dot11MeshHWMPpreqMinInterval)))
mesh_path_start_discovery(dev);
#endif
@@ -3809,13 +3801,11 @@ ieee80211_sta_scan_result(struct net_dev
memset(&iwe, 0, sizeof(iwe));
iwe.cmd = SIOCGIWESSID;
- if (bss->mesh_cfg) {
-#ifdef CONFIG_MAC80211_MESH
- iwe.u.data.length = bss->mesh_id_len;
+ if (bss_mesh_cfg(bss)) {
+ iwe.u.data.length = bss_mesh_id_len(bss);
iwe.u.data.flags = 1;
current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
- bss->mesh_id);
-#endif
+ bss_mesh_id(bss));
} else {
iwe.u.data.length = bss->ssid_len;
iwe.u.data.flags = 1;
@@ -3824,10 +3814,10 @@ ieee80211_sta_scan_result(struct net_dev
}
if (bss->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS
- || bss->mesh_cfg)) {
+ || bss_mesh_cfg(bss))) {
memset(&iwe, 0, sizeof(iwe));
iwe.cmd = SIOCGIWMODE;
- if (bss->mesh_cfg)
+ if (bss_mesh_cfg(bss))
iwe.u.mode = IW_MODE_MESH;
else if (bss->capability & WLAN_CAPABILITY_ESS)
iwe.u.mode = IW_MODE_MASTER;
@@ -3918,9 +3908,9 @@ ieee80211_sta_scan_result(struct net_dev
}
}
- if (bss->mesh_cfg) {
+ if (bss_mesh_cfg(bss)) {
char *buf;
- u8 *cfg = bss->mesh_cfg;
+ u8 *cfg = bss_mesh_cfg(bss);
buf = kmalloc(200, GFP_ATOMIC);
if (buf) {
memset(&iwe, 0, sizeof(iwe));
--- everything.orig/net/mac80211/mesh_plink.c 2008-02-23 14:58:16.000000000 +0100
+++ everything/net/mac80211/mesh_plink.c 2008-02-23 14:59:28.000000000 +0100
@@ -6,11 +6,11 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-
+#include <linux/kernel.h>
+#include <linux/random.h>
#include "ieee80211_i.h"
#include "ieee80211_rate.h"
#include "mesh.h"
-#include <linux/random.h>
#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
#define mpl_dbg(fmt, args...) printk(KERN_DEBUG fmt, ##args)
@@ -131,7 +131,7 @@ struct sta_info *mesh_plink_add(u8 *hw_a
}
/**
- * mesh_plink_deactivate - deactivate mesh peer link
+ * __mesh_plink_deactivate - deactivate mesh peer link
*
* @sta: mesh peer link to deactivate
*
@@ -139,7 +139,7 @@ struct sta_info *mesh_plink_add(u8 *hw_a
*
* Locking: the caller must hold sta->plink_lock
*/
-void mesh_plink_deactivate(struct sta_info *sta)
+static void __mesh_plink_deactivate(struct sta_info *sta)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
if (sta->plink_state == ESTAB)
@@ -148,6 +148,20 @@ void mesh_plink_deactivate(struct sta_in
mesh_path_flush_by_nexthop(sta);
}
+/**
+ * __mesh_plink_deactivate - deactivate mesh peer link
+ *
+ * @sta: mesh peer link to deactivate
+ *
+ * All mesh paths with this peer as next hop will be flushed
+ */
+void mesh_plink_deactivate(struct sta_info *sta)
+{
+ spin_lock_bh(&sta->plink_lock);
+ __mesh_plink_deactivate(sta);
+ spin_unlock_bh(&sta->plink_lock);
+}
+
static int mesh_plink_frame_tx(struct net_device *dev,
enum plink_frame_type action, u8 *da, __le16 llid, __le16 plid,
__le16 reason) {
@@ -365,7 +379,7 @@ void mesh_plink_block(struct sta_info *s
#endif
spin_lock_bh(&sta->plink_lock);
- mesh_plink_deactivate(sta);
+ __mesh_plink_deactivate(sta);
sta->plink_state = BLOCKED;
spin_unlock_bh(&sta->plink_lock);
}
@@ -390,7 +404,7 @@ int mesh_plink_close(struct sta_info *st
sta_info_put(sta);
return 0;
} else if (sta->plink_state == ESTAB) {
- mesh_plink_deactivate(sta);
+ __mesh_plink_deactivate(sta);
/* The timer should not be running */
if (!mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)))
__sta_info_get(sta);
@@ -699,7 +713,7 @@ void mesh_rx_plink_frame(struct net_devi
case CLS_ACPT:
reason = cpu_to_le16(MESH_CLOSE_RCVD);
sta->reason = reason;
- mesh_plink_deactivate(sta);
+ __mesh_plink_deactivate(sta);
sta->plink_state = HOLDING;
llid = sta->llid;
if (!mod_plink_timer(sta,
--- everything.orig/net/mac80211/rc80211_pid_algo.c 2008-02-23 14:57:45.000000000 +0100
+++ everything/net/mac80211/rc80211_pid_algo.c 2008-02-23 14:59:28.000000000 +0100
@@ -15,10 +15,7 @@
#include <linux/debugfs.h>
#include <net/mac80211.h>
#include "ieee80211_rate.h"
-#ifdef CONFIG_MAC80211_MESH
#include "mesh.h"
-#endif
-
#include "rc80211_pid.h"
--- everything.orig/net/mac80211/rx.c 2008-02-23 14:57:45.000000000 +0100
+++ everything/net/mac80211/rx.c 2008-02-23 14:59:28.000000000 +0100
@@ -20,9 +20,7 @@
#include "ieee80211_i.h"
#include "ieee80211_led.h"
-#ifdef CONFIG_MAC80211_MESH
#include "mesh.h"
-#endif
#include "wep.h"
#include "wpa.h"
#include "tkip.h"
@@ -439,6 +437,13 @@ ieee80211_rx_mesh_check(struct ieee80211
else
return RX_CONTINUE;
}
+#undef msh_h_get
+#else
+static inline ieee80211_rx_result
+ieee80211_rx_mesh_check(struct ieee80211_txrx_data *rx)
+{
+ return RX_CONTINUE;
+}
#endif
@@ -477,10 +482,8 @@ ieee80211_rx_h_check(struct ieee80211_tx
* responsible for filtering on both auth and assoc states.
*/
-#ifdef CONFIG_MAC80211_MESH
- if (rx->sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT)
+ if (ieee80211_vif_is_mesh(&rx->sdata->vif))
return ieee80211_rx_mesh_check(rx);
-#endif
if (unlikely(((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA ||
((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL &&
@@ -1111,8 +1114,7 @@ ieee80211_data_to_8023(struct ieee80211_
hdrlen = ieee80211_get_hdrlen(fc);
-#ifdef CONFIG_MAC80211_MESH
- if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) {
+ if (ieee80211_vif_is_mesh(&sdata->vif)) {
int meshhdrlen = ieee80211_get_mesh_hdrlen(
(struct ieee80211s_hdr *) (skb->data + hdrlen));
/* Copy on cb:
@@ -1126,7 +1128,6 @@ ieee80211_data_to_8023(struct ieee80211_
memcpy(MESH_PREQ(skb), hdr->addr2, ETH_ALEN);
hdrlen += meshhdrlen;
}
-#endif
/* convert IEEE 802.11 header + possible LLC headers into Ethernet
* header
@@ -1306,9 +1307,8 @@ ieee80211_deliver_skb(struct ieee80211_t
}
}
-#ifdef CONFIG_MAC80211_MESH
/* Mesh forwarding */
- if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) {
+ if (ieee80211_vif_is_mesh(&sdata->vif)) {
u8 *mesh_ttl = &((struct ieee80211s_hdr *)skb->cb)->ttl;
(*mesh_ttl)--;
@@ -1321,12 +1321,13 @@ ieee80211_deliver_skb(struct ieee80211_t
else
xmit_skb->pkt_type = PACKET_OTHERHOST;
} else
- sdata->u.sta.mshstats.dropped_frames_ttl++;
-
+ IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.sta,
+ dropped_frames_ttl);
} else if (skb->pkt_type != PACKET_OTHERHOST &&
compare_ether_addr(dev->dev_addr, skb->data) != 0) {
if (*mesh_ttl == 0) {
- sdata->u.sta.mshstats.dropped_frames_ttl++;
+ IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.sta,
+ dropped_frames_ttl);
dev_kfree_skb(skb);
skb = NULL;
} else {
@@ -1337,7 +1338,6 @@ ieee80211_deliver_skb(struct ieee80211_t
}
}
}
-#endif
if (skb) {
/* deliver to local stack */
--- everything.orig/net/mac80211/sta_info.c 2008-02-23 14:57:46.000000000 +0100
+++ everything/net/mac80211/sta_info.c 2008-02-23 14:59:28.000000000 +0100
@@ -21,9 +21,7 @@
#include "ieee80211_rate.h"
#include "sta_info.h"
#include "debugfs_sta.h"
-#ifdef CONFIG_MAC80211_MESH
#include "mesh.h"
-#endif
/* Caller must hold local->sta_lock */
static void sta_info_hash_add(struct ieee80211_local *local,
@@ -309,10 +307,8 @@ void sta_info_remove(struct sta_info *st
}
local->num_sta--;
-#ifdef CONFIG_MAC80211_MESH
- if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT)
+ if (ieee80211_vif_is_mesh(&sdata->vif))
mesh_accept_plinks_update(sdata->dev);
-#endif
}
void sta_info_free(struct sta_info *sta)
@@ -329,13 +325,8 @@ void sta_info_free(struct sta_info *sta)
sta_info_remove(sta);
write_unlock_bh(&local->sta_lock);
-#ifdef CONFIG_MAC80211_MESH
- if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) {
- spin_lock_bh(&sta->plink_lock);
+ if (ieee80211_vif_is_mesh(&sdata->vif))
mesh_plink_deactivate(sta);
- spin_unlock_bh(&sta->plink_lock);
- }
-#endif
while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) {
local->total_ps_buffered--;
--- everything.orig/net/mac80211/tx.c 2008-02-23 14:57:45.000000000 +0100
+++ everything/net/mac80211/tx.c 2008-02-23 14:59:28.000000000 +0100
@@ -26,9 +26,7 @@
#include "ieee80211_i.h"
#include "ieee80211_led.h"
-#ifdef CONFIG_MAC80211_MESH
#include "mesh.h"
-#endif
#include "wep.h"
#include "wpa.h"
#include "wme.h"
@@ -1460,7 +1458,7 @@ int ieee80211_subif_start_xmit(struct sk
goto fail;
}
meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr,
- sdata);
+ sdata);
}
hdrlen = 30;
break;
@@ -1778,40 +1776,6 @@ static void ieee80211_beacon_add_tim(str
read_unlock_bh(&local->sta_lock);
}
-#ifdef CONFIG_MAC80211_MESH
-static struct sk_buff *ieee80211_mesh_beacon_get(struct net_device *dev)
-{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
- struct ieee80211_mgmt *mgmt;
- u8 *pos;
-
- if (!skb)
- return NULL;
- skb_reserve(skb, local->hw.extra_tx_headroom);
- mgmt = (struct ieee80211_mgmt *)
- skb_put(skb, 24 + sizeof(mgmt->u.beacon));
- memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));
- mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
- IEEE80211_STYPE_BEACON);
- memset(mgmt->da, 0xff, ETH_ALEN);
- memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
- /* BSSID is left zeroed, wildcard value */
- mgmt->u.beacon.beacon_int =
- cpu_to_le16(local->hw.conf.beacon_int);
- mgmt->u.beacon.capab_info = 0x0; /* 0x0 for MPs */
-
- pos = skb_put(skb, 2);
- *pos++ = WLAN_EID_SSID;
- *pos++ = 0x0;
-
- mesh_mgmt_ies_add(skb, dev);
-
- return skb;
-}
-#endif
-
-
struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_tx_control *control)
@@ -1824,8 +1788,10 @@ struct sk_buff *ieee80211_beacon_get(str
struct rate_selection rsel;
struct beacon_data *beacon;
struct ieee80211_supported_band *sband;
+ struct ieee80211_mgmt *mgmt;
int *num_beacons;
- int err = 0;
+ bool err = true;
+ u8 *pos;
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
@@ -1834,47 +1800,65 @@ struct sk_buff *ieee80211_beacon_get(str
sdata = vif_to_sdata(vif);
bdev = sdata->dev;
- switch (sdata->vif.type) {
- case IEEE80211_IF_TYPE_AP:
+ if (sdata->vif.type == IEEE80211_IF_TYPE_AP) {
ap = &sdata->u.ap;
beacon = rcu_dereference(ap->beacon);
- if (!ap || !beacon) {
- err = -1;
- break;
- }
+ if (ap && beacon) {
+ /*
+ * headroom, head length,
+ * tail length and maximum TIM length
+ */
+ skb = dev_alloc_skb(local->tx_headroom +
+ beacon->head_len +
+ beacon->tail_len + 256);
+ if (!skb)
+ goto out;
- /* headroom, head length, tail length and maximum TIM length */
- skb = dev_alloc_skb(local->tx_headroom + beacon->head_len +
- beacon->tail_len + 256);
- if (!skb)
- goto out;
+ skb_reserve(skb, local->tx_headroom);
+ memcpy(skb_put(skb, beacon->head_len), beacon->head,
+ beacon->head_len);
- skb_reserve(skb, local->tx_headroom);
- memcpy(skb_put(skb, beacon->head_len), beacon->head,
- beacon->head_len);
+ ieee80211_include_sequence(sdata,
+ (struct ieee80211_hdr *)skb->data);
- ieee80211_include_sequence(sdata,
- (struct ieee80211_hdr *)skb->data);
+ ieee80211_beacon_add_tim(local, ap, skb, beacon);
- ieee80211_beacon_add_tim(local, ap, skb, beacon);
+ if (beacon->tail)
+ memcpy(skb_put(skb, beacon->tail_len),
+ beacon->tail, beacon->tail_len);
- if (beacon->tail)
- memcpy(skb_put(skb, beacon->tail_len), beacon->tail,
- beacon->tail_len);
+ num_beacons = &ap->num_beacons;
- num_beacons = &ap->num_beacons;
- break;
+ err = false;
+ }
+ } else if (ieee80211_vif_is_mesh(&sdata->vif)) {
+ /* headroom, head length, tail length and maximum TIM length */
+ skb = dev_alloc_skb(local->tx_headroom + 400);
+ if (!skb)
+ goto out;
+
+ skb_reserve(skb, local->hw.extra_tx_headroom);
+ mgmt = (struct ieee80211_mgmt *)
+ skb_put(skb, 24 + sizeof(mgmt->u.beacon));
+ memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));
+ mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+ IEEE80211_STYPE_BEACON);
+ memset(mgmt->da, 0xff, ETH_ALEN);
+ memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
+ /* BSSID is left zeroed, wildcard value */
+ mgmt->u.beacon.beacon_int =
+ cpu_to_le16(local->hw.conf.beacon_int);
+ mgmt->u.beacon.capab_info = 0x0; /* 0x0 for MPs */
+
+ pos = skb_put(skb, 2);
+ *pos++ = WLAN_EID_SSID;
+ *pos++ = 0x0;
+
+ mesh_mgmt_ies_add(skb, sdata->dev);
-#ifdef CONFIG_MAC80211_MESH
- case IEEE80211_IF_TYPE_MESH_POINT:
- skb = ieee80211_mesh_beacon_get(bdev);
num_beacons = &sdata->u.sta.num_beacons;
- break;
-#endif
- default:
- err = -1;
- break;
+ err = false;
}
if (err) {
--- everything.orig/net/mac80211/util.c 2008-02-23 14:57:45.000000000 +0100
+++ everything/net/mac80211/util.c 2008-02-23 14:59:28.000000000 +0100
@@ -26,9 +26,7 @@
#include "ieee80211_i.h"
#include "ieee80211_rate.h"
-#ifdef CONFIG_MAC80211_MESH
#include "mesh.h"
-#endif
#include "wme.h"
/* privid for wiphys to determine whether they belong to us or not */
@@ -149,7 +147,6 @@ int ieee80211_get_hdrlen_from_skb(const
}
EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb);
-#ifdef CONFIG_MAC80211_MESH
int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)
{
int ae = meshhdr->flags & IEEE80211S_FLAGS_AE;
@@ -167,7 +164,6 @@ int ieee80211_get_mesh_hdrlen(struct iee
return 5;
}
}
-#endif
void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx)
{
@@ -418,31 +414,3 @@ void ieee80211_iterate_active_interfaces
rcu_read_unlock();
}
EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces);
-
-#ifdef CONFIG_MAC80211_MESH
-/**
- * ieee80211_new_mesh_header - create a new mesh header
- * @meshhdr: uninitialized mesh header
- * @sdata: mesh interface to be used
- *
- * Return the header length.
- */
-int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr,
- struct ieee80211_sub_if_data *sdata)
-{
- meshhdr->flags = 0;
- meshhdr->ttl = sdata->u.sta.mshcfg.dot11MeshTTL;
-
- meshhdr->seqnum[0] = sdata->u.sta.mesh_seqnum[0]++;
- meshhdr->seqnum[1] = sdata->u.sta.mesh_seqnum[1];
- meshhdr->seqnum[2] = sdata->u.sta.mesh_seqnum[2];
-
- if (sdata->u.sta.mesh_seqnum[0] == 0) {
- sdata->u.sta.mesh_seqnum[1]++;
- if (sdata->u.sta.mesh_seqnum[1] == 0)
- sdata->u.sta.mesh_seqnum[2]++;
- }
-
- return 5;
-}
-#endif
--- everything.orig/net/mac80211/ieee80211_i.h 2008-02-23 14:58:05.000000000 +0100
+++ everything/net/mac80211/ieee80211_i.h 2008-02-23 14:59:45.000000000 +0100
@@ -93,9 +93,8 @@ struct ieee80211_sta_bss {
#ifdef CONFIG_MAC80211_MESH
u8 *mesh_id;
size_t mesh_id_len;
-#endif
- /* mesh_cfg left out the ifdef to reduce clutter on bss handling */
u8 *mesh_cfg;
+#endif
#define IEEE80211_MAX_SUPP_RATES 32
u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
size_t supp_rates_len;
@@ -113,6 +112,30 @@ struct ieee80211_sta_bss {
u8 erp_value;
};
+static inline u8 *bss_mesh_cfg(struct ieee80211_sta_bss *bss)
+{
+#ifdef CONFIG_MAC80211_MESH
+ return bss->mesh_cfg;
+#endif
+ return NULL;
+}
+
+static inline u8 *bss_mesh_id(struct ieee80211_sta_bss *bss)
+{
+#ifdef CONFIG_MAC80211_MESH
+ return bss->mesh_id;
+#endif
+ return NULL;
+}
+
+static inline u8 bss_mesh_id_len(struct ieee80211_sta_bss *bss)
+{
+#ifdef CONFIG_MAC80211_MESH
+ return bss->mesh_id_len;
+#endif
+ return 0;
+}
+
typedef unsigned __bitwise__ ieee80211_tx_result;
#define TX_CONTINUE ((__force ieee80211_tx_result) 0u)
@@ -233,7 +256,6 @@ struct ieee80211_if_vlan {
struct list_head list;
};
-#ifdef CONFIG_MAC80211_MESH
struct mesh_stats {
__u32 fwded_frames; /* Mesh forwarded frames */
__u32 dropped_frames_ttl; /* Not transmitted since mesh_ttl == 0*/
@@ -249,7 +271,6 @@ struct mesh_preq_queue {
u8 flags;
};
-
struct mesh_config {
/* Timeouts in ms */
/* Mesh plink management parameters */
@@ -268,7 +289,7 @@ struct mesh_config {
u32 path_refresh_time;
u16 min_discovery_timeout;
};
-#endif
+
/* flags used in struct ieee80211_if_sta.flags */
#define IEEE80211_STA_SSID_SET BIT(0)
@@ -361,6 +382,22 @@ struct ieee80211_if_sta {
int num_beacons; /* number of TXed beacon frames by this STA */
};
+static inline void ieee80211_if_sta_set_mesh_id(struct ieee80211_if_sta *ifsta,
+ u8 mesh_id_len, u8 *mesh_id)
+{
+#ifdef CONFIG_MAC80211_MESH
+ ifsta->mesh_id_len = mesh_id_len;
+ memcpy(ifsta->mesh_id, mesh_id, mesh_id_len);
+#endif
+}
+
+#ifdef CONFIG_MAC80211_MESH
+#define IEEE80211_IFSTA_MESH_CTR_INC(sta, name) \
+ do { (sta)->mshstats.name++; } while (0)
+#else
+#define IEEE80211_IFSTA_MESH_CTR_INC(sta, name) \
+ do { } while (0)
+#endif
/* flags used in struct ieee80211_sub_if_data.flags */
#define IEEE80211_SDATA_ALLMULTI BIT(0)
@@ -472,7 +509,7 @@ struct ieee80211_sub_if_data {
struct dentry *dropped_frames_ttl;
struct dentry *dropped_frames_no_route;
struct dentry *estab_plinks;
- struct timer_list mesh_path_timer;
+ struct timer_list mesh_path_timer;
} mesh_stats;
struct dentry *mesh_config_dir;
@@ -884,12 +921,17 @@ void sta_addba_resp_timer_expired(unsign
u64 ieee80211_sta_get_rates(struct ieee80211_local *local,
struct ieee802_11_elems *elems,
enum ieee80211_band band);
-void ieee80211_start_mesh(struct net_device *dev);
void ieee80211_sta_tx(struct net_device *dev, struct sk_buff *skb,
int encrypt);
void ieee802_11_parse_elems(u8 *start, size_t len,
struct ieee802_11_elems *elems);
+#ifdef CONFIG_MAC80211_MESH
+void ieee80211_start_mesh(struct net_device *dev);
+#else
+static inline void ieee80211_start_mesh(struct net_device *dev)
+{}
+#endif
/* ieee80211_iface.c */
int ieee80211_if_add(struct net_device *dev, const char *name,
--- everything.orig/net/mac80211/mesh.h 2008-02-23 14:57:45.000000000 +0100
+++ everything/net/mac80211/mesh.h 2008-02-23 14:59:28.000000000 +0100
@@ -11,10 +11,10 @@
#ifndef IEEE80211S_H
#define IEEE80211S_H
-#include "ieee80211_i.h"
+#include <linux/types.h>
#include <linux/jhash.h>
+#include "ieee80211_i.h"
-extern int mesh_allocated;
/* Data structures */
@@ -211,6 +211,8 @@ void mesh_rmc_free(struct net_device *de
int mesh_rmc_init(struct net_device *dev);
void ieee80211s_init(void);
void ieee80211s_stop(void);
+void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata);
+
/* Mesh paths */
int mesh_nexthop_lookup(u8 *next_hop, struct sk_buff *skb,
struct net_device *dev);
@@ -257,6 +259,9 @@ void mesh_path_timer(unsigned long data)
void mesh_path_flush_by_nexthop(struct sta_info *sta);
void mesh_path_discard_frame(struct sk_buff *skb, struct net_device *dev);
+#ifdef CONFIG_MAC80211_MESH
+extern int mesh_allocated;
+
static inline int mesh_plink_free_count(struct ieee80211_sub_if_data *sdata)
{
return sdata->u.sta.mshcfg.dot11MeshMaxPeerLinks -
@@ -278,6 +283,10 @@ static inline void mesh_path_activate(st
for (i = 0; i <= x->hash_mask; i++) \
hlist_for_each_entry_rcu(node, p, &x->hash_buckets[i], list)
+#else
+#define mesh_allocated 0
+#endif
+
#define MESH_PREQ(skb) (skb->cb + 30)
#endif /* IEEE80211S_H */
--- everything.orig/include/net/mac80211.h 2008-02-23 14:57:45.000000000 +0100
+++ everything/include/net/mac80211.h 2008-02-23 14:59:28.000000000 +0100
@@ -461,6 +461,14 @@ struct ieee80211_vif {
u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *))));
};
+static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif)
+{
+#ifdef CONFIG_MAC80211_MESH
+ return vif->type == IEEE80211_IF_TYPE_MESH_POINT;
+#endif
+ return false;
+}
+
/**
* struct ieee80211_if_init_conf - initial configuration of an interface
*
--- everything.orig/net/mac80211/sta_info.h 2008-02-23 14:57:45.000000000 +0100
+++ everything/net/mac80211/sta_info.h 2008-02-23 14:59:28.000000000 +0100
@@ -107,7 +107,6 @@ struct tid_ampdu_rx {
struct timer_list session_timer;
};
-#ifdef CONFIG_MAC80211_MESH
enum plink_state {
LISTEN,
OPN_SNT,
@@ -117,7 +116,6 @@ enum plink_state {
HOLDING,
BLOCKED
};
-#endif
/**
* struct sta_ampdu_mlme - STA aggregation information.
--- everything.orig/net/mac80211/mesh.c 2008-02-23 14:57:45.000000000 +0100
+++ everything/net/mac80211/mesh.c 2008-02-23 14:59:28.000000000 +0100
@@ -381,3 +381,70 @@ endgrow:
else
return newtbl;
}
+
+/**
+ * ieee80211_new_mesh_header - create a new mesh header
+ * @meshhdr: uninitialized mesh header
+ * @sdata: mesh interface to be used
+ *
+ * Return the header length.
+ */
+int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr,
+ struct ieee80211_sub_if_data *sdata)
+{
+ meshhdr->flags = 0;
+ meshhdr->ttl = sdata->u.sta.mshcfg.dot11MeshTTL;
+
+ meshhdr->seqnum[0] = sdata->u.sta.mesh_seqnum[0]++;
+ meshhdr->seqnum[1] = sdata->u.sta.mesh_seqnum[1];
+ meshhdr->seqnum[2] = sdata->u.sta.mesh_seqnum[2];
+
+ if (sdata->u.sta.mesh_seqnum[0] == 0) {
+ sdata->u.sta.mesh_seqnum[1]++;
+ if (sdata->u.sta.mesh_seqnum[1] == 0)
+ sdata->u.sta.mesh_seqnum[2]++;
+ }
+
+ return 5;
+}
+
+void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+
+ ifsta->mshcfg.dot11MeshRetryTimeout = MESH_RET_T;
+ ifsta->mshcfg.dot11MeshConfirmTimeout = MESH_CONF_T;
+ ifsta->mshcfg.dot11MeshHoldingTimeout = MESH_HOLD_T;
+ ifsta->mshcfg.dot11MeshMaxRetries = MESH_MAX_RETR;
+ ifsta->mshcfg.dot11MeshTTL = MESH_TTL;
+ ifsta->mshcfg.auto_open_plinks = true;
+ ifsta->mshcfg.dot11MeshMaxPeerLinks =
+ MESH_MAX_ESTAB_PLINKS;
+ ifsta->mshcfg.dot11MeshHWMPactivePathTimeout =
+ MESH_PATH_TIMEOUT;
+ ifsta->mshcfg.dot11MeshHWMPpreqMinInterval =
+ MESH_PREQ_MIN_INT;
+ ifsta->mshcfg.dot11MeshHWMPnetDiameterTraversalTime =
+ MESH_DIAM_TRAVERSAL_TIME;
+ ifsta->mshcfg.dot11MeshHWMPmaxPREQretries =
+ MESH_MAX_PREQ_RETRIES;
+ ifsta->mshcfg.path_refresh_time =
+ MESH_PATH_REFRESH_TIME;
+ ifsta->mshcfg.min_discovery_timeout =
+ MESH_MIN_DISCOVERY_TIMEOUT;
+ ifsta->accepting_plinks = true;
+ ifsta->preq_id = 0;
+ ifsta->dsn = 0;
+ atomic_set(&ifsta->mpaths, 0);
+ mesh_rmc_init(sdata->dev);
+ ifsta->last_preq = jiffies;
+ /* Allocate all mesh structures when creating the first mesh interface. */
+ if (!mesh_allocated)
+ ieee80211s_init();
+ mesh_ids_set_default(ifsta);
+ setup_timer(&ifsta->mesh_path_timer,
+ ieee80211_mesh_path_timer,
+ (unsigned long) sdata);
+ INIT_LIST_HEAD(&ifsta->preq_queue.list);
+ spin_lock_init(&ifsta->mesh_preq_queue_lock);
+}
--
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH 17/18] mac80211: mesh hwmp locking fixes
2008-02-23 14:17 [PATCH 00/18] mac80211 802.11s networking code Johannes Berg
` (15 preceding siblings ...)
2008-02-23 14:17 ` [PATCH 16/18] mac80211: clean up mesh code Johannes Berg
@ 2008-02-23 14:17 ` Johannes Berg
2008-02-25 19:09 ` Luis Carlos Cobo
2008-02-23 14:17 ` [PATCH 18/18] mac80211: enable mesh in Kconfig Johannes Berg
17 siblings, 1 reply; 29+ messages in thread
From: Johannes Berg @ 2008-02-23 14:17 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless, Luis Carlos Cobo
This fixes missing unlocks noticed by sparse.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
net/mac80211/mesh_hwmp.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
--- everything.orig/net/mac80211/mesh_hwmp.c 2008-02-23 13:50:40.000000000 +0100
+++ everything/net/mac80211/mesh_hwmp.c 2008-02-23 13:51:11.000000000 +0100
@@ -264,8 +264,10 @@ static u32 hwmp_route_info_get(struct ne
rcu_read_lock();
sta = sta_info_get(local, mgmt->sa);
- if (!sta)
+ if (!sta) {
+ rcu_read_unlock();
return 0;
+ }
last_hop_metric = airtime_link_metric_get(local, sta);
/* Update and check originator routing info */
@@ -293,6 +295,7 @@ static u32 hwmp_route_info_get(struct ne
break;
default:
sta_info_put(sta);
+ rcu_read_unlock();
return 0;
}
new_metric = orig_metric + last_hop_metric;
--
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH 18/18] mac80211: enable mesh in Kconfig
2008-02-23 14:17 [PATCH 00/18] mac80211 802.11s networking code Johannes Berg
` (16 preceding siblings ...)
2008-02-23 14:17 ` [PATCH 17/18] mac80211: mesh hwmp locking fixes Johannes Berg
@ 2008-02-23 14:17 ` Johannes Berg
2008-02-25 20:58 ` Luis Carlos Cobo
17 siblings, 1 reply; 29+ messages in thread
From: Johannes Berg @ 2008-02-23 14:17 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless, Luis Carlos Cobo
Currently marked BROKEN because of endianness problems.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
See huge sparse output...
net/mac80211/Kconfig | 15 +++++++++++++++
net/mac80211/Makefile | 6 ++++++
2 files changed, 21 insertions(+)
--- everything.orig/net/mac80211/Kconfig 2008-02-23 14:57:44.000000000 +0100
+++ everything/net/mac80211/Kconfig 2008-02-23 15:00:57.000000000 +0100
@@ -81,6 +81,14 @@ config MAC80211_RC_SIMPLE
Say N unless you know what you are doing.
endmenu
+config MAC80211_MESH
+ bool "Enable mac80211 mesh networking (pre-802.11s) support"
+ depends on MAC80211 && EXPERIMENTAL && BROKEN
+ ---help---
+ This options enables support of pre-802.11s mesh interfaces.
+ For more information visit http://o11s.org
+
+
config MAC80211_LEDS
bool "Enable LED triggers"
depends on MAC80211 && LEDS_TRIGGERS
@@ -166,3 +174,10 @@ config MAC80211_VERBOSE_PS_DEBUG
---help---
Say Y here to print out verbose powersave
mode debug messages.
+
+config MAC80211_VERBOSE_MPL_DEBUG
+ bool "Verbose mesh peer link debugging"
+ depends on MAC80211_DEBUG && MAC80211_MESH
+ ---help---
+ Say Y here to print out verbose mesh peer link
+ debug messages.
--- everything.orig/net/mac80211/Makefile 2008-02-23 14:57:44.000000000 +0100
+++ everything/net/mac80211/Makefile 2008-02-23 15:00:57.000000000 +0100
@@ -36,6 +36,12 @@ mac80211-$(CONFIG_MAC80211_DEBUGFS) += \
debugfs_netdev.o \
debugfs_key.o
+mac80211-$(CONFIG_MAC80211_MESH) += \
+ mesh.o \
+ mesh_pathtbl.o \
+ mesh_plink.o \
+ mesh_hwmp.o
+
# Build rate control algorithm(s)
CFLAGS_rc80211_simple.o += -DRC80211_SIMPLE_COMPILE
--
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 17/18] mac80211: mesh hwmp locking fixes
2008-02-23 14:17 ` [PATCH 17/18] mac80211: mesh hwmp locking fixes Johannes Berg
@ 2008-02-25 19:09 ` Luis Carlos Cobo
2008-02-25 19:09 ` Johannes Berg
0 siblings, 1 reply; 29+ messages in thread
From: Luis Carlos Cobo @ 2008-02-25 19:09 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless
On Sat, 2008-02-23 at 15:17 +0100, Johannes Berg wrote:
> This fixes missing unlocks noticed by sparse.
Thanks for the fix. It would be easier though to just acquire the lock
later, since rcu_read_lock() is no longer needed to look for mesh peer
links, like in this patch (applied to the original version of the file
without the patch included in the mail I'm replying to).
---
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -262,7 +262,6 @@ static u32 hwmp_route_info_get(struct net_device *dev,
bool process = true;
u8 action = mgmt->u.action.u.mesh_action.action_code;
- rcu_read_lock();
sta = sta_info_get(local, mgmt->sa);
if (!sta)
return 0;
@@ -300,6 +299,7 @@ static u32 hwmp_route_info_get(struct net_device *dev,
new_metric = MAX_METRIC;
exp_time = TU_TO_EXP_TIME(orig_lifetime);
+ rcu_read_lock();
if (memcmp(orig_addr, dev->dev_addr, ETH_ALEN) == 0) {
/* This MP is the originator, we are not interested in this
* frame, except for updating transmitter's path info.
--
Luis Carlos Cobo Rus GnuPG ID: 44019B60
cozybit Inc.
--
Luis Carlos Cobo Rus GnuPG ID: 44019B60
cozybit Inc.
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 17/18] mac80211: mesh hwmp locking fixes
2008-02-25 19:09 ` Luis Carlos Cobo
@ 2008-02-25 19:09 ` Johannes Berg
2008-02-25 19:41 ` Luis Carlos Cobo
0 siblings, 1 reply; 29+ messages in thread
From: Johannes Berg @ 2008-02-25 19:09 UTC (permalink / raw)
To: Luis Carlos Cobo; +Cc: linux-wireless
[-- Attachment #1: Type: text/plain, Size: 847 bytes --]
On Mon, 2008-02-25 at 11:09 -0800, Luis Carlos Cobo wrote:
> On Sat, 2008-02-23 at 15:17 +0100, Johannes Berg wrote:
> > This fixes missing unlocks noticed by sparse.
>
> Thanks for the fix. It would be easier though to just acquire the lock
> later, since rcu_read_lock() is no longer needed to look for mesh peer
> links, like in this patch (applied to the original version of the file
> without the patch included in the mail I'm replying to).
> u8 action = mgmt->u.action.u.mesh_action.action_code;
>
> - rcu_read_lock();
> sta = sta_info_get(local, mgmt->sa);
> if (!sta)
> return 0;
Ah, but sta_info_get will require rcu locking after a few more patches
so I now that I posted both sets this is easier (otherwise the sta info
rcu-ification would have to add all the code and revert this patch)
johannes
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 828 bytes --]
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 17/18] mac80211: mesh hwmp locking fixes
2008-02-25 19:09 ` Johannes Berg
@ 2008-02-25 19:41 ` Luis Carlos Cobo
0 siblings, 0 replies; 29+ messages in thread
From: Luis Carlos Cobo @ 2008-02-25 19:41 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless
On Mon, 2008-02-25 at 20:09 +0100, Johannes Berg wrote:
> Ah, but sta_info_get will require rcu locking after a few more patches
> so I now that I posted both sets this is easier (otherwise the sta info
> rcu-ification would have to add all the code and revert this patch)
You're right, just noticed the sta rcu-ification process.
--
Luis Carlos Cobo Rus GnuPG ID: 44019B60
cozybit Inc.
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 18/18] mac80211: enable mesh in Kconfig
2008-02-23 14:17 ` [PATCH 18/18] mac80211: enable mesh in Kconfig Johannes Berg
@ 2008-02-25 20:58 ` Luis Carlos Cobo
2008-02-25 21:24 ` Johannes Berg
0 siblings, 1 reply; 29+ messages in thread
From: Luis Carlos Cobo @ 2008-02-25 20:58 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless
On Sat, 2008-02-23 at 15:17 +0100, Johannes Berg wrote:
> Currently marked BROKEN because of endianness problems.
Will take care of those problems.
--
Luis Carlos Cobo Rus GnuPG ID: 44019B60
cozybit Inc.
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 18/18] mac80211: enable mesh in Kconfig
2008-02-25 20:58 ` Luis Carlos Cobo
@ 2008-02-25 21:24 ` Johannes Berg
2008-02-25 23:27 ` Luis Carlos Cobo
0 siblings, 1 reply; 29+ messages in thread
From: Johannes Berg @ 2008-02-25 21:24 UTC (permalink / raw)
To: Luis Carlos Cobo; +Cc: linux-wireless
[-- Attachment #1: Type: text/plain, Size: 648 bytes --]
On Mon, 2008-02-25 at 12:58 -0800, Luis Carlos Cobo wrote:
> On Sat, 2008-02-23 at 15:17 +0100, Johannes Berg wrote:
> > Currently marked BROKEN because of endianness problems.
>
> Will take care of those problems.
Oh this reminds me.
You have a lot of macros like
#define PREQ_IE_ORIG_DSN(x) le32_to_cpu(*((u32 *) (x + 13)))
Would it be possible to define the preq IE as a struct? Not sure if it
is. Either way, this should be converted to a static inline instead of a
macro.
Also, you need to add a lot of get_unaligned() to the code. Please read
Daniel's excellent Documentation/unaligned-memory-access.txt
johannes
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 828 bytes --]
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 18/18] mac80211: enable mesh in Kconfig
2008-02-25 21:24 ` Johannes Berg
@ 2008-02-25 23:27 ` Luis Carlos Cobo
0 siblings, 0 replies; 29+ messages in thread
From: Luis Carlos Cobo @ 2008-02-25 23:27 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless
On Mon, 2008-02-25 at 22:24 +0100, Johannes Berg wrote:
> #define PREQ_IE_ORIG_DSN(x) le32_to_cpu(*((u32 *) (x + 13)))
>
> Would it be possible to define the preq IE as a struct? Not sure if it
> is. Either way, this should be converted to a static inline instead of a
> macro.
The problem is that preq and prep IEs do not have a fixed size.
Depending on the address extension bit, they can have or not a 6 byte
proxied address in the middle, so I would need 4 structures.
>
> Also, you need to add a lot of get_unaligned() to the code. Please read
> Daniel's excellent Documentation/unaligned-memory-access.txt
Will do.
--
Luis Carlos Cobo Rus GnuPG ID: 44019B60
cozybit Inc.
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 13/18] mac80211: mesh statistics and config through debugfs
2008-02-23 14:17 ` [PATCH 13/18] mac80211: mesh statistics and config through debugfs Johannes Berg
@ 2008-03-28 6:16 ` Andrew Morton
2008-03-31 21:55 ` Luis Carlos Cobo
2008-03-28 6:38 ` Andrew Morton
1 sibling, 1 reply; 29+ messages in thread
From: Andrew Morton @ 2008-03-28 6:16 UTC (permalink / raw)
To: Johannes Berg; +Cc: John Linville, linux-wireless, Luis Carlos Cobo
On Sat, 23 Feb 2008 15:17:16 +0100 Johannes Berg <johannes@sipsolutions.net> wrote:
>
> This patch contains the debugfs code for mesh statistics and configuration
> parameters. Please note that generic support for r/w debugfs attributes has been
> added.
y'know, we have carefully developed all this lovely runtime self-checking
code in the kernel which can catch all sorts of common errors and yet it's
a continual struggle to get kernel developers *of all people* to actually
TURN THE DAMN THINGS ON.
So. I would ask everyone who "tested" this patch to
- read Documentation/SubmitChecklist
- suitable modify your .config
- SAVE A COPY OF THE THING!!!!!
- then fix the obvious, trivial, instantly-detectable, very-deadlockable
bug in this patch. There is just no longer any excuse for this:
+ read_lock(&dev_base_lock);
+ if (copy_from_user(buf, userbuf, buf_size))
Thanks.
There's also a question regarding review quality - I spotted that bug the
instant I looked at the patch. It's not exactly subtle.
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 13/18] mac80211: mesh statistics and config through debugfs
2008-02-23 14:17 ` [PATCH 13/18] mac80211: mesh statistics and config through debugfs Johannes Berg
2008-03-28 6:16 ` Andrew Morton
@ 2008-03-28 6:38 ` Andrew Morton
2008-03-31 21:48 ` Luis Carlos Cobo
1 sibling, 1 reply; 29+ messages in thread
From: Andrew Morton @ 2008-03-28 6:38 UTC (permalink / raw)
To: Johannes Berg; +Cc: John Linville, linux-wireless, Luis Carlos Cobo
On Sat, 23 Feb 2008 15:17:16 +0100 Johannes Berg <johannes@sipsolutions.net> wrote:
>
> This patch contains the debugfs code for mesh statistics and configuration
> parameters. Please note that generic support for r/w debugfs attributes has been
> added.
Would it be OK if we do this?
From: Andrew Morton <akpm@linux-foundation.org>
This bool causes my gcc-4.1.0 alpha cross compiler to go into an infinite
loop. Switching it to u8 works around that.
Cc: Johannes Berg <johannes@sipsolutions.net>
Cc: John Linville <linville@tuxdriver.com>
Cc: Luis Carlos Cobo <luisca@cozybit.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
net/mac80211/debugfs_netdev.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff -puN net/mac80211/debugfs_netdev.c~net-mac80211-debugfs_netdevc-use-of-bool-triggers-a-gcc-bug net/mac80211/debugfs_netdev.c
--- a/net/mac80211/debugfs_netdev.c~net-mac80211-debugfs_netdevc-use-of-bool-triggers-a-gcc-bug
+++ a/net/mac80211/debugfs_netdev.c
@@ -222,7 +222,7 @@ IEEE80211_IF_WFILE(dot11MeshConfirmTimeo
IEEE80211_IF_WFILE(dot11MeshHoldingTimeout,
u.sta.mshcfg.dot11MeshHoldingTimeout, DEC, u16);
IEEE80211_IF_WFILE(dot11MeshTTL, u.sta.mshcfg.dot11MeshTTL, DEC, u8);
-IEEE80211_IF_WFILE(auto_open_plinks, u.sta.mshcfg.auto_open_plinks, DEC, bool);
+IEEE80211_IF_WFILE(auto_open_plinks, u.sta.mshcfg.auto_open_plinks, DEC, u8);
IEEE80211_IF_WFILE(dot11MeshMaxPeerLinks,
u.sta.mshcfg.dot11MeshMaxPeerLinks, DEC, u16);
IEEE80211_IF_WFILE(dot11MeshHWMPactivePathTimeout,
_
quite a few people are (hopefully) using the alpha cross-compiler from
http://userweb.kernel.org/~akpm/cross-compilers/, and this is rather an
inconvenience.
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 13/18] mac80211: mesh statistics and config through debugfs
2008-03-28 6:38 ` Andrew Morton
@ 2008-03-31 21:48 ` Luis Carlos Cobo
0 siblings, 0 replies; 29+ messages in thread
From: Luis Carlos Cobo @ 2008-03-31 21:48 UTC (permalink / raw)
To: Andrew Morton; +Cc: Johannes Berg, John Linville, linux-wireless
On Thu, 2008-03-27 at 23:38 -0700, Andrew Morton wrote:
> Would it be OK if we do this?
>=20
> From: Andrew Morton <akpm@linux-foundation.org>
> -IEEE80211_IF_WFILE(auto_open_plinks, u.sta.mshcfg.auto_open_plinks, =
DEC, bool);
> +IEEE80211_IF_WFILE(auto_open_plinks, u.sta.mshcfg.auto_open_plinks, =
DEC, u8);
> IEEE80211_IF_WFILE(dot11MeshMaxPeerLinks,
> u.sta.mshcfg.dot11MeshMaxPeerLinks, DEC, u16);
> IEEE80211_IF_WFILE(dot11MeshHWMPactivePathTimeout,
> _
>=20
=EF=BB=BFUsing bool ensures that only boolean values can be written to =
that
debugfs file. It is just used to cast the value, I do not know why that
causes any problem.
Anyway, using u8 would work almost the same, so it is an acceptable
solution if there is no other easy workaround.
--=20
Luis Carlos Cobo Rus GnuPG ID: 44019B60
cozybit Inc.
--
To unsubscribe from this list: send the line "unsubscribe linux-wireles=
s" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 13/18] mac80211: mesh statistics and config through debugfs
2008-03-28 6:16 ` Andrew Morton
@ 2008-03-31 21:55 ` Luis Carlos Cobo
0 siblings, 0 replies; 29+ messages in thread
From: Luis Carlos Cobo @ 2008-03-31 21:55 UTC (permalink / raw)
To: Andrew Morton; +Cc: Johannes Berg, John Linville, linux-wireless
On Thu, 2008-03-27 at 23:16 -0700, Andrew Morton wrote:
> - then fix the obvious, trivial, instantly-detectable, very-deadlocka=
ble
> bug in this patch. There is just no longer any excuse for this:
>=20
> + read_lock(&dev_base_lock);
> + if (copy_from_user(buf, userbuf, buf_size))
=EF=BB=BFAs the author of the patch, I would like to apologize about th=
is.=20
Regarding review quality, I would like to point out that the function
just above this one, ieee80211_if_read(), which has been for a while in
the stable releases, suffers the same problem. That does not excuse
myself though, I should have spotted and fixed it and then implement
ieee80211_if_write() properly. I will send a patch fixing both issues
today.
Again sorry for the mess and thank you for spotting the problem.
--=20
Luis Carlos Cobo Rus GnuPG ID: 44019B60
cozybit Inc.
--
To unsubscribe from this list: send the line "unsubscribe linux-wireles=
s" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 29+ messages in thread
end of thread, other threads:[~2008-03-31 21:56 UTC | newest]
Thread overview: 29+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-02-23 14:17 [PATCH 00/18] mac80211 802.11s networking code Johannes Berg
2008-02-23 14:17 ` [PATCH 01/18] wireless: various definitions for mesh networking Johannes Berg
2008-02-23 14:17 ` [PATCH 02/18] WEXT: add mesh interface type Johannes Berg
2008-02-23 14:17 ` [PATCH 03/18] nl80211/cfg80211: support for mesh, sta dumping Johannes Berg
2008-02-23 14:17 ` [PATCH 04/18] mac80211: add mesh interface type Johannes Berg
2008-02-23 14:17 ` [PATCH 05/18] mac80211: mesh function and data structures definitions Johannes Berg
2008-02-23 14:17 ` [PATCH 06/18] mac80211: support functions for mesh Johannes Berg
2008-02-23 14:17 ` [PATCH 07/18] mac80211: support for mesh interfaces in mac80211 data path Johannes Berg
2008-02-23 14:17 ` [PATCH 08/18] mac80211: mesh data structures and first mesh changes Johannes Berg
2008-02-23 14:17 ` [PATCH 09/18] mac80211: mesh changes to the MLME Johannes Berg
2008-02-23 14:17 ` [PATCH 10/18] mac80211: mesh peer link implementation Johannes Berg
2008-02-23 14:17 ` [PATCH 11/18] mac80211: mesh path table implementation Johannes Berg
2008-02-23 14:17 ` [PATCH 12/18] mac80211: code for on-demand Hybrid Wireless Mesh Protocol Johannes Berg
2008-02-23 14:17 ` [PATCH 13/18] mac80211: mesh statistics and config through debugfs Johannes Berg
2008-03-28 6:16 ` Andrew Morton
2008-03-31 21:55 ` Luis Carlos Cobo
2008-03-28 6:38 ` Andrew Morton
2008-03-31 21:48 ` Luis Carlos Cobo
2008-02-23 14:17 ` [PATCH 14/18] mac80211: mesh path and mesh peer configuration Johannes Berg
2008-02-23 14:17 ` [PATCH 15/18] mac80211: complete the mesh (interface handling) code Johannes Berg
2008-02-23 14:17 ` [PATCH 16/18] mac80211: clean up mesh code Johannes Berg
2008-02-23 14:17 ` [PATCH 17/18] mac80211: mesh hwmp locking fixes Johannes Berg
2008-02-25 19:09 ` Luis Carlos Cobo
2008-02-25 19:09 ` Johannes Berg
2008-02-25 19:41 ` Luis Carlos Cobo
2008-02-23 14:17 ` [PATCH 18/18] mac80211: enable mesh in Kconfig Johannes Berg
2008-02-25 20:58 ` Luis Carlos Cobo
2008-02-25 21:24 ` Johannes Berg
2008-02-25 23:27 ` Luis Carlos Cobo
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).