@@ -1759,6 +1759,10 @@ struct ieee80211_ops {
u32 iv32, u16 *phase1key);
int (*hw_scan)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct cfg80211_scan_request *req);
+ int (*periodic_start)(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif);
+ int (*periodic_stop)(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif);
void (*sw_scan_start)(struct ieee80211_hw *hw);
void (*sw_scan_complete)(struct ieee80211_hw *hw);
int (*get_stats)(struct ieee80211_hw *hw,
@@ -1223,6 +1223,30 @@ static int ieee80211_scan(struct wiphy *wiphy,
return ieee80211_request_scan(sdata, req);
}
+static int ieee80211_periodic_start(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct cfg80211_periodic_request *req)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ if(!sdata->local->ops->periodic_start)
+ return -EOPNOTSUPP;
+
+ return ieee80211_request_periodic_start(sdata, req);
+}
+
+static int ieee80211_periodic_stop(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct cfg80211_periodic_request *req)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ if(!sdata->local->ops->periodic_stop)
+ return -EOPNOTSUPP;
+
+ return ieee80211_request_periodic_stop(sdata);
+}
+
static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_auth_request *req)
{
@@ -1654,6 +1678,8 @@ struct cfg80211_ops mac80211_config_ops = {
.suspend = ieee80211_suspend,
.resume = ieee80211_resume,
.scan = ieee80211_scan,
+ .periodic_start= ieee80211_periodic_start,
+ .periodic_stop= ieee80211_periodic_stop,
.auth = ieee80211_auth,
.assoc = ieee80211_assoc,
.deauth = ieee80211_deauth,
@@ -191,6 +191,32 @@ static inline int drv_hw_scan(struct ieee80211_local *local,
return ret;
}
+static inline int drv_periodic_start(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata)
+{
+ int ret;
+
+ might_sleep();
+
+ trace_drv_periodic_start(local, sdata);
+ ret = local->ops->periodic_start(&local->hw, &sdata->vif);
+ trace_drv_return_int(local, ret);
+ return ret;
+}
+
+static inline int drv_periodic_stop(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata)
+{
+ int ret;
+
+ might_sleep();
+
+ trace_drv_periodic_stop(local, sdata);
+ ret = local->ops->periodic_stop(&local->hw, &sdata->vif);
+ trace_drv_return_int(local, ret);
+ return ret;
+}
+
static inline void drv_sw_scan_start(struct ieee80211_local *local)
{
might_sleep();
@@ -439,6 +439,50 @@ TRACE_EVENT(drv_hw_scan,
)
);
+TRACE_EVENT(drv_periodic_start,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata),
+
+ TP_ARGS(local, sdata),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ VIF_ENTRY
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ VIF_ASSIGN;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT VIF_PR_FMT,
+ LOCAL_PR_ARG,VIF_PR_ARG
+ )
+);
+
+TRACE_EVENT(drv_periodic_stop,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata),
+
+ TP_ARGS(local, sdata),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ VIF_ENTRY
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ VIF_ASSIGN;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT VIF_PR_FMT,
+ LOCAL_PR_ARG,VIF_PR_ARG
+ )
+);
+
TRACE_EVENT(drv_sw_scan_start,
TP_PROTO(struct ieee80211_local *local),
@@ -812,6 +812,7 @@ struct ieee80211_local {
struct cfg80211_ssid scan_ssid;
struct cfg80211_scan_request *int_scan_req;
struct cfg80211_scan_request *scan_req, *hw_scan_req;
+ struct cfg80211_periodic_request *periodic_req;
struct ieee80211_channel *scan_channel;
enum ieee80211_band hw_scan_band;
int scan_channel_idx;
@@ -1115,6 +1116,11 @@ ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq,
void ieee80211_rx_bss_put(struct ieee80211_local *local,
struct ieee80211_bss *bss);
+/* periodic scan handling */
+int ieee80211_request_periodic_start(struct ieee80211_sub_if_data *sdata,
+ struct cfg80211_periodic_request *req);
+int ieee80211_request_periodic_stop(struct ieee80211_sub_if_data *sdata);
+
/* off-channel helpers */
void ieee80211_offchannel_stop_beaconing(struct ieee80211_local *local);
void ieee80211_offchannel_stop_station(struct ieee80211_local *local);
@@ -823,3 +823,57 @@ void ieee80211_scan_cancel(struct ieee80211_local *local)
if (finish)
__ieee80211_scan_completed_finish(&local->hw, false);
}
+
+int ieee80211_request_periodic_start(struct ieee80211_sub_if_data *sdata,
+ struct cfg80211_periodic_request *req)
+{
+ struct ieee80211_local *local = sdata->local;
+ int ret;
+
+ mutex_lock(&sdata->local->mtx);
+
+ /* FIXME: check if hw scanning or associated and return -EBUSY */
+
+ if (local->periodic_req) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ if (!local->ops->periodic_start) {
+ ret = -ENOTSUPP;
+ goto out;
+ }
+
+ local->periodic_req = req;
+
+ ret = drv_periodic_start(local, sdata);
+ if (ret)
+ local->periodic_req = NULL;
+out:
+ mutex_unlock(&sdata->local->mtx);
+
+ return ret;
+}
+
+int ieee80211_request_periodic_stop(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_local *local = sdata->local;
+ int ret = 0;
+
+ mutex_lock(&sdata->local->mtx);
+
+ if (!local->ops->periodic_stop) {
+ ret = -ENOTSUPP;
+ goto out;
+ }
+
+ if (local->periodic_req) {
+ ret = drv_periodic_stop(local, sdata);
+ local->periodic_req = NULL;
+ }
+
+out:
+ mutex_unlock(&sdata->local->mtx);
+
+ return ret;
+}