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, \
{ \
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) \
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);
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)
/* 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);
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)
{
}
+#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);
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)
{
}
+#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);