net80211_output.c revision c1500db945971ce16b2509a64fc04cd590779a2e
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright (c) 2001 Atsushi Onoe
* Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Send out 802.11 frames
*/
#include <sys/byteorder.h>
#include "net80211_impl.h"
/*
* Set the direction field and address fields of an outgoing
* non-QoS frame. Note this should be called early on in
* constructing a frame as it sets i_fc[1]; other bits can
* then be or'd in.
*/
static void
{
case IEEE80211_M_STA:
break;
case IEEE80211_M_IBSS:
case IEEE80211_M_AHDEMO:
break;
default:
ieee80211_err("ieee80211_send_setup: "
return;
}
} else {
}
}
/*
* Send a management frame to the specified node. The node pointer
* must have a reference as the pointer will be passed to the driver
* and potentially held for a long time. If the frame is successfully
* dispatched to the driver, then it is responsible for freeing the
* reference (and potentially free'ing up any associated storage).
*
* Return 0 on success
*/
static int
{
struct ieee80211_frame *wh;
if (timer > 0) {
/*
* Set the mgt frame timeout.
*/
}
}
/*
* Send a null data frame to the specified node.
*
* NB: the caller is assumed to have setup a node reference
* for use; this is necessary to deal with a race condition
* when probing for inactive stations.
*/
int
{
mblk_t *m;
struct ieee80211_frame *wh;
m = ieee80211_getmgtframe(&frm, 0);
if (m == NULL) {
return (ENOMEM);
}
/* NB: power management bit is never sent by an AP */
"send null data frame on channel %u, pwr mgt %s\n",
return (0);
}
/*
* Encapsulate an outbound data frame for GLDv3 based driver.
* Fill in the variable part of the 80211 frame
*/
/* ARGSUSED */
mblk_t *
{
struct ieee80211_frame *wh;
struct ieee80211_key *key;
else
/*
* IEEE 802.1X: send EAPOL frames always in the clear.
*/
ieee80211_err("ieee80211_crypto_enmic failed.\n");
}
}
return (mp);
}
/*
* Add supported rates information element to a frame.
*/
static uint8_t *
{
*frm++ = IEEE80211_ELEMID_RATES;
if (nrates > IEEE80211_RATE_SIZE)
}
/*
* Add extended supported rates element to a frame, usually for 11g mode
*/
static uint8_t *
{
*frm++ = IEEE80211_ELEMID_XRATES;
}
return (frm);
}
/*
* Add SSID element to a frame
*/
static uint8_t *
{
*frm++ = IEEE80211_ELEMID_SSID;
}
/*
* Add an erp element to a frame.
*/
static uint8_t *
{
*frm++ = IEEE80211_ELEMID_ERP;
*frm++ = 1;
erp = 0;
return (frm);
}
/*
* Get capability information from the interface softc, ic.
*/
static uint16_t
{
else
}
return (capinfo);
}
/*
* Send a probe request frame with the specified ssid
* and any optional information element data.
*/
int
{
enum ieee80211_phymode mode;
struct ieee80211_frame *wh;
/*
* prreq frame format ([tlv] - 1 byte element ID + 1 byte length)
* [tlv] ssid
* [tlv] supported rates
* [tlv] extended supported rates
* [tlv] user-specified ie's
*/
+ 2 + IEEE80211_RATE_SIZE +
+ 2 + IEEE80211_XRATE_SIZE
+ optielen);
return (ENOMEM);
}
"[%s] send probe req on channel %u\n",
return (0);
}
/*
* Send a management frame. The node is for the destination (or ic_bss
* when in station mode). Nodes other than ic_bss have their reference
* count bumped to reflect our use for an indeterminant time.
*/
int
{
struct ieee80211_key *key;
int ret;
int timer;
int status;
timer = 0;
switch (type) {
/*
* probe response frame format
* [8] time stamp
* [2] beacon interval
* [2] capability information
* [tlv] ssid
* [tlv] supported rates
* [tlv] parameter set (IBSS)
* [tlv] extended rate phy (ERP)
* [tlv] extended supported rates
* [tlv] WPA
* [tlv] WME (optional)
*/
8 /* time stamp */
+ sizeof (uint16_t) /* beacon interval */
+ sizeof (uint16_t) /* capability */
+ 2 + IEEE80211_NWID_LEN
+ 2 + IEEE80211_RATE_SIZE
+ 2 + IEEE80211_FH_LEN
+ 2 + IEEE80211_IBSS_LEN
+ 2 + IEEE80211_ERP_LEN
+ 2 + IEEE80211_XRATE_SIZE
2 * sizeof (struct ieee80211_ie_wpa) : 0)
/* [tlv] WPA */
sizeof (struct ieee80211_wme_param) : 0));
/* [tlv] WME */
return (ENOMEM);
frm += 8;
frm += 2;
frm += 2;
*frm++ = IEEE80211_ELEMID_FHPARMS;
*frm++ = IEEE80211_FH_LEN;
*frm++ = IEEE80211_FH_CHANSET(
*frm++ = IEEE80211_FH_CHANPAT(
} else {
*frm++ = IEEE80211_ELEMID_DSPARMS;
*frm++ = IEEE80211_DS_LEN;
}
*frm++ = IEEE80211_IBSS_LEN;
}
break;
arg &= 0xffff;
/*
* Deduce whether we're doing open authentication or
* shared key authentication. We do the latter if
* we're in the middle of a shared key authentication
* handshake or if we're initiating an authentication
* request and configured to use shared key.
*/
(arg == IEEE80211_AUTH_SHARED_REQUEST &&
else
3 * sizeof (uint16_t)
sizeof (uint16_t) + IEEE80211_CHALLENGE_LEN : 0)
return (ENOMEM);
frm++;
frm++;
}
break;
return (ENOMEM);
break;
/*
* asreq frame format
* [2] capability information
* [2] listen interval
* [6*] current AP address (reassoc only)
* [tlv] ssid
* [tlv] supported rates
* [tlv] extended supported rates
* [tlv] WME
* [tlv] user-specified ie's
*/
sizeof (uint16_t)
+ sizeof (uint16_t) + IEEE80211_ADDR_LEN
+ 2 + IEEE80211_NWID_LEN
+ 2 + IEEE80211_RATE_SIZE
+ 2 + IEEE80211_XRATE_SIZE
+ ic->ic_opt_ie_len);
return (ENOMEM);
} else {
}
frm += 2;
frm += 2;
if (type == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) {
}
}
break;
/*
* asreq frame format
* [2] capability information
* [2] status
* [2] association ID
* [tlv] supported rates
* [tlv] extended supported rates
* [tlv] WME (if enabled and STA enabled)
*/
3 * sizeof (uint16_t)
+ 2 + IEEE80211_RATE_SIZE
+ 2 + IEEE80211_XRATE_SIZE);
return (ENOMEM);
frm += 2;
frm += 2;
if (arg == IEEE80211_STATUS_SUCCESS)
else
frm += 2;
break;
return (ENOMEM);
break;
default:
"[%s] invalid mgmt frame type %u\n",
return (EINVAL);
} /* type */
return (ret);
}
/*
* Allocate a beacon frame and fillin the appropriate bits.
*/
mblk_t *
struct ieee80211_beacon_offsets *bo)
{
struct ieee80211_frame *wh;
struct ieee80211_rateset *rs;
mblk_t *m;
int pktlen;
/*
* beacon frame format
* [8] time stamp
* [2] beacon interval
* [2] cabability information
* [tlv] ssid
* [tlv] supported rates
* [3] parameter set (DS)
* [tlv] extended rate phy (ERP)
* [tlv] extended supported rates
* [tlv] WME parameters
* Vendor-specific OIDs (e.g. Atheros)
* NB: we allocate the max space required for the TIM bitmap.
*/
+ sizeof (uint16_t) /* beacon interval */
+ sizeof (uint16_t) /* capabilities */
+ 2 + 1 /* DS parameters */
+ 2 + 1 /* ERP */
+ 2 + IEEE80211_XRATE_SIZE;
if (m == NULL) {
"cannot get buf; size %u\n", pktlen);
return (NULL);
}
frm += 8;
frm += 2;
frm += 2;
*frm++ = IEEE80211_ELEMID_SSID;
} else {
*frm++ = 0;
}
*frm++ = IEEE80211_ELEMID_DSPARMS;
*frm++ = 1;
}
*frm++ = 2;
bo->bo_tim_len = 0;
} else {
struct ieee80211_tim_ie *tie =
(struct ieee80211_tim_ie *)frm;
frm += sizeof (struct ieee80211_tim_ie);
}
}
return (m);
}
/*
* Update the dynamic parts of a beacon frame based on the current state.
*/
/* ARGSUSED */
int
{
return (0);
}