]> git.ipfire.org Git - thirdparty/iw.git/blob - ibss.c
iw: don't use NULL pointer in nla_nest_end()
[thirdparty/iw.git] / ibss.c
1 #ifndef _POSIX_SOURCE
2 #define _POSIX_SOURCE
3 #endif
4 #include <errno.h>
5 #include <string.h>
6 #include <strings.h>
7
8 #include <netlink/genl/genl.h>
9 #include <netlink/genl/family.h>
10 #include <netlink/genl/ctrl.h>
11 #include <netlink/msg.h>
12 #include <netlink/attr.h>
13
14 #include "nl80211.h"
15 #include "iw.h"
16
17 SECTION(ibss);
18
19 struct chanmode {
20 const char *name;
21 unsigned int width;
22 int freq1_diff;
23 int chantype; /* for older kernel */
24 };
25
26 static int get_cf1(const struct chanmode *chanmode, unsigned long freq)
27 {
28 unsigned int cf1 = freq, j;
29 unsigned int vht80[] = { 5180, 5260, 5500, 5580, 5660, 5745 };
30
31 switch (chanmode->width) {
32 case NL80211_CHAN_WIDTH_80:
33 /* setup center_freq1 */
34 for (j = 0; j < ARRAY_SIZE(vht80); j++) {
35 if (freq >= vht80[j] && freq < vht80[j] + 80)
36 break;
37 }
38
39 if (j == ARRAY_SIZE(vht80))
40 break;
41
42 cf1 = vht80[j] + 30;
43 break;
44 default:
45 cf1 = freq + chanmode->freq1_diff;
46 break;
47 }
48
49 return cf1;
50 }
51
52 static int join_ibss(struct nl80211_state *state,
53 struct nl_msg *msg,
54 int argc, char **argv,
55 enum id_input id)
56 {
57 char *end;
58 unsigned char abssid[6];
59 unsigned char rates[NL80211_MAX_SUPP_RATES];
60 int n_rates = 0;
61 char *value = NULL, *sptr = NULL;
62 float rate;
63 int bintval;
64 unsigned int i;
65 unsigned long freq;
66 const struct chanmode *chanmode_selected = NULL;
67 static const struct chanmode chanmode[] = {
68 { .name = "HT20",
69 .width = NL80211_CHAN_WIDTH_20,
70 .freq1_diff = 0,
71 .chantype = NL80211_CHAN_HT20 },
72 { .name = "HT40+",
73 .width = NL80211_CHAN_WIDTH_40,
74 .freq1_diff = 10,
75 .chantype = NL80211_CHAN_HT40PLUS },
76 { .name = "HT40-",
77 .width = NL80211_CHAN_WIDTH_40,
78 .freq1_diff = -10,
79 .chantype = NL80211_CHAN_HT40MINUS },
80 { .name = "NOHT",
81 .width = NL80211_CHAN_WIDTH_20_NOHT,
82 .freq1_diff = 0,
83 .chantype = NL80211_CHAN_NO_HT },
84 { .name = "5MHz",
85 .width = NL80211_CHAN_WIDTH_5,
86 .freq1_diff = 0,
87 .chantype = -1 },
88 { .name = "10MHz",
89 .width = NL80211_CHAN_WIDTH_10,
90 .freq1_diff = 0,
91 .chantype = -1 },
92 { .name = "80MHz",
93 .width = NL80211_CHAN_WIDTH_80,
94 .freq1_diff = 0,
95 .chantype = -1 },
96 };
97
98 if (argc < 2)
99 return 1;
100
101 /* SSID */
102 NLA_PUT(msg, NL80211_ATTR_SSID, strlen(argv[0]), argv[0]);
103 argv++;
104 argc--;
105
106 /* freq */
107 freq = strtoul(argv[0], &end, 10);
108 if (*end != '\0')
109 return 1;
110
111 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
112 argv++;
113 argc--;
114
115 if (argc) {
116 for (i = 0; i < ARRAY_SIZE(chanmode); i++) {
117 if (strcasecmp(chanmode[i].name, argv[0]) == 0) {
118 chanmode_selected = &chanmode[i];
119 break;
120 }
121 }
122 if (chanmode_selected) {
123 NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
124 chanmode_selected->width);
125 NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1,
126 get_cf1(chanmode_selected, freq));
127 if (chanmode_selected->chantype != -1)
128 NLA_PUT_U32(msg,
129 NL80211_ATTR_WIPHY_CHANNEL_TYPE,
130 chanmode_selected->chantype);
131
132 argv++;
133 argc--;
134 }
135
136 }
137
138 if (argc && strcmp(argv[0], "fixed-freq") == 0) {
139 NLA_PUT_FLAG(msg, NL80211_ATTR_FREQ_FIXED);
140 argv++;
141 argc--;
142 }
143
144 if (argc) {
145 if (mac_addr_a2n(abssid, argv[0]) == 0) {
146 NLA_PUT(msg, NL80211_ATTR_MAC, 6, abssid);
147 argv++;
148 argc--;
149 }
150 }
151
152 if (argc > 1 && strcmp(argv[0], "beacon-interval") == 0) {
153 argv++;
154 argc--;
155 bintval = strtoul(argv[0], &end, 10);
156 if (*end != '\0')
157 return 1;
158 NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, bintval);
159 argv++;
160 argc--;
161 }
162
163 /* basic rates */
164 if (argc > 1 && strcmp(argv[0], "basic-rates") == 0) {
165 argv++;
166 argc--;
167
168 value = strtok_r(argv[0], ",", &sptr);
169
170 while (value && n_rates < NL80211_MAX_SUPP_RATES) {
171 rate = strtod(value, &end);
172 rates[n_rates] = rate * 2;
173
174 /* filter out suspicious values */
175 if (*end != '\0' || !rates[n_rates] ||
176 rate*2 != rates[n_rates])
177 return 1;
178
179 n_rates++;
180 value = strtok_r(NULL, ",", &sptr);
181 }
182
183 NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, n_rates, rates);
184
185 argv++;
186 argc--;
187 }
188
189 /* multicast rate */
190 if (argc > 1 && strcmp(argv[0], "mcast-rate") == 0) {
191 argv++;
192 argc--;
193
194 rate = strtod(argv[0], &end);
195 if (*end != '\0')
196 return 1;
197
198 NLA_PUT_U32(msg, NL80211_ATTR_MCAST_RATE, (int)(rate * 10));
199 argv++;
200 argc--;
201 }
202
203 if (!argc)
204 return 0;
205
206 if (strcmp(*argv, "key") != 0 && strcmp(*argv, "keys") != 0)
207 return 1;
208
209 argv++;
210 argc--;
211
212 return parse_keys(msg, argv, argc);
213 nla_put_failure:
214 return -ENOSPC;
215 }
216
217 static int leave_ibss(struct nl80211_state *state,
218 struct nl_msg *msg,
219 int argc, char **argv,
220 enum id_input id)
221 {
222 return 0;
223 }
224 COMMAND(ibss, leave, NULL,
225 NL80211_CMD_LEAVE_IBSS, 0, CIB_NETDEV, leave_ibss,
226 "Leave the current IBSS cell.");
227 COMMAND(ibss, join,
228 "<SSID> <freq in MHz> [HT20|HT40+|HT40-|NOHT|5MHz|10MHz|80MHz] [fixed-freq] [<fixed bssid>] [beacon-interval <TU>]"
229 " [basic-rates <rate in Mbps,rate2,...>] [mcast-rate <rate in Mbps>] "
230 "[key d:0:abcde]",
231 NL80211_CMD_JOIN_IBSS, 0, CIB_NETDEV, join_ibss,
232 "Join the IBSS cell with the given SSID, if it doesn't exist create\n"
233 "it on the given frequency. When fixed frequency is requested, don't\n"
234 "join/create a cell on a different frequency. When a fixed BSSID is\n"
235 "requested use that BSSID and do not adopt another cell's BSSID even\n"
236 "if it has higher TSF and the same SSID. If an IBSS is created, create\n"
237 "it with the specified basic-rates, multicast-rate and beacon-interval.");