ieee80211_output.c revision 116742
1/*- 2 * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer, 10 * without modification. 11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 13 * redistribution must be conditioned upon including a substantially 14 * similar Disclaimer requirement for further binary redistribution. 15 * 3. Neither the names of the above-listed copyright holders nor the names 16 * of any contributors may be used to endorse or promote products derived 17 * from this software without specific prior written permission. 18 * 19 * Alternatively, this software may be distributed under the terms of the 20 * GNU General Public License ("GPL") version 2 as published by the Free 21 * Software Foundation. 22 * 23 * NO WARRANTY 24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 28 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 29 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 32 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 34 * THE POSSIBILITY OF SUCH DAMAGES. 35 */ 36 37#include <sys/cdefs.h> 38__FBSDID("$FreeBSD: head/sys/net80211/ieee80211_output.c 116742 2003-06-23 16:55:01Z sam $"); 39 40#include "opt_inet.h" 41 42#include <sys/param.h> 43#include <sys/systm.h> 44#include <sys/mbuf.h> 45#include <sys/malloc.h> 46#include <sys/kernel.h> 47#include <sys/socket.h> 48#include <sys/sockio.h> 49#include <sys/endian.h> 50#include <sys/errno.h> 51#include <sys/bus.h> 52#include <sys/proc.h> 53#include <sys/sysctl.h> 54 55#include <machine/atomic.h> 56 57#include <net/if.h> 58#include <net/if_dl.h> 59#include <net/if_media.h> 60#include <net/if_arp.h> 61#include <net/ethernet.h> 62#include <net/if_llc.h> 63 64#include <net80211/ieee80211_var.h> 65 66#include <net/bpf.h> 67 68#ifdef INET 69#include <netinet/in.h> 70#include <netinet/if_ether.h> 71#endif 72 73int 74ieee80211_mgmt_output(struct ifnet *ifp, struct ieee80211_node *ni, 75 struct mbuf *m, int type) 76{ 77 struct ieee80211com *ic = (void *)ifp; 78 struct ieee80211_frame *wh; 79 80 /* XXX this probably shouldn't be permitted */ 81 KASSERT(ni != NULL, ("%s: null node", __func__)); 82 ni->ni_inact = 0; 83 84 M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT); 85 if (m == NULL) 86 return ENOMEM; 87 wh = mtod(m, struct ieee80211_frame *); 88 wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | type; 89 wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 90 *(u_int16_t *)wh->i_dur = 0; 91 *(u_int16_t *)wh->i_seq = 92 htole16(ni->ni_txseq << IEEE80211_SEQ_SEQ_SHIFT); 93 ni->ni_txseq++; 94 IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr); 95 IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_myaddr); 96 IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid); 97 98 if (ifp->if_flags & IFF_DEBUG) { 99 /* avoid to print too many frames */ 100 if (ic->ic_opmode == IEEE80211_M_IBSS || 101#ifdef IEEE80211_DEBUG 102 ieee80211_debug > 1 || 103#endif 104 (type & IEEE80211_FC0_SUBTYPE_MASK) != 105 IEEE80211_FC0_SUBTYPE_PROBE_RESP) 106 if_printf(ifp, "sending %s to %s on channel %u\n", 107 ieee80211_mgt_subtype_name[ 108 (type & IEEE80211_FC0_SUBTYPE_MASK) 109 >> IEEE80211_FC0_SUBTYPE_SHIFT], 110 ether_sprintf(ni->ni_macaddr), 111 ieee80211_chan2ieee(ic, ni->ni_chan)); 112 } 113 IF_ENQUEUE(&ic->ic_mgtq, m); 114 ifp->if_timer = 1; 115 (*ifp->if_start)(ifp); 116 return 0; 117} 118 119struct mbuf * 120ieee80211_encap(struct ifnet *ifp, struct mbuf *m) 121{ 122 struct ieee80211com *ic = (void *)ifp; 123 struct ether_header eh; 124 struct ieee80211_frame *wh; 125 struct llc *llc; 126 struct ieee80211_node *ni; 127 128 if (m->m_len < sizeof(struct ether_header)) { 129 m = m_pullup(m, sizeof(struct ether_header)); 130 if (m == NULL) 131 return NULL; 132 } 133 memcpy(&eh, mtod(m, caddr_t), sizeof(struct ether_header)); 134 135 ni = ieee80211_find_node(ic, eh.ether_dhost); 136 if (ni == NULL) /*ic_opmode?? XXX*/ 137 ni = ieee80211_ref_node(ic->ic_bss); 138 ni->ni_inact = 0; 139 140 m_adj(m, sizeof(struct ether_header) - sizeof(struct llc)); 141 llc = mtod(m, struct llc *); 142 llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; 143 llc->llc_control = LLC_UI; 144 llc->llc_snap.org_code[0] = 0; 145 llc->llc_snap.org_code[1] = 0; 146 llc->llc_snap.org_code[2] = 0; 147 llc->llc_snap.ether_type = eh.ether_type; 148 M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT); 149 if (m == NULL) { 150 ieee80211_unref_node(&ni); 151 return NULL; 152 } 153 wh = mtod(m, struct ieee80211_frame *); 154 wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA; 155 *(u_int16_t *)wh->i_dur = 0; 156 *(u_int16_t *)wh->i_seq = 157 htole16(ni->ni_txseq << IEEE80211_SEQ_SEQ_SHIFT); 158 ni->ni_txseq++; 159 switch (ic->ic_opmode) { 160 case IEEE80211_M_STA: 161 wh->i_fc[1] = IEEE80211_FC1_DIR_TODS; 162 IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_bssid); 163 IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost); 164 IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost); 165 break; 166 case IEEE80211_M_IBSS: 167 case IEEE80211_M_AHDEMO: 168 wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 169 IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost); 170 IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost); 171 IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid); 172 break; 173 case IEEE80211_M_HOSTAP: 174 wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; 175 IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost); 176 IEEE80211_ADDR_COPY(wh->i_addr2, ni->ni_bssid); 177 IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_shost); 178 break; 179 } 180 ieee80211_unref_node(&ni); 181 return m; 182} 183 184/* 185 * Add a supported rates element id to a frame. 186 */ 187u_int8_t * 188ieee80211_add_rates(u_int8_t *frm, const struct ieee80211_rateset *rs) 189{ 190 int nrates; 191 192 *frm++ = IEEE80211_ELEMID_RATES; 193 nrates = rs->rs_nrates; 194 if (nrates > IEEE80211_RATE_SIZE) 195 nrates = IEEE80211_RATE_SIZE; 196 *frm++ = nrates; 197 memcpy(frm, rs->rs_rates, nrates); 198 return frm + nrates; 199} 200 201/* 202 * Add an extended supported rates element id to a frame. 203 */ 204u_int8_t * 205ieee80211_add_xrates(u_int8_t *frm, const struct ieee80211_rateset *rs) 206{ 207 /* 208 * Add an extended supported rates element if operating in 11g mode. 209 */ 210 if (rs->rs_nrates > IEEE80211_RATE_SIZE) { 211 int nrates = rs->rs_nrates - IEEE80211_RATE_SIZE; 212 *frm++ = IEEE80211_ELEMID_XRATES; 213 *frm++ = nrates; 214 memcpy(frm, rs->rs_rates + IEEE80211_RATE_SIZE, nrates); 215 frm += nrates; 216 } 217 return frm; 218} 219 220/* 221 * Add an ssid elemet to a frame. 222 */ 223static u_int8_t * 224ieee80211_add_ssid(u_int8_t *frm, const u_int8_t *ssid, u_int len) 225{ 226 *frm++ = IEEE80211_ELEMID_SSID; 227 *frm++ = len; 228 memcpy(frm, ssid, len); 229 return frm + len; 230} 231 232static struct mbuf * 233ieee80211_getmbuf(int flags, int type, u_int pktlen) 234{ 235 struct mbuf *m; 236 237 if (pktlen > MHLEN) 238 MGETHDR(m, flags, type); 239 else 240 m = m_getcl(flags, type, M_PKTHDR); 241 return m; 242} 243 244int 245ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni, 246 int type, int arg) 247{ 248 struct ifnet *ifp = &ic->ic_if; 249 struct mbuf *m; 250 u_int8_t *frm; 251 enum ieee80211_phymode mode; 252 u_int16_t capinfo; 253 int ret, timer; 254 255 timer = 0; 256 switch (type) { 257 case IEEE80211_FC0_SUBTYPE_PROBE_REQ: 258 /* 259 * prreq frame format 260 * [tlv] ssid 261 * [tlv] supported rates 262 * [tlv] extended supported rates 263 */ 264 m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA, 265 2 + ic->ic_des_esslen 266 + 2 + IEEE80211_RATE_SIZE 267 + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)); 268 if (m == NULL) 269 return ENOMEM; 270 m->m_data += sizeof(struct ieee80211_frame); 271 frm = mtod(m, u_int8_t *); 272 frm = ieee80211_add_ssid(frm, ic->ic_des_essid, ic->ic_des_esslen); 273 mode = ieee80211_chan2mode(ic, ni->ni_chan); 274 frm = ieee80211_add_rates(frm, &ic->ic_sup_rates[mode]); 275 frm = ieee80211_add_xrates(frm, &ic->ic_sup_rates[mode]); 276 m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *); 277 278 timer = IEEE80211_TRANS_WAIT; 279 break; 280 281 case IEEE80211_FC0_SUBTYPE_PROBE_RESP: 282 /* 283 * probe response frame format 284 * [8] time stamp 285 * [2] beacon interval 286 * [2] cabability information 287 * [tlv] ssid 288 * [tlv] supported rates 289 * [tlv] parameter set (IBSS) 290 * [tlv] extended supported rates 291 */ 292 m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA, 293 8 + 2 + 2 + 2 294 + 2 + ni->ni_esslen 295 + 2 + IEEE80211_RATE_SIZE 296 + 6 297 + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)); 298 if (m == NULL) 299 return ENOMEM; 300 m->m_data += sizeof(struct ieee80211_frame); 301 frm = mtod(m, u_int8_t *); 302 303 memset(frm, 0, 8); /* timestamp should be filled later */ 304 frm += 8; 305 *(u_int16_t *)frm = htole16(ic->ic_bss->ni_intval); 306 frm += 2; 307 if (ic->ic_opmode == IEEE80211_M_IBSS) 308 capinfo = IEEE80211_CAPINFO_IBSS; 309 else 310 capinfo = IEEE80211_CAPINFO_ESS; 311 if (ic->ic_flags & IEEE80211_F_WEPON) 312 capinfo |= IEEE80211_CAPINFO_PRIVACY; 313 *(u_int16_t *)frm = htole16(capinfo); 314 frm += 2; 315 316 frm = ieee80211_add_ssid(frm, ic->ic_bss->ni_essid, 317 ic->ic_bss->ni_esslen); 318 frm = ieee80211_add_rates(frm, &ic->ic_bss->ni_rates); 319 320 if (ic->ic_opmode == IEEE80211_M_IBSS) { 321 *frm++ = IEEE80211_ELEMID_IBSSPARMS; 322 *frm++ = 2; 323 *frm++ = 0; *frm++ = 0; /* TODO: ATIM window */ 324 } else { /* IEEE80211_M_HOSTAP */ 325 /* TODO: TIM */ 326 *frm++ = IEEE80211_ELEMID_TIM; 327 *frm++ = 4; /* length */ 328 *frm++ = 0; /* DTIM count */ 329 *frm++ = 1; /* DTIM period */ 330 *frm++ = 0; /* bitmap control */ 331 *frm++ = 0; /* Partial Virtual Bitmap (variable length) */ 332 } 333 frm = ieee80211_add_xrates(frm, &ic->ic_bss->ni_rates); 334 m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *); 335 break; 336 337 case IEEE80211_FC0_SUBTYPE_AUTH: 338 MGETHDR(m, M_DONTWAIT, MT_DATA); 339 if (m == NULL) 340 return ENOMEM; 341 MH_ALIGN(m, 2 * 3); 342 m->m_pkthdr.len = m->m_len = 6; 343 frm = mtod(m, u_int8_t *); 344 /* TODO: shared key auth */ 345 ((u_int16_t *)frm)[0] = htole16(IEEE80211_AUTH_ALG_OPEN); 346 ((u_int16_t *)frm)[1] = htole16(arg); /* sequence number */ 347 ((u_int16_t *)frm)[2] = 0; /* status */ 348 if (ic->ic_opmode == IEEE80211_M_STA) 349 timer = IEEE80211_TRANS_WAIT; 350 break; 351 352 case IEEE80211_FC0_SUBTYPE_DEAUTH: 353 if (ifp->if_flags & IFF_DEBUG) 354 if_printf(ifp, "station %s deauthenticate (reason %d)\n", 355 ether_sprintf(ni->ni_macaddr), arg); 356 MGETHDR(m, M_DONTWAIT, MT_DATA); 357 if (m == NULL) 358 return ENOMEM; 359 MH_ALIGN(m, 2); 360 m->m_pkthdr.len = m->m_len = 2; 361 *mtod(m, u_int16_t *) = htole16(arg); /* reason */ 362 break; 363 364 case IEEE80211_FC0_SUBTYPE_ASSOC_REQ: 365 case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: 366 /* 367 * asreq frame format 368 * [2] capability information 369 * [2] listen interval 370 * [6*] current AP address (reassoc only) 371 * [tlv] ssid 372 * [tlv] supported rates 373 * [tlv] extended supported rates 374 */ 375 m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA, 376 sizeof(capinfo) 377 + sizeof(u_int16_t) 378 + IEEE80211_ADDR_LEN 379 + 2 + ni->ni_esslen 380 + 2 + IEEE80211_RATE_SIZE 381 + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)); 382 if (m == NULL) 383 return ENOMEM; 384 m->m_data += sizeof(struct ieee80211_frame); 385 frm = mtod(m, u_int8_t *); 386 387 capinfo = 0; 388 if (ic->ic_opmode == IEEE80211_M_IBSS) 389 capinfo |= IEEE80211_CAPINFO_IBSS; 390 else /* IEEE80211_M_STA */ 391 capinfo |= IEEE80211_CAPINFO_ESS; 392 if (ic->ic_flags & IEEE80211_F_WEPON) 393 capinfo |= IEEE80211_CAPINFO_PRIVACY; 394 if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) 395 capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; 396 if (ic->ic_flags & IEEE80211_F_SHSLOT) 397 capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; 398 *(u_int16_t *)frm = htole16(capinfo); 399 frm += 2; 400 401 *(u_int16_t *)frm = htole16(ic->ic_lintval); 402 frm += 2; 403 404 if (type == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) { 405 IEEE80211_ADDR_COPY(frm, ic->ic_bss->ni_bssid); 406 frm += IEEE80211_ADDR_LEN; 407 } 408 409 frm = ieee80211_add_ssid(frm, ni->ni_essid, ni->ni_esslen); 410 frm = ieee80211_add_rates(frm, &ni->ni_rates); 411 frm = ieee80211_add_xrates(frm, &ni->ni_rates); 412 m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *); 413 414 timer = IEEE80211_TRANS_WAIT; 415 break; 416 417 case IEEE80211_FC0_SUBTYPE_ASSOC_RESP: 418 case IEEE80211_FC0_SUBTYPE_REASSOC_RESP: 419 /* 420 * asreq frame format 421 * [2] capability information 422 * [2] status 423 * [2] association ID 424 * [tlv] supported rates 425 * [tlv] extended supported rates 426 */ 427 m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA, 428 sizeof(capinfo) 429 + sizeof(u_int16_t) 430 + sizeof(u_int16_t) 431 + 2 + IEEE80211_RATE_SIZE 432 + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)); 433 if (m == NULL) 434 return ENOMEM; 435 m->m_data += sizeof(struct ieee80211_frame); 436 frm = mtod(m, u_int8_t *); 437 438 capinfo = IEEE80211_CAPINFO_ESS; 439 if (ic->ic_flags & IEEE80211_F_WEPON) 440 capinfo |= IEEE80211_CAPINFO_PRIVACY; 441 *(u_int16_t *)frm = htole16(capinfo); 442 frm += 2; 443 444 *(u_int16_t *)frm = htole16(arg); /* status */ 445 frm += 2; 446 447 if (arg == IEEE80211_STATUS_SUCCESS && ni != NULL) 448 *(u_int16_t *)frm = htole16(ni->ni_associd); 449 else 450 *(u_int16_t *)frm = htole16(0); 451 frm += 2; 452 453 if (ni != NULL) { 454 frm = ieee80211_add_rates(frm, &ni->ni_rates); 455 frm = ieee80211_add_xrates(frm, &ni->ni_rates); 456 } else { 457 frm = ieee80211_add_rates(frm, &ic->ic_bss->ni_rates); 458 frm = ieee80211_add_xrates(frm, &ic->ic_bss->ni_rates); 459 } 460 m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *); 461 break; 462 463 case IEEE80211_FC0_SUBTYPE_DISASSOC: 464 if (ifp->if_flags & IFF_DEBUG) 465 if_printf(ifp, "station %s disassociate (reason %d)\n", 466 ether_sprintf(ni->ni_macaddr), arg); 467 MGETHDR(m, M_DONTWAIT, MT_DATA); 468 if (m == NULL) 469 return ENOMEM; 470 MH_ALIGN(m, 2); 471 m->m_pkthdr.len = m->m_len = 2; 472 *mtod(m, u_int16_t *) = htole16(arg); /* reason */ 473 break; 474 475 default: 476 IEEE80211_DPRINTF(("%s: invalid mgmt frame type %u\n", 477 __func__, type)); 478 return EINVAL; 479 } 480 481 ret = ieee80211_mgmt_output(ifp, ni, m, type); 482 if (ret == 0 && timer) 483 ic->ic_mgt_timer = timer; 484 return ret; 485} 486