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