summaryrefslogtreecommitdiffstats
path: root/package/mac80211/patches/015-hostapd-ioctl-hw-features.patch
blob: d6e5dfd07357f2b9d970b42b0df2a5ab5c4e3c28 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
---
 net/mac80211/ieee80211_ioctl.c |  102 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 102 insertions(+)

--- everything.orig/net/mac80211/ieee80211_ioctl.c	2007-11-07 13:19:32.281514919 +0100
+++ everything/net/mac80211/ieee80211_ioctl.c	2007-11-07 13:19:33.681513453 +0100
@@ -125,6 +125,105 @@ static int ieee80211_ioctl_siwgenie(stru
 	return -EOPNOTSUPP;
 }
 
+/*
+ * Wow. This ioctl interface is such crap, it's tied
+ * to internal definitions. I hope it dies soon.
+ */
+static int mode_to_hostapd_mode(enum ieee80211_phymode mode)
+{
+	switch (mode) {
+	case MODE_IEEE80211A:
+		return 0;
+	case MODE_IEEE80211B:
+		return 1;
+	case MODE_IEEE80211G:
+		return 3;
+	case NUM_IEEE80211_MODES:
+		WARN_ON(1);
+		break;
+	}
+	WARN_ON(1);
+	return -1;
+}
+
+static int channel_flags_to_hostapd_flags(int flags)
+{
+	int res = 0;
+
+	if (flags & IEEE80211_CHAN_W_SCAN)
+		res |= 1;
+	if (flags & IEEE80211_CHAN_W_ACTIVE_SCAN)
+		res |= 2;
+	if (flags & IEEE80211_CHAN_W_IBSS)
+		res |= 4;
+
+	return res;
+}
+
+struct ieee80211_channel_data {
+	short chan; /* channel number (IEEE 802.11) */
+	short freq; /* frequency in MHz */
+	int flag; /* flag for hostapd use (IEEE80211_CHAN_*) */
+};
+
+struct ieee80211_rate_data {
+	int rate; /* rate in 100 kbps */
+	int flags; /* IEEE80211_RATE_ flags */
+};
+
+static int ieee80211_ioctl_get_hw_features(struct net_device *dev,
+					   struct prism2_hostapd_param *param,
+					   int param_len)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	u8 *pos = param->u.hw_features.data;
+	int left = param_len - (pos - (u8 *) param);
+	int i;
+	struct hostapd_ioctl_hw_modes_hdr *hdr;
+	struct ieee80211_rate_data *rate;
+	struct ieee80211_channel_data *chan;
+	struct ieee80211_hw_mode *mode;
+
+	param->u.hw_features.flags = 0;
+
+	param->u.hw_features.num_modes = 0;
+	list_for_each_entry(mode, &local->modes_list, list) {
+		int clen, rlen;
+
+		param->u.hw_features.num_modes++;
+		clen =
+		    mode->num_channels * sizeof(struct ieee80211_channel_data);
+		rlen = mode->num_rates * sizeof(struct ieee80211_rate_data);
+		if (left < sizeof(*hdr) + clen + rlen)
+			return -E2BIG;
+		left -= sizeof(*hdr) + clen + rlen;
+
+		hdr = (struct hostapd_ioctl_hw_modes_hdr *)pos;
+		hdr->mode = mode_to_hostapd_mode(mode->mode);
+		hdr->num_channels = mode->num_channels;
+		hdr->num_rates = mode->num_rates;
+
+		pos = (u8 *) (hdr + 1);
+		chan = (struct ieee80211_channel_data *)pos;
+		for (i = 0; i < mode->num_channels; i++) {
+			chan[i].chan = mode->channels[i].chan;
+			chan[i].freq = mode->channels[i].freq;
+			chan[i].flag = channel_flags_to_hostapd_flags(
+						mode->channels[i].flag);
+		}
+		pos += clen;
+
+		rate = (struct ieee80211_rate_data *)pos;
+		for (i = 0; i < mode->num_rates; i++) {
+			rate[i].rate = mode->rates[i].rate;
+			rate[i].flags = mode->rates[i].flags;
+		}
+		pos += rlen;
+	}
+
+	return 0;
+}
+
 
 static int ieee80211_ioctl_priv_hostapd(struct net_device *dev,
 					struct iw_point *p)
@@ -151,6 +250,9 @@ static int ieee80211_ioctl_priv_hostapd(
 	}
 
 	switch (param->cmd) {
+	case PRISM2_HOSTAPD_GET_HW_FEATURES:
+		ret = ieee80211_ioctl_get_hw_features(dev, param, p->length);
+		break;
 	default:
 		ret = -EOPNOTSUPP;
 		break;