/*
- * Copyright (c) 2008 open80211s Ltd.
+ * Copyright (c) 2008, 2009 open80211s Ltd.
* Author: Luis Carlos Cobo <luisca@cozybit.com>
*
* This program is free software; you can redistribute it and/or modify
#define mpl_dbg(fmt, args...) do { (void)(0); } while (0)
#endif
-#define PLINK_GET_FRAME_SUBTYPE(p) (p)
-#define PLINK_GET_LLID(p) (p + 1)
-#define PLINK_GET_PLID(p) (p + 3)
+#define PLINK_GET_LLID(p) (p + 4)
+#define PLINK_GET_PLID(p) (p + 6)
#define mod_plink_timer(s, t) (mod_timer(&s->plink_timer, \
jiffies + HZ * t / 1000))
{
atomic_inc(&sdata->u.mesh.mshstats.estab_plinks);
mesh_accept_plinks_update(sdata);
+ ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
}
static inline
{
atomic_dec(&sdata->u.mesh.mshstats.estab_plinks);
mesh_accept_plinks_update(sdata);
+ ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
}
/**
* mesh_plink_fsm_restart - restart a mesh peer link finite state machine
*
- * @sta: mes peer link to restart
+ * @sta: mesh peer link to restart
*
* Locking: this function must be called holding sta->lock
*/
* on it in the lifecycle management section!
*/
static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,
- u8 *hw_addr, u64 rates)
+ u8 *hw_addr, u32 rates)
{
struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
return NULL;
sta->flags = WLAN_STA_AUTHORIZED;
- sta->supp_rates[local->hw.conf.channel->band] = rates;
+ sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
+ rate_control_rate_init(sta);
return sta;
}
struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
struct ieee80211_mgmt *mgmt;
bool include_plid = false;
+ static const u8 meshpeeringproto[] = { 0x00, 0x0F, 0xAC, 0x2A };
u8 *pos;
int ie_len;
memcpy(mgmt->da, da, ETH_ALEN);
memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
/* BSSID is left zeroed, wildcard value */
- mgmt->u.action.category = PLINK_CATEGORY;
+ mgmt->u.action.category = MESH_PLINK_CATEGORY;
mgmt->u.action.u.plink_action.action_code = action;
if (action == PLINK_CLOSE)
if (action == PLINK_CONFIRM) {
pos = skb_put(skb, 4);
/* two-byte status code followed by two-byte AID */
- memset(pos, 0, 4);
+ memset(pos, 0, 2);
+ memcpy(pos + 2, &plid, 2);
}
mesh_mgmt_ies_add(skb, sdata);
}
/* Add Peer Link Management element */
switch (action) {
case PLINK_OPEN:
- ie_len = 3;
+ ie_len = 6;
break;
case PLINK_CONFIRM:
- ie_len = 5;
+ ie_len = 8;
include_plid = true;
break;
case PLINK_CLOSE:
default:
if (!plid)
- ie_len = 5;
+ ie_len = 8;
else {
- ie_len = 7;
+ ie_len = 10;
include_plid = true;
}
break;
pos = skb_put(skb, 2 + ie_len);
*pos++ = WLAN_EID_PEER_LINK;
*pos++ = ie_len;
- *pos++ = action;
+ memcpy(pos, meshpeeringproto, sizeof(meshpeeringproto));
+ pos += 4;
memcpy(pos, &llid, 2);
if (include_plid) {
pos += 2;
memcpy(pos, &reason, 2);
}
- ieee80211_tx_skb(sdata, skb, 0);
+ ieee80211_tx_skb(sdata, skb);
return 0;
}
-void mesh_neighbour_update(u8 *hw_addr, u64 rates, struct ieee80211_sub_if_data *sdata,
+void mesh_neighbour_update(u8 *hw_addr, u32 rates, struct ieee80211_sub_if_data *sdata,
bool peer_accepting_plinks)
{
struct ieee80211_local *local = sdata->local;
}
sta->last_rx = jiffies;
- sta->supp_rates[local->hw.conf.channel->band] = rates;
+ sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
if (peer_accepting_plinks && sta->plink_state == PLINK_LISTEN &&
sdata->u.mesh.accepting_plinks &&
sdata->u.mesh.mshcfg.auto_open_plinks)
struct sta_info *sta;
__le16 llid, plid, reason;
struct ieee80211_sub_if_data *sdata;
-#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
- DECLARE_MAC_BUF(mac);
-#endif
/*
* This STA is valid because sta_info_destroy() will
*/
sta = (struct sta_info *) data;
+ if (sta->sdata->local->quiescing) {
+ sta->plink_timer_was_running = true;
+ return;
+ }
+
spin_lock_bh(&sta->lock);
if (sta->ignore_plink_timer) {
sta->ignore_plink_timer = false;
spin_unlock_bh(&sta->lock);
return;
}
- mpl_dbg("Mesh plink timer for %s fired on state %d\n",
- print_mac(mac, sta->sta.addr), sta->plink_state);
+ mpl_dbg("Mesh plink timer for %pM fired on state %d\n",
+ sta->sta.addr, sta->plink_state);
reason = 0;
llid = sta->llid;
plid = sta->plid;
/* 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->sta.addr),
- sta->plink_retries, sta->plink_timeout);
+ mpl_dbg("Mesh plink for %pM (retry, timeout): %d %d\n",
+ sta->sta.addr, sta->plink_retries,
+ sta->plink_timeout);
get_random_bytes(&rand, sizeof(u32));
sta->plink_timeout = sta->plink_timeout +
rand % sta->plink_timeout;
}
}
+#ifdef CONFIG_PM
+void mesh_plink_quiesce(struct sta_info *sta)
+{
+ if (del_timer_sync(&sta->plink_timer))
+ sta->plink_timer_was_running = true;
+}
+
+void mesh_plink_restart(struct sta_info *sta)
+{
+ if (sta->plink_timer_was_running) {
+ add_timer(&sta->plink_timer);
+ sta->plink_timer_was_running = false;
+ }
+}
+#endif
+
static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout)
{
sta->plink_timer.expires = jiffies + (HZ * timeout / 1000);
{
__le16 llid;
struct ieee80211_sub_if_data *sdata = sta->sdata;
-#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
- DECLARE_MAC_BUF(mac);
-#endif
spin_lock_bh(&sta->lock);
get_random_bytes(&llid, 2);
sta->plink_state = PLINK_OPN_SNT;
mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata));
spin_unlock_bh(&sta->lock);
- mpl_dbg("Mesh plink: starting establishment with %s\n",
- print_mac(mac, sta->sta.addr));
+ mpl_dbg("Mesh plink: starting establishment with %pM\n",
+ sta->sta.addr);
return mesh_plink_frame_tx(sdata, PLINK_OPEN,
sta->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->lock);
__mesh_plink_deactivate(sta);
sta->plink_state = PLINK_BLOCKED;
spin_unlock_bh(&sta->lock);
}
-int mesh_plink_close(struct sta_info *sta)
-{
- struct ieee80211_sub_if_data *sdata = sta->sdata;
- __le16 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->sta.addr));
- spin_lock_bh(&sta->lock);
- sta->reason = cpu_to_le16(MESH_LINK_CANCELLED);
- reason = sta->reason;
-
- if (sta->plink_state == PLINK_LISTEN ||
- sta->plink_state == PLINK_BLOCKED) {
- mesh_plink_fsm_restart(sta);
- spin_unlock_bh(&sta->lock);
- return 0;
- } else if (sta->plink_state == PLINK_ESTAB) {
- __mesh_plink_deactivate(sta);
- /* The timer should not be running */
- mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata));
- } else if (!mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)))
- sta->ignore_plink_timer = true;
-
- sta->plink_state = PLINK_HOLDING;
- llid = sta->llid;
- plid = sta->plid;
- spin_unlock_bh(&sta->lock);
- mesh_plink_frame_tx(sta->sdata, PLINK_CLOSE, sta->sta.addr, llid,
- plid, reason);
- return 0;
-}
void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt,
size_t len, struct ieee80211_rx_status *rx_status)
u8 *baseaddr;
__le16 plid, llid, reason;
#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
- DECLARE_MAC_BUF(mac);
+ static const char *mplstates[] = {
+ [PLINK_LISTEN] = "LISTEN",
+ [PLINK_OPN_SNT] = "OPN-SNT",
+ [PLINK_OPN_RCVD] = "OPN-RCVD",
+ [PLINK_CNF_RCVD] = "CNF_RCVD",
+ [PLINK_ESTAB] = "ESTAB",
+ [PLINK_HOLDING] = "HOLDING",
+ [PLINK_BLOCKED] = "BLOCKED"
+ };
#endif
/* need action_code, aux */
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;
+ baselen += 4;
}
ieee802_11_parse_elems(baseaddr, len - baselen, &elems);
if (!elems.peer_link) {
return;
}
- ftype = *((u8 *)PLINK_GET_FRAME_SUBTYPE(elems.peer_link));
+ ftype = mgmt->u.action.u.plink_action.action_code;
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");
+ if ((ftype == PLINK_OPEN && ie_len != 6) ||
+ (ftype == PLINK_CONFIRM && ie_len != 8) ||
+ (ftype == PLINK_CLOSE && ie_len != 8 && ie_len != 10)) {
+ mpl_dbg("Mesh plink: incorrect plink ie length %d %d\n",
+ ftype, ie_len);
return;
}
* 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))
+ if (ftype == PLINK_CONFIRM || (ftype == PLINK_CLOSE && ie_len == 10))
memcpy(&llid, PLINK_GET_PLID(elems.peer_link), 2);
rcu_read_lock();
spin_lock_bh(&sta->lock);
} else if (!sta) {
/* ftype == PLINK_OPEN */
- u64 rates;
+ u32 rates;
if (!mesh_plink_free_count(sdata)) {
mpl_dbg("Mesh plink error: no more free plinks\n");
rcu_read_unlock();
}
}
- 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);
+ mpl_dbg("Mesh plink (peer, state, llid, plid, event): %pM %s %d %d %d\n",
+ mgmt->sa, mplstates[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 */
sta->plink_state = PLINK_ESTAB;
mesh_plink_inc_estab_count(sdata);
spin_unlock_bh(&sta->lock);
- mpl_dbg("Mesh plink with %s ESTABLISHED\n",
- print_mac(mac, sta->sta.addr));
+ mpl_dbg("Mesh plink with %pM ESTABLISHED\n",
+ sta->sta.addr);
break;
default:
spin_unlock_bh(&sta->lock);
sta->plink_state = PLINK_ESTAB;
mesh_plink_inc_estab_count(sdata);
spin_unlock_bh(&sta->lock);
- mpl_dbg("Mesh plink with %s ESTABLISHED\n",
- print_mac(mac, sta->sta.addr));
+ mpl_dbg("Mesh plink with %pM ESTABLISHED\n",
+ sta->sta.addr);
mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->sta.addr, llid,
plid, 0);
break;