openwrt/package/d80211/src/ieee80211_sysfs_sta.c

438 lines
11 KiB
C

/*
* Copyright 2003-2005, Devicescape Software, Inc.
* Copyright (c) 2006 Jiri Benc <jbenc@suse.cz>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kobject.h>
#include <linux/sysfs.h>
#include "ieee80211_i.h"
#include "ieee80211_key.h"
#include "sta_info.h"
static ssize_t sta_sysfs_show(struct kobject *, struct attribute *, char *);
static ssize_t key_sysfs_show(struct kobject *, struct attribute *, char *);
static struct sysfs_ops sta_ktype_ops = {
.show = sta_sysfs_show,
};
static struct sysfs_ops key_ktype_ops = {
.show = key_sysfs_show,
};
/* sta attributtes */
#define STA_SHOW(name, field, format_string) \
static ssize_t show_sta_##name(const struct sta_info *sta, char *buf) \
{ \
return sprintf(buf, format_string, sta->field); \
}
#define STA_SHOW_D(name, field) STA_SHOW(name, field, "%d\n")
#define STA_SHOW_U(name, field) STA_SHOW(name, field, "%u\n")
#define STA_SHOW_LU(name, field) STA_SHOW(name, field, "%lu\n")
#define STA_SHOW_S(name, field) STA_SHOW(name, field, "%s\n")
#define STA_SHOW_RATE(name, field) \
static ssize_t show_sta_##name(const struct sta_info *sta, char *buf) \
{ \
struct ieee80211_local *local = sta->dev->ieee80211_ptr; \
return sprintf(buf, "%d\n", \
(sta->field >= 0 && \
sta->field < local->num_curr_rates) ? \
local->curr_rates[sta->field].rate : -1); \
}
#define __STA_ATTR(name) \
static struct sta_attribute sta_attr_##name = \
__ATTR(name, S_IRUGO, show_sta_##name, NULL)
#define STA_ATTR(name, field, format) \
STA_SHOW_##format(name, field) \
__STA_ATTR(name)
STA_ATTR(aid, aid, D);
STA_ATTR(key_idx_compression, key_idx_compression, D);
STA_ATTR(dev, dev->name, S);
STA_ATTR(vlan_id, vlan_id, D);
STA_ATTR(rx_packets, rx_packets, LU);
STA_ATTR(tx_packets, tx_packets, LU);
STA_ATTR(rx_bytes, rx_bytes, LU);
STA_ATTR(tx_bytes, tx_bytes, LU);
STA_ATTR(rx_duplicates, num_duplicates, LU);
STA_ATTR(rx_fragments, rx_fragments, LU);
STA_ATTR(rx_dropped, rx_dropped, LU);
STA_ATTR(tx_fragments, tx_fragments, LU);
STA_ATTR(tx_filtered, tx_filtered_count, LU);
STA_ATTR(txrate, txrate, RATE);
STA_ATTR(last_txrate, last_txrate, RATE);
STA_ATTR(tx_retry_failed, tx_retry_failed, LU);
STA_ATTR(tx_retry_count, tx_retry_count, LU);
STA_ATTR(last_rssi, last_rssi, D);
STA_ATTR(last_signal, last_signal, D);
STA_ATTR(last_noise, last_noise, D);
STA_ATTR(channel_use, channel_use, D);
STA_ATTR(wep_weak_iv_count, wep_weak_iv_count, D);
static ssize_t show_sta_flags(const struct sta_info *sta, char *buf)
{
return sprintf(buf, "%s%s%s%s%s%s%s%s%s",
sta->flags & WLAN_STA_AUTH ? "AUTH\n" : "",
sta->flags & WLAN_STA_ASSOC ? "ASSOC\n" : "",
sta->flags & WLAN_STA_PS ? "PS\n" : "",
sta->flags & WLAN_STA_TIM ? "TIM\n" : "",
sta->flags & WLAN_STA_PERM ? "PERM\n" : "",
sta->flags & WLAN_STA_AUTHORIZED ? "AUTHORIZED\n" : "",
sta->flags & WLAN_STA_SHORT_PREAMBLE ?
"SHORT PREAMBLE\n" : "",
sta->flags & WLAN_STA_WME ? "WME\n" : "",
sta->flags & WLAN_STA_WDS ? "WDS\n" : "");
}
__STA_ATTR(flags);
static ssize_t show_sta_num_ps_buf_frames(const struct sta_info *sta, char *buf)
{
return sprintf(buf, "%u\n", skb_queue_len(&sta->ps_tx_buf));
}
__STA_ATTR(num_ps_buf_frames);
static ssize_t show_sta_last_ack_rssi(const struct sta_info *sta, char *buf)
{
return sprintf(buf, "%d %d %d\n", sta->last_ack_rssi[0],
sta->last_ack_rssi[1], sta->last_ack_rssi[2]);
}
__STA_ATTR(last_ack_rssi);
static ssize_t show_sta_last_ack_ms(const struct sta_info *sta, char *buf)
{
return sprintf(buf, "%d\n", sta->last_ack ?
jiffies_to_msecs(jiffies - sta->last_ack) : -1);
}
__STA_ATTR(last_ack_ms);
static ssize_t show_sta_inactive_ms(const struct sta_info *sta, char *buf)
{
return sprintf(buf, "%d\n", jiffies_to_msecs(jiffies - sta->last_rx));
}
__STA_ATTR(inactive_ms);
static ssize_t show_sta_last_seq_ctrl(const struct sta_info *sta, char *buf)
{
int i;
char *p = buf;
for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
p += sprintf(p, "%x ", sta->last_seq_ctrl[i]);
p += sprintf(p, "\n");
return (p - buf);
}
__STA_ATTR(last_seq_ctrl);
#ifdef CONFIG_D80211_DEBUG_COUNTERS
static ssize_t show_sta_wme_rx_queue(const struct sta_info *sta, char *buf)
{
int i;
char *p = buf;
for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
p += sprintf(p, "%u ", sta->wme_rx_queue[i]);
p += sprintf(p, "\n");
return (p - buf);
}
__STA_ATTR(wme_rx_queue);
static ssize_t show_sta_wme_tx_queue(const struct sta_info *sta, char *buf)
{
int i;
char *p = buf;
for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
p += sprintf(p, "%u ", sta->wme_tx_queue[i]);
p += sprintf(p, "\n");
return (p - buf);
}
__STA_ATTR(wme_tx_queue);
#endif
static struct attribute *sta_ktype_attrs[] = {
&sta_attr_aid.attr,
&sta_attr_key_idx_compression.attr,
&sta_attr_dev.attr,
&sta_attr_vlan_id.attr,
&sta_attr_rx_packets.attr,
&sta_attr_tx_packets.attr,
&sta_attr_rx_bytes.attr,
&sta_attr_tx_bytes.attr,
&sta_attr_rx_duplicates.attr,
&sta_attr_rx_fragments.attr,
&sta_attr_rx_dropped.attr,
&sta_attr_tx_fragments.attr,
&sta_attr_tx_filtered.attr,
&sta_attr_txrate.attr,
&sta_attr_last_txrate.attr,
&sta_attr_tx_retry_failed.attr,
&sta_attr_tx_retry_count.attr,
&sta_attr_last_rssi.attr,
&sta_attr_last_signal.attr,
&sta_attr_last_noise.attr,
&sta_attr_channel_use.attr,
&sta_attr_wep_weak_iv_count.attr,
&sta_attr_flags.attr,
&sta_attr_num_ps_buf_frames.attr,
&sta_attr_last_ack_rssi.attr,
&sta_attr_last_ack_ms.attr,
&sta_attr_inactive_ms.attr,
&sta_attr_last_seq_ctrl.attr,
#ifdef CONFIG_D80211_DEBUG_COUNTERS
&sta_attr_wme_rx_queue.attr,
&sta_attr_wme_tx_queue.attr,
#endif
NULL
};
/* keys attributtes */
struct key_attribute {
struct attribute attr;
ssize_t (*show)(const struct ieee80211_key *, char *buf);
ssize_t (*store)(struct ieee80211_key *, const char *buf,
size_t count);
};
#define KEY_SHOW(name, field, format_string) \
static ssize_t show_key_##name(const struct ieee80211_key *key, char *buf)\
{ \
return sprintf(buf, format_string, key->field); \
}
#define KEY_SHOW_D(name, field) KEY_SHOW(name, field, "%d\n")
#define __KEY_ATTR(name) \
static struct key_attribute key_attr_##name = \
__ATTR(name, S_IRUSR, show_key_##name, NULL)
#define KEY_ATTR(name, field, format) \
KEY_SHOW_##format(name, field) \
__KEY_ATTR(name)
KEY_ATTR(length, keylen, D);
KEY_ATTR(sw_encrypt, force_sw_encrypt, D);
KEY_ATTR(index, keyidx, D);
KEY_ATTR(hw_index, hw_key_idx, D);
KEY_ATTR(tx_rx_count, tx_rx_count, D);
static ssize_t show_key_algorithm(const struct ieee80211_key *key, char *buf)
{
char *alg;
switch (key->alg) {
case ALG_WEP:
alg = "WEP";
break;
case ALG_TKIP:
alg = "TKIP";
break;
case ALG_CCMP:
alg = "CCMP";
break;
default:
return 0;
}
return sprintf(buf, "%s\n", alg);
}
__KEY_ATTR(algorithm);
static ssize_t show_key_tx_spec(const struct ieee80211_key *key, char *buf)
{
const u8 *tpn;
switch (key->alg) {
case ALG_WEP:
return sprintf(buf, "\n");
case ALG_TKIP:
return sprintf(buf, "%08x %04x\n", key->u.tkip.iv32,
key->u.tkip.iv16);
case ALG_CCMP:
tpn = key->u.ccmp.tx_pn;
return sprintf(buf, "%02x%02x%02x%02x%02x%02x\n", tpn[0],
tpn[1], tpn[2], tpn[3], tpn[4], tpn[5]);
default:
return 0;
}
}
__KEY_ATTR(tx_spec);
static ssize_t show_key_rx_spec(const struct ieee80211_key *key, char *buf)
{
int i;
const u8 *rpn;
char *p = buf;
switch (key->alg) {
case ALG_WEP:
return sprintf(buf, "\n");
case ALG_TKIP:
for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
p += sprintf(p, "%08x %04x\n",
key->u.tkip.iv32_rx[i],
key->u.tkip.iv16_rx[i]);
return (p - buf);
case ALG_CCMP:
for (i = 0; i < NUM_RX_DATA_QUEUES; i++) {
rpn = key->u.ccmp.rx_pn[i];
p += sprintf(p, "%02x%02x%02x%02x%02x%02x\n", rpn[0],
rpn[1], rpn[2], rpn[3], rpn[4], rpn[5]);
}
return (p - buf);
default:
return 0;
}
}
__KEY_ATTR(rx_spec);
static ssize_t show_key_replays(const struct ieee80211_key *key, char *buf)
{
if (key->alg != ALG_CCMP)
return 0;
return sprintf(buf, "%u\n", key->u.ccmp.replays);
}
__KEY_ATTR(replays);
static ssize_t show_key_key(const struct ieee80211_key *key, char *buf)
{
int i;
char *p = buf;
for (i = 0; i < key->keylen; i++)
p += sprintf(p, "%02x", key->key[i]);
p += sprintf(p, "\n");
return (p - buf);
}
__KEY_ATTR(key);
static struct attribute *key_ktype_attrs[] = {
&key_attr_length.attr,
&key_attr_sw_encrypt.attr,
&key_attr_index.attr,
&key_attr_hw_index.attr,
&key_attr_tx_rx_count.attr,
&key_attr_algorithm.attr,
&key_attr_tx_spec.attr,
&key_attr_rx_spec.attr,
&key_attr_replays.attr,
&key_attr_key.attr,
NULL
};
/* structures and functions */
static struct kobj_type sta_ktype = {
.release = sta_info_release,
.sysfs_ops = &sta_ktype_ops,
.default_attrs = sta_ktype_attrs,
};
static struct kobj_type key_ktype = {
.release = ieee80211_key_release,
.sysfs_ops = &key_ktype_ops,
.default_attrs = key_ktype_attrs,
};
static ssize_t sta_sysfs_show(struct kobject *kobj, struct attribute *attr,
char *buf)
{
struct sta_attribute *sta_attr;
struct sta_info *sta;
sta_attr = container_of(attr, struct sta_attribute, attr);
sta = container_of(kobj, struct sta_info, kobj);
return sta_attr->show(sta, buf);
}
static ssize_t key_sysfs_show(struct kobject *kobj, struct attribute *attr,
char *buf)
{
struct key_attribute *key_attr;
struct ieee80211_key *key;
key_attr = container_of(attr, struct key_attribute, attr);
key = container_of(kobj, struct ieee80211_key, kobj);
return key_attr->show(key, buf);
}
int ieee80211_sta_kset_sysfs_register(struct ieee80211_local *local)
{
int res;
res = kobject_set_name(&local->sta_kset.kobj, "sta");
if (res)
return res;
local->sta_kset.kobj.parent = &local->class_dev.kobj;
local->sta_kset.ktype = &sta_ktype;
return kset_register(&local->sta_kset);
}
void ieee80211_sta_kset_sysfs_unregister(struct ieee80211_local *local)
{
kset_unregister(&local->sta_kset);
}
int ieee80211_key_kset_sysfs_register(struct ieee80211_sub_if_data *sdata)
{
int res;
res = kobject_set_name(&sdata->key_kset.kobj, "keys");
if (res)
return res;
sdata->key_kset.kobj.parent = &sdata->dev->class_dev.kobj;
sdata->key_kset.ktype = &key_ktype;
return kset_register(&sdata->key_kset);
}
void ieee80211_key_kset_sysfs_unregister(struct ieee80211_sub_if_data *sdata)
{
kset_unregister(&sdata->key_kset);
}
int ieee80211_sta_sysfs_add(struct sta_info *sta)
{
return kobject_add(&sta->kobj);
}
void ieee80211_sta_sysfs_remove(struct sta_info *sta)
{
kobject_del(&sta->kobj);
}
void ieee80211_key_sysfs_set_kset(struct ieee80211_key *key, struct kset *kset)
{
key->kobj.kset = kset;
if (!kset)
key->kobj.ktype = &key_ktype;
}
int ieee80211_key_sysfs_add(struct ieee80211_key *key)
{
return kobject_add(&key->kobj);
}
void ieee80211_key_sysfs_remove(struct ieee80211_key *key)
{
if (key)
kobject_del(&key->kobj);
}
int ieee80211_key_sysfs_add_default(struct ieee80211_sub_if_data *sdata)
{
return sysfs_create_link(&sdata->key_kset.kobj,
&sdata->default_key->kobj, "default");
}
void ieee80211_key_sysfs_remove_default(struct ieee80211_sub_if_data *sdata)
{
sysfs_remove_link(&sdata->key_kset.kobj, "default");
}