Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 327660
b: refs/heads/master
c: 98104fd
h: refs/heads/master
v: v3
  • Loading branch information
Johannes Berg committed Aug 20, 2012
1 parent 3d7d9e7 commit e8eec97
Show file tree
Hide file tree
Showing 10 changed files with 266 additions and 21 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: cc74c0c7d6d623d0d3f13ef64895937edb7b3177
refs/heads/master: 98104fdeda63d57631c9f89e90a7b83b58fcee40
30 changes: 26 additions & 4 deletions trunk/include/linux/nl80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,14 @@
* %NL80211_ATTR_IFINDEX is now on %NL80211_ATTR_WIPHY_FREQ with
* %NL80211_ATTR_WIPHY_CHANNEL_TYPE.
*
* @NL80211_CMD_START_P2P_DEVICE: Start the given P2P Device, identified by
* its %NL80211_ATTR_WDEV identifier. It must have been created with
* %NL80211_CMD_NEW_INTERFACE previously. After it has been started, the
* P2P Device can be used for P2P operations, e.g. remain-on-channel and
* public action frame TX.
* @NL80211_CMD_STOP_P2P_DEVICE: Stop the given P2P Device, identified by
* its %NL80211_ATTR_WDEV identifier.
*
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
Expand Down Expand Up @@ -708,6 +716,9 @@ enum nl80211_commands {

NL80211_CMD_CH_SWITCH_NOTIFY,

NL80211_CMD_START_P2P_DEVICE,
NL80211_CMD_STOP_P2P_DEVICE,

/* add new commands above here */

/* used to define NL80211_CMD_MAX below */
Expand Down Expand Up @@ -1575,6 +1586,10 @@ enum nl80211_attrs {
* @NL80211_IFTYPE_MESH_POINT: mesh point
* @NL80211_IFTYPE_P2P_CLIENT: P2P client
* @NL80211_IFTYPE_P2P_GO: P2P group owner
* @NL80211_IFTYPE_P2P_DEVICE: P2P device interface type, this is not a netdev
* and therefore can't be created in the normal ways, use the
* %NL80211_CMD_START_P2P_DEVICE and %NL80211_CMD_STOP_P2P_DEVICE
* commands to create and destroy one
* @NL80211_IFTYPE_MAX: highest interface type number currently defined
* @NUM_NL80211_IFTYPES: number of defined interface types
*
Expand All @@ -1593,6 +1608,7 @@ enum nl80211_iftype {
NL80211_IFTYPE_MESH_POINT,
NL80211_IFTYPE_P2P_CLIENT,
NL80211_IFTYPE_P2P_GO,
NL80211_IFTYPE_P2P_DEVICE,

/* keep last */
NUM_NL80211_IFTYPES,
Expand Down Expand Up @@ -2994,12 +3010,18 @@ enum nl80211_ap_sme_features {
* @NL80211_FEATURE_CELL_BASE_REG_HINTS: This driver has been tested
* to work properly to suppport receiving regulatory hints from
* cellular base stations.
* @NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL: If this is set, an active
* P2P Device (%NL80211_IFTYPE_P2P_DEVICE) requires its own channel
* in the interface combinations, even when it's only used for scan
* and remain-on-channel. This could be due to, for example, the
* remain-on-channel implementation requiring a channel context.
*/
enum nl80211_feature_flags {
NL80211_FEATURE_SK_TX_STATUS = 1 << 0,
NL80211_FEATURE_HT_IBSS = 1 << 1,
NL80211_FEATURE_INACTIVITY_TIMER = 1 << 2,
NL80211_FEATURE_CELL_BASE_REG_HINTS = 1 << 3,
NL80211_FEATURE_SK_TX_STATUS = 1 << 0,
NL80211_FEATURE_HT_IBSS = 1 << 1,
NL80211_FEATURE_INACTIVITY_TIMER = 1 << 2,
NL80211_FEATURE_CELL_BASE_REG_HINTS = 1 << 3,
NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL = 1 << 4,
};

/**
Expand Down
40 changes: 38 additions & 2 deletions trunk/include/net/cfg80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -1437,7 +1437,8 @@ struct cfg80211_gtk_rekey_data {
* @add_virtual_intf: create a new virtual interface with the given name,
* must set the struct wireless_dev's iftype. Beware: You must create
* the new netdev in the wiphy's network namespace! Returns the struct
* wireless_dev, or an ERR_PTR.
* wireless_dev, or an ERR_PTR. For P2P device wdevs, the driver must
* also set the address member in the wdev.
*
* @del_virtual_intf: remove the virtual interface
*
Expand Down Expand Up @@ -1616,6 +1617,9 @@ struct cfg80211_gtk_rekey_data {
* @get_channel: Get the current operating channel for the virtual interface.
* For monitor interfaces, it should return %NULL unless there's a single
* current monitoring channel.
*
* @start_p2p_device: Start the given P2P device.
* @stop_p2p_device: Stop the given P2P device.
*/
struct cfg80211_ops {
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
Expand Down Expand Up @@ -1832,6 +1836,11 @@ struct cfg80211_ops {
(*get_channel)(struct wiphy *wiphy,
struct wireless_dev *wdev,
enum nl80211_channel_type *type);

int (*start_p2p_device)(struct wiphy *wiphy,
struct wireless_dev *wdev);
void (*stop_p2p_device)(struct wiphy *wiphy,
struct wireless_dev *wdev);
};

/*
Expand Down Expand Up @@ -2395,6 +2404,8 @@ struct cfg80211_cached_keys;
* @cleanup_work: work struct used for cleanup that can't be done directly
* @beacon_interval: beacon interval used on this device for transmitting
* beacons, 0 when not valid
* @address: The address for this device, valid only if @netdev is %NULL
* @p2p_started: true if this is a P2P Device that has been started
*/
struct wireless_dev {
struct wiphy *wiphy;
Expand All @@ -2413,7 +2424,9 @@ struct wireless_dev {

struct work_struct cleanup_work;

bool use_4addr;
bool use_4addr, p2p_started;

u8 address[ETH_ALEN] __aligned(sizeof(u16));

/* currently used for IBSS and SME - might be rearranged later */
u8 ssid[IEEE80211_MAX_SSID_LEN];
Expand Down Expand Up @@ -2461,6 +2474,13 @@ struct wireless_dev {
#endif
};

static inline u8 *wdev_address(struct wireless_dev *wdev)
{
if (wdev->netdev)
return wdev->netdev->dev_addr;
return wdev->address;
}

/**
* wdev_priv - return wiphy priv from wireless_dev
*
Expand Down Expand Up @@ -3528,6 +3548,22 @@ void cfg80211_ch_switch_notify(struct net_device *dev, int freq,
*/
u32 cfg80211_calculate_bitrate(struct rate_info *rate);

/**
* cfg80211_unregister_wdev - remove the given wdev
* @wdev: struct wireless_dev to remove
*
* Call this function only for wdevs that have no netdev assigned,
* e.g. P2P Devices. It removes the device from the list so that
* it can no longer be used. It is necessary to call this function
* even when cfg80211 requests the removal of the interface by
* calling the del_virtual_intf() callback. The function must also
* be called when the driver wishes to unregister the wdev, e.g.
* when the device is unbound from the driver.
*
* Requires the RTNL to be held.
*/
void cfg80211_unregister_wdev(struct wireless_dev *wdev);

/* Logging, debugging and troubleshooting/diagnostic helpers. */

/* wiphy_printk helpers, similar to dev_printk */
Expand Down
3 changes: 3 additions & 0 deletions trunk/net/mac80211/iface.c
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,7 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
case NUM_NL80211_IFTYPES:
case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_P2P_GO:
case NL80211_IFTYPE_P2P_DEVICE:
/* cannot happen */
WARN_ON(1);
break;
Expand Down Expand Up @@ -1146,6 +1147,8 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
case NL80211_IFTYPE_WDS:
case NL80211_IFTYPE_AP_VLAN:
break;
case NL80211_IFTYPE_P2P_DEVICE:
/* not yet supported */
case NL80211_IFTYPE_UNSPECIFIED:
case NUM_NL80211_IFTYPES:
BUG();
Expand Down
2 changes: 2 additions & 0 deletions trunk/net/mac80211/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -1390,6 +1390,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)
case NL80211_IFTYPE_MONITOR:
/* ignore virtual */
break;
case NL80211_IFTYPE_P2P_DEVICE:
/* not yet supported */
case NL80211_IFTYPE_UNSPECIFIED:
case NUM_NL80211_IFTYPES:
case NL80211_IFTYPE_P2P_CLIENT:
Expand Down
7 changes: 6 additions & 1 deletion trunk/net/wireless/chan.c
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ cfg80211_get_chan_state(struct wireless_dev *wdev,

ASSERT_WDEV_LOCK(wdev);

if (!netif_running(wdev->netdev))
if (wdev->netdev && !netif_running(wdev->netdev))
return;

switch (wdev->iftype) {
Expand Down Expand Up @@ -143,6 +143,11 @@ cfg80211_get_chan_state(struct wireless_dev *wdev,
case NL80211_IFTYPE_WDS:
/* these interface types don't really have a channel */
return;
case NL80211_IFTYPE_P2P_DEVICE:
if (wdev->wiphy->features &
NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL)
*chanmode = CHAN_MODE_EXCLUSIVE;
return;
case NL80211_IFTYPE_UNSPECIFIED:
case NUM_NL80211_IFTYPES:
WARN_ON(1);
Expand Down
53 changes: 51 additions & 2 deletions trunk/net/wireless/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -230,9 +230,24 @@ static int cfg80211_rfkill_set_block(void *data, bool blocked)
rtnl_lock();
mutex_lock(&rdev->devlist_mtx);

list_for_each_entry(wdev, &rdev->wdev_list, list)
if (wdev->netdev)
list_for_each_entry(wdev, &rdev->wdev_list, list) {
if (wdev->netdev) {
dev_close(wdev->netdev);
continue;
}
/* otherwise, check iftype */
switch (wdev->iftype) {
case NL80211_IFTYPE_P2P_DEVICE:
if (!wdev->p2p_started)
break;
rdev->ops->stop_p2p_device(&rdev->wiphy, wdev);
wdev->p2p_started = false;
rdev->opencount--;
break;
default:
break;
}
}

mutex_unlock(&rdev->devlist_mtx);
rtnl_unlock();
Expand Down Expand Up @@ -407,6 +422,11 @@ static int wiphy_verify_combinations(struct wiphy *wiphy)
if (WARN_ON(wiphy->software_iftypes & types))
return -EINVAL;

/* Only a single P2P_DEVICE can be allowed */
if (WARN_ON(types & BIT(NL80211_IFTYPE_P2P_DEVICE) &&
c->limits[j].max > 1))
return -EINVAL;

cnt += c->limits[j].max;
/*
* Don't advertise an unsupported type
Expand Down Expand Up @@ -734,6 +754,35 @@ static void wdev_cleanup_work(struct work_struct *work)
dev_put(wdev->netdev);
}

void cfg80211_unregister_wdev(struct wireless_dev *wdev)
{
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);

ASSERT_RTNL();

if (WARN_ON(wdev->netdev))
return;

mutex_lock(&rdev->devlist_mtx);
list_del_rcu(&wdev->list);
rdev->devlist_generation++;

switch (wdev->iftype) {
case NL80211_IFTYPE_P2P_DEVICE:
if (!wdev->p2p_started)
break;
rdev->ops->stop_p2p_device(&rdev->wiphy, wdev);
wdev->p2p_started = false;
rdev->opencount--;
break;
default:
WARN_ON_ONCE(1);
break;
}
mutex_unlock(&rdev->devlist_mtx);
}
EXPORT_SYMBOL(cfg80211_unregister_wdev);

static struct device_type wiphy_type = {
.name = "wlan",
};
Expand Down
10 changes: 7 additions & 3 deletions trunk/net/wireless/mlme.c
Original file line number Diff line number Diff line change
Expand Up @@ -736,7 +736,6 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
const u8 *buf, size_t len, bool no_cck,
bool dont_wait_for_ack, u64 *cookie)
{
struct net_device *dev = wdev->netdev;
const struct ieee80211_mgmt *mgmt;
u16 stype;

Expand Down Expand Up @@ -796,7 +795,7 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_P2P_GO:
case NL80211_IFTYPE_AP_VLAN:
if (!ether_addr_equal(mgmt->bssid, dev->dev_addr))
if (!ether_addr_equal(mgmt->bssid, wdev_address(wdev)))
err = -EINVAL;
break;
case NL80211_IFTYPE_MESH_POINT:
Expand All @@ -809,6 +808,11 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
* cfg80211 doesn't track the stations
*/
break;
case NL80211_IFTYPE_P2P_DEVICE:
/*
* fall through, P2P device only supports
* public action frames
*/
default:
err = -EOPNOTSUPP;
break;
Expand All @@ -819,7 +823,7 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
return err;
}

if (!ether_addr_equal(mgmt->sa, dev->dev_addr))
if (!ether_addr_equal(mgmt->sa, wdev_address(wdev)))
return -EINVAL;

/* Transmit the Action frame as requested by user space */
Expand Down
Loading

0 comments on commit e8eec97

Please sign in to comment.