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