Skip to content

Commit

Permalink
mac80211: mesh path and mesh peer configuration
Browse files Browse the repository at this point in the history
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>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Luis Carlos Cobo authored and John W. Linville committed Mar 6, 2008
1 parent 9f42f60 commit c5dd9c2
Showing 1 changed file with 259 additions and 10 deletions.
269 changes: 259 additions & 10 deletions net/mac80211/cfg.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -28,6 +33,10 @@ nl80211_type_to_mac80211_type(enum nl80211_iftype type)
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;
}
Expand Down Expand Up @@ -110,6 +119,15 @@ static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex,
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;

Expand Down Expand Up @@ -297,6 +315,51 @@ static int ieee80211_config_default_key(struct wiphy *wiphy,
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)
{
Expand All @@ -308,15 +371,7 @@ static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
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;
Expand Down Expand Up @@ -525,6 +580,9 @@ static void sta_apply_parameters(struct ieee80211_local *local,
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;
Expand Down Expand Up @@ -562,6 +620,19 @@ static void sta_apply_parameters(struct ieee80211_local *local,
}
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,
Expand All @@ -584,7 +655,13 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
} 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);

Expand Down Expand Up @@ -656,6 +733,170 @@ static int ieee80211_change_station(struct wiphy *wiphy,
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,
Expand All @@ -671,4 +912,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
};

0 comments on commit c5dd9c2

Please sign in to comment.