Print this page
fixup .text where possible
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/mac/plugins/mac_wifi.c
+++ new/usr/src/uts/common/io/mac/plugins/mac_wifi.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25
26 26 /*
27 27 * WiFi MAC Type plugin for the Nemo mac module
28 28 *
29 29 * This is a bit of mutant since we pretend to be mostly DL_ETHER.
30 30 */
31 31
32 32 #include <sys/types.h>
33 33 #include <sys/modctl.h>
34 34 #include <sys/dlpi.h>
35 35 #include <sys/dld_impl.h>
36 36 #include <sys/mac_wifi.h>
37 37 #include <sys/ethernet.h>
38 38 #include <sys/byteorder.h>
39 39 #include <sys/strsun.h>
40 40 #include <inet/common.h>
41 41
42 42 uint8_t wifi_bcastaddr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
43 43 static uint8_t wifi_ietfmagic[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
44 44 static uint8_t wifi_ieeemagic[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
45 45
46 46 static mac_stat_info_t wifi_stats[] = {
47 47 /* statistics described in ieee802.11(5) */
48 48 { WIFI_STAT_TX_FRAGS, "tx_frags", KSTAT_DATA_UINT32, 0 },
49 49 { WIFI_STAT_MCAST_TX, "mcast_tx", KSTAT_DATA_UINT32, 0 },
50 50 { WIFI_STAT_TX_FAILED, "tx_failed", KSTAT_DATA_UINT32, 0 },
51 51 { WIFI_STAT_TX_RETRANS, "tx_retrans", KSTAT_DATA_UINT32, 0 },
52 52 { WIFI_STAT_TX_RERETRANS, "tx_reretrans", KSTAT_DATA_UINT32, 0 },
53 53 { WIFI_STAT_RTS_SUCCESS, "rts_success", KSTAT_DATA_UINT32, 0 },
54 54 { WIFI_STAT_RTS_FAILURE, "rts_failure", KSTAT_DATA_UINT32, 0 },
55 55 { WIFI_STAT_ACK_FAILURE, "ack_failure", KSTAT_DATA_UINT32, 0 },
56 56 { WIFI_STAT_RX_FRAGS, "rx_frags", KSTAT_DATA_UINT32, 0 },
57 57 { WIFI_STAT_MCAST_RX, "mcast_rx", KSTAT_DATA_UINT32, 0 },
58 58 { WIFI_STAT_FCS_ERRORS, "fcs_errors", KSTAT_DATA_UINT32, 0 },
59 59 { WIFI_STAT_WEP_ERRORS, "wep_errors", KSTAT_DATA_UINT32, 0 },
↓ open down ↓ |
59 lines elided |
↑ open up ↑ |
60 60 { WIFI_STAT_RX_DUPS, "rx_dups", KSTAT_DATA_UINT32, 0 }
61 61 };
62 62
63 63 static struct modlmisc mac_wifi_modlmisc = {
64 64 &mod_miscops,
65 65 "WiFi MAC plugin 1.4"
66 66 };
67 67
68 68 static struct modlinkage mac_wifi_modlinkage = {
69 69 MODREV_1,
70 - &mac_wifi_modlmisc,
71 - NULL
70 + { &mac_wifi_modlmisc,
71 + NULL }
72 72 };
73 73
74 74 static mactype_ops_t mac_wifi_type_ops;
75 75
76 76 int
77 77 _init(void)
78 78 {
79 79 mactype_register_t *mtrp = mactype_alloc(MACTYPE_VERSION);
80 80 int err;
81 81
82 82 /*
83 83 * If `mtrp' is NULL, then this plugin is not compatible with
84 84 * the system's MAC Type plugin framework.
85 85 */
86 86 if (mtrp == NULL)
87 87 return (ENOTSUP);
88 88
89 89 mtrp->mtr_ops = &mac_wifi_type_ops;
90 90 mtrp->mtr_ident = MAC_PLUGIN_IDENT_WIFI;
91 91 mtrp->mtr_mactype = DL_ETHER;
92 92 mtrp->mtr_nativetype = DL_WIFI;
93 93 mtrp->mtr_stats = wifi_stats;
94 94 mtrp->mtr_statcount = A_CNT(wifi_stats);
95 95 mtrp->mtr_addrlen = IEEE80211_ADDR_LEN;
96 96 mtrp->mtr_brdcst_addr = wifi_bcastaddr;
97 97
98 98 if ((err = mactype_register(mtrp)) == 0) {
99 99 if ((err = mod_install(&mac_wifi_modlinkage)) != 0)
100 100 (void) mactype_unregister(MAC_PLUGIN_IDENT_WIFI);
101 101 }
102 102 mactype_free(mtrp);
103 103 return (err);
104 104 }
105 105
106 106 int
107 107 _fini(void)
108 108 {
109 109 int err;
110 110
111 111 if ((err = mactype_unregister(MAC_PLUGIN_IDENT_WIFI)) != 0)
112 112 return (err);
113 113 return (mod_remove(&mac_wifi_modlinkage));
114 114 }
115 115
116 116 int
117 117 _info(struct modinfo *modinfop)
118 118 {
119 119 return (mod_info(&mac_wifi_modlinkage, modinfop));
120 120 }
121 121
122 122 /*
123 123 * MAC Type plugin operations
124 124 */
125 125
126 126 static boolean_t
127 127 mac_wifi_pdata_verify(void *pdata, size_t pdata_size)
128 128 {
129 129 wifi_data_t *wdp = pdata;
130 130
131 131 return (pdata_size == sizeof (wifi_data_t) && wdp->wd_opts == 0);
132 132 }
133 133
134 134 /* ARGSUSED */
135 135 static int
136 136 mac_wifi_unicst_verify(const void *addr, void *pdata)
137 137 {
138 138 /* If it's not a group address, then it's a valid unicast address. */
139 139 return (IEEE80211_IS_MULTICAST(addr) ? EINVAL : 0);
140 140 }
141 141
142 142 /* ARGSUSED */
143 143 static int
144 144 mac_wifi_multicst_verify(const void *addr, void *pdata)
145 145 {
146 146 /* The address must be a group address. */
147 147 if (!IEEE80211_IS_MULTICAST(addr))
148 148 return (EINVAL);
149 149 /* The address must not be the media broadcast address. */
150 150 if (bcmp(addr, wifi_bcastaddr, sizeof (wifi_bcastaddr)) == 0)
151 151 return (EINVAL);
152 152 return (0);
153 153 }
154 154
155 155 /*
156 156 * Verify that `sap' is valid, and return the actual SAP to bind to in
157 157 * `*bind_sap'. The WiFI SAP space is identical to Ethernet.
158 158 */
159 159 /* ARGSUSED */
160 160 static boolean_t
161 161 mac_wifi_sap_verify(uint32_t sap, uint32_t *bind_sap, void *pdata)
162 162 {
163 163 if (sap >= ETHERTYPE_802_MIN && sap <= ETHERTYPE_MAX) {
164 164 if (bind_sap != NULL)
165 165 *bind_sap = sap;
166 166 return (B_TRUE);
167 167 }
168 168
169 169 if (sap <= ETHERMTU) {
170 170 if (bind_sap != NULL)
171 171 *bind_sap = DLS_SAP_LLC;
172 172 return (B_TRUE);
173 173 }
174 174 return (B_FALSE);
175 175 }
176 176
177 177 /*
178 178 * Create a template WiFi datalink header for `sap' packets between `saddr'
179 179 * and `daddr'. Any enabled modes and features relevant to building the
180 180 * header are passed via `pdata'. Return NULL on failure.
181 181 */
182 182 /* ARGSUSED */
183 183 static mblk_t *
184 184 mac_wifi_header(const void *saddr, const void *daddr, uint32_t sap,
185 185 void *pdata, mblk_t *payload, size_t extra_len)
186 186 {
187 187 struct ieee80211_frame *wh;
188 188 struct ieee80211_llc *llc;
189 189 mblk_t *mp;
190 190 wifi_data_t *wdp = pdata;
191 191
192 192 if (!mac_wifi_sap_verify(sap, NULL, NULL))
193 193 return (NULL);
194 194
195 195 if ((mp = allocb(WIFI_HDRSIZE + extra_len, BPRI_HI)) == NULL)
196 196 return (NULL);
197 197 bzero(mp->b_rptr, WIFI_HDRSIZE + extra_len);
198 198
199 199 /*
200 200 * Fill in the fixed parts of the ieee80211_frame.
201 201 */
202 202 wh = (struct ieee80211_frame *)mp->b_rptr;
203 203 mp->b_wptr += sizeof (struct ieee80211_frame) + wdp->wd_qospad;
204 204 wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA;
205 205
206 206 switch (wdp->wd_opmode) {
207 207 case IEEE80211_M_STA:
208 208 wh->i_fc[1] = IEEE80211_FC1_DIR_TODS;
209 209 IEEE80211_ADDR_COPY(wh->i_addr1, wdp->wd_bssid);
210 210 IEEE80211_ADDR_COPY(wh->i_addr2, saddr);
211 211 IEEE80211_ADDR_COPY(wh->i_addr3, daddr);
212 212 break;
213 213
214 214 case IEEE80211_M_IBSS:
215 215 case IEEE80211_M_AHDEMO:
216 216 wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
217 217 IEEE80211_ADDR_COPY(wh->i_addr1, daddr);
218 218 IEEE80211_ADDR_COPY(wh->i_addr2, saddr);
219 219 IEEE80211_ADDR_COPY(wh->i_addr3, wdp->wd_bssid);
220 220 break;
221 221
222 222 case IEEE80211_M_HOSTAP:
223 223 wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS;
224 224 IEEE80211_ADDR_COPY(wh->i_addr1, daddr);
225 225 IEEE80211_ADDR_COPY(wh->i_addr2, wdp->wd_bssid);
226 226 IEEE80211_ADDR_COPY(wh->i_addr3, saddr);
227 227 break;
228 228 }
229 229
230 230 if (wdp->wd_qospad) {
231 231 struct ieee80211_qosframe *qwh =
232 232 (struct ieee80211_qosframe *)wh;
233 233 qwh->i_qos[1] = 0;
234 234 qwh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_QOS;
235 235 }
236 236
237 237 switch (wdp->wd_secalloc) {
238 238 case WIFI_SEC_WEP:
239 239 /*
240 240 * Fill in the fixed parts of the WEP-portion of the frame.
241 241 */
242 242 wh->i_fc[1] |= IEEE80211_FC1_WEP;
243 243 /*
244 244 * The actual contents of the WEP-portion of the packet
245 245 * are computed when the packet is sent -- for now, we
246 246 * just need to account for the size.
247 247 */
248 248 mp->b_wptr += IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN;
249 249 break;
250 250
251 251 case WIFI_SEC_WPA:
252 252 wh->i_fc[1] |= IEEE80211_FC1_WEP;
253 253 mp->b_wptr += IEEE80211_WEP_IVLEN +
254 254 IEEE80211_WEP_KIDLEN + IEEE80211_WEP_EXTIVLEN;
255 255 break;
256 256
257 257 default:
258 258 break;
259 259 }
260 260
261 261 /*
262 262 * Fill in the fixed parts of the ieee80211_llc header.
263 263 */
264 264 llc = (struct ieee80211_llc *)mp->b_wptr;
265 265 mp->b_wptr += sizeof (struct ieee80211_llc);
266 266 bcopy(wifi_ietfmagic, llc, sizeof (wifi_ietfmagic));
267 267 llc->illc_ether_type = htons(sap);
268 268
269 269 return (mp);
270 270 }
271 271
272 272 /*
273 273 * Use the provided `mp' (which is expected to point to a WiFi header), and
274 274 * fill in the provided `mhp'. Return an errno on failure.
275 275 */
276 276 /* ARGSUSED */
277 277 static int
278 278 mac_wifi_header_info(mblk_t *mp, void *pdata, mac_header_info_t *mhp)
279 279 {
280 280 struct ieee80211_frame *wh;
281 281 struct ieee80211_llc *llc;
282 282 uchar_t *llcp;
283 283 wifi_data_t *wdp = pdata;
284 284
285 285 if (MBLKL(mp) < sizeof (struct ieee80211_frame))
286 286 return (EINVAL);
287 287
288 288 wh = (struct ieee80211_frame *)mp->b_rptr;
289 289 llcp = mp->b_rptr + sizeof (struct ieee80211_frame);
290 290
291 291 /*
292 292 * Generally, QoS data field takes 2 bytes, but some special hardware,
293 293 * such as Atheros, will need the 802.11 header padded to a 32-bit
294 294 * boundary for 4-address and QoS frames, at this time, it's 4 bytes.
295 295 */
296 296 if (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_QOS)
297 297 llcp += wdp->wd_qospad;
298 298
299 299 /*
300 300 * When we receive frames from other hosts, the hardware will have
301 301 * already performed WEP decryption, and thus there will not be a WEP
302 302 * portion. However, when we receive a loopback copy of our own
303 303 * packets, it will still have a WEP portion. Skip past it to get to
304 304 * the LLC header.
305 305 */
306 306 if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
307 307 llcp += IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN;
308 308 if (wdp->wd_secalloc == WIFI_SEC_WPA)
309 309 llcp += IEEE80211_WEP_EXTIVLEN;
310 310 }
311 311
312 312 if ((uintptr_t)mp->b_wptr - (uintptr_t)llcp <
313 313 sizeof (struct ieee80211_llc))
314 314 return (EINVAL);
315 315
316 316 llc = (struct ieee80211_llc *)llcp;
317 317 mhp->mhi_origsap = ntohs(llc->illc_ether_type);
318 318 mhp->mhi_bindsap = mhp->mhi_origsap;
319 319 mhp->mhi_pktsize = 0;
320 320 mhp->mhi_hdrsize = (uintptr_t)llcp + sizeof (*llc) -
321 321 (uintptr_t)mp->b_rptr;
322 322
323 323 /*
324 324 * Verify the LLC header is one of the known formats. As per MSFT's
325 325 * convention, if the header is using IEEE 802.1H encapsulation, then
326 326 * treat the LLC header as data. As per DL_ETHER custom when treating
327 327 * the LLC header as data, set the mhi_bindsap to be DLS_SAP_LLC, and
328 328 * assume mhi_origsap contains the data length.
329 329 */
330 330 if (bcmp(llc, wifi_ieeemagic, sizeof (wifi_ieeemagic)) == 0) {
331 331 mhp->mhi_bindsap = DLS_SAP_LLC;
332 332 mhp->mhi_hdrsize -= sizeof (*llc);
333 333 mhp->mhi_pktsize = mhp->mhi_hdrsize + mhp->mhi_origsap;
334 334 } else if (bcmp(llc, wifi_ietfmagic, sizeof (wifi_ietfmagic)) != 0) {
335 335 return (EINVAL);
336 336 }
337 337
338 338 switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
339 339 case IEEE80211_FC1_DIR_NODS:
340 340 mhp->mhi_daddr = wh->i_addr1;
341 341 mhp->mhi_saddr = wh->i_addr2;
342 342 break;
343 343
344 344 case IEEE80211_FC1_DIR_TODS:
345 345 mhp->mhi_daddr = wh->i_addr3;
346 346 mhp->mhi_saddr = wh->i_addr2;
347 347 break;
348 348
349 349 case IEEE80211_FC1_DIR_FROMDS:
350 350 mhp->mhi_daddr = wh->i_addr1;
351 351 mhp->mhi_saddr = wh->i_addr3;
352 352 break;
353 353
354 354 case IEEE80211_FC1_DIR_DSTODS:
355 355 /* We don't support AP-to-AP mode yet */
356 356 return (ENOTSUP);
357 357 }
358 358
359 359 if (mac_wifi_unicst_verify(mhp->mhi_daddr, NULL) == 0)
360 360 mhp->mhi_dsttype = MAC_ADDRTYPE_UNICAST;
361 361 else if (mac_wifi_multicst_verify(mhp->mhi_daddr, NULL) == 0)
362 362 mhp->mhi_dsttype = MAC_ADDRTYPE_MULTICAST;
363 363 else
364 364 mhp->mhi_dsttype = MAC_ADDRTYPE_BROADCAST;
365 365
366 366 return (0);
367 367 }
368 368
369 369 /*
370 370 * Take the provided `mp' (which is expected to have an Ethernet header), and
371 371 * return a pointer to an mblk_t with a WiFi header. Note that the returned
372 372 * header will not be complete until the driver finishes filling it in prior
373 373 * to transmit. If the conversion cannot be performed, return NULL.
374 374 */
375 375 static mblk_t *
376 376 mac_wifi_header_cook(mblk_t *mp, void *pdata)
377 377 {
378 378 struct ether_header *ehp;
379 379 mblk_t *llmp;
380 380
381 381 if (MBLKL(mp) < sizeof (struct ether_header))
382 382 return (NULL);
383 383
384 384 ehp = (void *)mp->b_rptr;
385 385 llmp = mac_wifi_header(&ehp->ether_shost, &ehp->ether_dhost,
386 386 ntohs(ehp->ether_type), pdata, NULL, 0);
387 387 if (llmp == NULL)
388 388 return (NULL);
389 389
390 390 /*
391 391 * The plugin framework guarantees that we have the only reference
392 392 * to the mblk_t, so we can safely modify it.
393 393 */
394 394 ASSERT(DB_REF(mp) == 1);
395 395 mp->b_rptr += sizeof (struct ether_header);
396 396 llmp->b_cont = mp;
397 397 return (llmp);
398 398 }
399 399
400 400 /*
401 401 * Take the provided `mp' (which is expected to have a WiFi header), and
402 402 * return a pointer to an mblk_t with an Ethernet header. If the conversion
403 403 * cannot be performed, return NULL.
404 404 */
405 405 static mblk_t *
406 406 mac_wifi_header_uncook(mblk_t *mp, void *pdata)
407 407 {
408 408 mac_header_info_t mhi;
409 409 struct ether_header eh;
410 410
411 411 if (mac_wifi_header_info(mp, pdata, &mhi) != 0) {
412 412 /*
413 413 * The plugin framework guarantees the header is properly
414 414 * formed, so this should never happen.
415 415 */
416 416 return (NULL);
417 417 }
418 418
419 419 /*
420 420 * The plugin framework guarantees that we have the only reference to
421 421 * the mblk_t and the underlying dblk_t, so we can safely modify it.
422 422 */
423 423 ASSERT(DB_REF(mp) == 1);
424 424
425 425 IEEE80211_ADDR_COPY(&eh.ether_dhost, mhi.mhi_daddr);
426 426 IEEE80211_ADDR_COPY(&eh.ether_shost, mhi.mhi_saddr);
427 427 eh.ether_type = htons(mhi.mhi_origsap);
428 428
429 429 ASSERT(mhi.mhi_hdrsize >= sizeof (struct ether_header));
430 430 mp->b_rptr += mhi.mhi_hdrsize - sizeof (struct ether_header);
431 431 bcopy(&eh, mp->b_rptr, sizeof (struct ether_header));
432 432 return (mp);
433 433 }
434 434
435 435 static mactype_ops_t mac_wifi_type_ops = {
436 436 MTOPS_PDATA_VERIFY | MTOPS_HEADER_COOK | MTOPS_HEADER_UNCOOK,
437 437 mac_wifi_unicst_verify,
438 438 mac_wifi_multicst_verify,
439 439 mac_wifi_sap_verify,
440 440 mac_wifi_header,
441 441 mac_wifi_header_info,
442 442 mac_wifi_pdata_verify,
443 443 mac_wifi_header_cook,
444 444 mac_wifi_header_uncook
445 445 };
↓ open down ↓ |
364 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX