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