blob: 1bf1bab5f5b5fb29d0a67ef8f7900d783476421e [file] [log] [blame]
Johannes Bergb8936862010-09-22 11:33:51 +02001#ifndef _POSIX_SOURCE
2#define _POSIX_SOURCE
3#endif
Johannes Bergedea4d12009-04-19 00:53:31 +02004#include <errno.h>
Johannes Bergb8936862010-09-22 11:33:51 +02005#include <string.h>
Simon Wunderlich135cb522011-11-30 16:56:35 +01006#include <strings.h>
Johannes Bergedea4d12009-04-19 00:53:31 +02007
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
Johannes Berg4698bfc2009-08-24 12:53:34 +020017SECTION(ibss);
18
Johannes Bergedea4d12009-04-19 00:53:31 +020019static int join_ibss(struct nl80211_state *state,
20 struct nl_cb *cb,
21 struct nl_msg *msg,
Johannes Berg05514f92012-07-19 11:50:50 +020022 int argc, char **argv,
23 enum id_input id)
Johannes Bergedea4d12009-04-19 00:53:31 +020024{
Johannes Berg95940df2009-04-19 17:52:14 +020025 char *end;
Johannes Bergedea4d12009-04-19 00:53:31 +020026 unsigned char abssid[6];
Teemu Paasikivi6a24bb22010-06-16 09:22:16 +030027 unsigned char rates[NL80211_MAX_SUPP_RATES];
28 int n_rates = 0;
29 char *value = NULL, *sptr = NULL;
30 float rate;
Bruno Randolfec46ba52010-10-27 15:02:37 +090031 int bintval;
Simon Wunderlich135cb522011-11-30 16:56:35 +010032 int i;
Simon Wunderlich85da7702013-11-12 18:31:58 +010033 unsigned long freq;
Simon Wunderlich135cb522011-11-30 16:56:35 +010034 static const struct {
35 const char *name;
Simon Wunderlich85da7702013-11-12 18:31:58 +010036 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 },
Simon Wunderlich135cb522011-11-30 16:56:35 +010064 };
Johannes Bergedea4d12009-04-19 00:53:31 +020065
Johannes Berg95940df2009-04-19 17:52:14 +020066 if (argc < 2)
67 return 1;
Johannes Bergedea4d12009-04-19 00:53:31 +020068
Johannes Berg95940df2009-04-19 17:52:14 +020069 /* SSID */
70 NLA_PUT(msg, NL80211_ATTR_SSID, strlen(argv[0]), argv[0]);
Johannes Bergedea4d12009-04-19 00:53:31 +020071 argv++;
72 argc--;
73
Johannes Berg95940df2009-04-19 17:52:14 +020074 /* freq */
Simon Wunderlich85da7702013-11-12 18:31:58 +010075 freq = strtoul(argv[0], &end, 10);
Johannes Berg95940df2009-04-19 17:52:14 +020076 if (*end != '\0')
77 return 1;
Simon Wunderlich85da7702013-11-12 18:31:58 +010078
79 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
Johannes Berg95940df2009-04-19 17:52:14 +020080 argv++;
81 argc--;
Johannes Bergedea4d12009-04-19 00:53:31 +020082
Simon Wunderlich135cb522011-11-30 16:56:35 +010083 if (argc) {
Simon Wunderlich85da7702013-11-12 18:31:58 +010084 for (i = 0; i < ARRAY_SIZE(chanmode); i++) {
85 if (strcasecmp(chanmode[i].name, argv[0]) == 0) {
86 chanmode_selected = &chanmode[i];
Simon Wunderlich135cb522011-11-30 16:56:35 +010087 break;
88 }
89 }
Simon Wunderlich85da7702013-11-12 18:31:58 +010090 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
Simon Wunderlich135cb522011-11-30 16:56:35 +0100100 argv++;
101 argc--;
102 }
103
104 }
105
Johannes Berg95940df2009-04-19 17:52:14 +0200106 if (argc && strcmp(argv[0], "fixed-freq") == 0) {
107 NLA_PUT_FLAG(msg, NL80211_ATTR_FREQ_FIXED);
108 argv++;
109 argc--;
Johannes Bergedea4d12009-04-19 00:53:31 +0200110 }
111
Johannes Berg95940df2009-04-19 17:52:14 +0200112 if (argc) {
Johannes Berg51e9bd82009-07-08 00:44:25 +0200113 if (mac_addr_a2n(abssid, argv[0]) == 0) {
114 NLA_PUT(msg, NL80211_ATTR_MAC, 6, abssid);
115 argv++;
116 argc--;
117 }
Johannes Bergedea4d12009-04-19 00:53:31 +0200118 }
119
Bruno Randolfec46ba52010-10-27 15:02:37 +0900120 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
Teemu Paasikivi6a24bb22010-06-16 09:22:16 +0300131 /* 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
Felix Fietkau506b4422011-01-11 09:51:18 +0900157 /* 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
Jo-Philipp Wiche399be82011-05-22 15:09:51 +0200166 NLA_PUT_U32(msg, NL80211_ATTR_MCAST_RATE, (int)(rate * 10));
Felix Fietkau506b4422011-01-11 09:51:18 +0900167 argv++;
168 argc--;
169 }
170
Johannes Berg1e036902009-08-16 16:02:15 +0200171 if (!argc)
172 return 0;
Johannes Berg51e9bd82009-07-08 00:44:25 +0200173
Johannes Berg1e036902009-08-16 16:02:15 +0200174 if (strcmp(*argv, "key") != 0 && strcmp(*argv, "keys") != 0)
175 return 1;
Johannes Bergedea4d12009-04-19 00:53:31 +0200176
Johannes Berg1e036902009-08-16 16:02:15 +0200177 argv++;
178 argc--;
Johannes Berg51e9bd82009-07-08 00:44:25 +0200179
Johannes Berg1e036902009-08-16 16:02:15 +0200180 return parse_keys(msg, argv, argc);
Johannes Bergedea4d12009-04-19 00:53:31 +0200181 nla_put_failure:
182 return -ENOSPC;
183}
184
185static int leave_ibss(struct nl80211_state *state,
186 struct nl_cb *cb,
187 struct nl_msg *msg,
Johannes Berg05514f92012-07-19 11:50:50 +0200188 int argc, char **argv,
189 enum id_input id)
Johannes Bergedea4d12009-04-19 00:53:31 +0200190{
191 return 0;
192}
193COMMAND(ibss, leave, NULL,
Johannes Berg806bad32009-05-05 14:56:40 +0200194 NL80211_CMD_LEAVE_IBSS, 0, CIB_NETDEV, leave_ibss,
195 "Leave the current IBSS cell.");
Teemu Paasikivi6a24bb22010-06-16 09:22:16 +0300196COMMAND(ibss, join,
Simon Wunderlich85da7702013-11-12 18:31:58 +0100197 "<SSID> <freq in MHz> [HT20|HT40+|HT40-|NOHT|5MHZ|10MHZ] [fixed-freq] [<fixed bssid>] [beacon-interval <TU>]"
Felix Fietkau506b4422011-01-11 09:51:18 +0900198 " [basic-rates <rate in Mbps,rate2,...>] [mcast-rate <rate in Mbps>] "
199 "[key d:0:abcde]",
Johannes Berg806bad32009-05-05 14:56:40 +0200200 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"
Bruno Randolfec46ba52010-10-27 15:02:37 +0900205 "if it has higher TSF and the same SSID. If an IBSS is created, create\n"
Felix Fietkau506b4422011-01-11 09:51:18 +0900206 "it with the specified basic-rates, multicast-rate and beacon-interval.");