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