13147Sxc151355 /*
23147Sxc151355 * CDDL HEADER START
33147Sxc151355 *
43147Sxc151355 * The contents of this file are subject to the terms of the
53147Sxc151355 * Common Development and Distribution License (the "License").
63147Sxc151355 * You may not use this file except in compliance with the License.
73147Sxc151355 *
83147Sxc151355 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93147Sxc151355 * or http://www.opensolaris.org/os/licensing.
103147Sxc151355 * See the License for the specific language governing permissions
113147Sxc151355 * and limitations under the License.
123147Sxc151355 *
133147Sxc151355 * When distributing Covered Code, include this CDDL HEADER in each
143147Sxc151355 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153147Sxc151355 * If applicable, add the following below this CDDL HEADER, with the
163147Sxc151355 * fields enclosed by brackets "[]" replaced with your own identifying
173147Sxc151355 * information: Portions Copyright [yyyy] [name of copyright owner]
183147Sxc151355 *
193147Sxc151355 * CDDL HEADER END
203147Sxc151355 */
213147Sxc151355 /*
22*10266SQuaker.Fang@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
233147Sxc151355 * Use is subject to license terms.
243147Sxc151355 */
253147Sxc151355
263147Sxc151355 /*
273147Sxc151355 * WiFi MAC Type plugin for the Nemo mac module
283147Sxc151355 *
293147Sxc151355 * This is a bit of mutant since we pretend to be mostly DL_ETHER.
303147Sxc151355 */
313147Sxc151355
323147Sxc151355 #include <sys/types.h>
333147Sxc151355 #include <sys/modctl.h>
343147Sxc151355 #include <sys/dlpi.h>
358275SEric Cheng #include <sys/dld_impl.h>
363147Sxc151355 #include <sys/mac_wifi.h>
373147Sxc151355 #include <sys/ethernet.h>
383147Sxc151355 #include <sys/byteorder.h>
393147Sxc151355 #include <sys/strsun.h>
403147Sxc151355 #include <inet/common.h>
413147Sxc151355
423147Sxc151355 uint8_t wifi_bcastaddr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
433147Sxc151355 static uint8_t wifi_ietfmagic[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
443147Sxc151355 static uint8_t wifi_ieeemagic[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
453147Sxc151355
463147Sxc151355 static mac_stat_info_t wifi_stats[] = {
473147Sxc151355 /* statistics described in ieee802.11(5) */
483147Sxc151355 { WIFI_STAT_TX_FRAGS, "tx_frags", KSTAT_DATA_UINT32, 0 },
493147Sxc151355 { WIFI_STAT_MCAST_TX, "mcast_tx", KSTAT_DATA_UINT32, 0 },
503147Sxc151355 { WIFI_STAT_TX_FAILED, "tx_failed", KSTAT_DATA_UINT32, 0 },
513147Sxc151355 { WIFI_STAT_TX_RETRANS, "tx_retrans", KSTAT_DATA_UINT32, 0 },
523147Sxc151355 { WIFI_STAT_TX_RERETRANS, "tx_reretrans", KSTAT_DATA_UINT32, 0 },
533147Sxc151355 { WIFI_STAT_RTS_SUCCESS, "rts_success", KSTAT_DATA_UINT32, 0 },
543147Sxc151355 { WIFI_STAT_RTS_FAILURE, "rts_failure", KSTAT_DATA_UINT32, 0 },
553147Sxc151355 { WIFI_STAT_ACK_FAILURE, "ack_failure", KSTAT_DATA_UINT32, 0 },
563147Sxc151355 { WIFI_STAT_RX_FRAGS, "rx_frags", KSTAT_DATA_UINT32, 0 },
573147Sxc151355 { WIFI_STAT_MCAST_RX, "mcast_rx", KSTAT_DATA_UINT32, 0 },
583147Sxc151355 { WIFI_STAT_FCS_ERRORS, "fcs_errors", KSTAT_DATA_UINT32, 0 },
593147Sxc151355 { WIFI_STAT_WEP_ERRORS, "wep_errors", KSTAT_DATA_UINT32, 0 },
603147Sxc151355 { WIFI_STAT_RX_DUPS, "rx_dups", KSTAT_DATA_UINT32, 0 }
613147Sxc151355 };
623147Sxc151355
633147Sxc151355 static struct modlmisc mac_wifi_modlmisc = {
643147Sxc151355 &mod_miscops,
65*10266SQuaker.Fang@Sun.COM "WiFi MAC plugin 1.4"
663147Sxc151355 };
673147Sxc151355
683147Sxc151355 static struct modlinkage mac_wifi_modlinkage = {
693147Sxc151355 MODREV_1,
703147Sxc151355 &mac_wifi_modlmisc,
713147Sxc151355 NULL
723147Sxc151355 };
733147Sxc151355
743147Sxc151355 static mactype_ops_t mac_wifi_type_ops;
753147Sxc151355
763147Sxc151355 int
_init(void)773147Sxc151355 _init(void)
783147Sxc151355 {
793147Sxc151355 mactype_register_t *mtrp = mactype_alloc(MACTYPE_VERSION);
803147Sxc151355 int err;
813147Sxc151355
823147Sxc151355 /*
833147Sxc151355 * If `mtrp' is NULL, then this plugin is not compatible with
843147Sxc151355 * the system's MAC Type plugin framework.
853147Sxc151355 */
863147Sxc151355 if (mtrp == NULL)
873147Sxc151355 return (ENOTSUP);
883147Sxc151355
893147Sxc151355 mtrp->mtr_ops = &mac_wifi_type_ops;
903147Sxc151355 mtrp->mtr_ident = MAC_PLUGIN_IDENT_WIFI;
913147Sxc151355 mtrp->mtr_mactype = DL_ETHER;
923147Sxc151355 mtrp->mtr_nativetype = DL_WIFI;
933147Sxc151355 mtrp->mtr_stats = wifi_stats;
943147Sxc151355 mtrp->mtr_statcount = A_CNT(wifi_stats);
953147Sxc151355 mtrp->mtr_addrlen = IEEE80211_ADDR_LEN;
963147Sxc151355 mtrp->mtr_brdcst_addr = wifi_bcastaddr;
973147Sxc151355
983147Sxc151355 if ((err = mactype_register(mtrp)) == 0) {
993147Sxc151355 if ((err = mod_install(&mac_wifi_modlinkage)) != 0)
1003147Sxc151355 (void) mactype_unregister(MAC_PLUGIN_IDENT_WIFI);
1013147Sxc151355 }
1023147Sxc151355 mactype_free(mtrp);
1033147Sxc151355 return (err);
1043147Sxc151355 }
1053147Sxc151355
1063147Sxc151355 int
_fini(void)1073147Sxc151355 _fini(void)
1083147Sxc151355 {
1093147Sxc151355 int err;
1103147Sxc151355
1113147Sxc151355 if ((err = mactype_unregister(MAC_PLUGIN_IDENT_WIFI)) != 0)
1123147Sxc151355 return (err);
1133147Sxc151355 return (mod_remove(&mac_wifi_modlinkage));
1143147Sxc151355 }
1153147Sxc151355
1163147Sxc151355 int
_info(struct modinfo * modinfop)1173147Sxc151355 _info(struct modinfo *modinfop)
1183147Sxc151355 {
1193147Sxc151355 return (mod_info(&mac_wifi_modlinkage, modinfop));
1203147Sxc151355 }
1213147Sxc151355
1223147Sxc151355 /*
1233147Sxc151355 * MAC Type plugin operations
1243147Sxc151355 */
1253147Sxc151355
1263147Sxc151355 static boolean_t
mac_wifi_pdata_verify(void * pdata,size_t pdata_size)1273147Sxc151355 mac_wifi_pdata_verify(void *pdata, size_t pdata_size)
1283147Sxc151355 {
1293147Sxc151355 wifi_data_t *wdp = pdata;
1303147Sxc151355
1313147Sxc151355 return (pdata_size == sizeof (wifi_data_t) && wdp->wd_opts == 0);
1323147Sxc151355 }
1333147Sxc151355
1343147Sxc151355 /* ARGSUSED */
1353147Sxc151355 static int
mac_wifi_unicst_verify(const void * addr,void * pdata)1363147Sxc151355 mac_wifi_unicst_verify(const void *addr, void *pdata)
1373147Sxc151355 {
1383147Sxc151355 /* If it's not a group address, then it's a valid unicast address. */
1393147Sxc151355 return (IEEE80211_IS_MULTICAST(addr) ? EINVAL : 0);
1403147Sxc151355 }
1413147Sxc151355
1423147Sxc151355 /* ARGSUSED */
1433147Sxc151355 static int
mac_wifi_multicst_verify(const void * addr,void * pdata)1443147Sxc151355 mac_wifi_multicst_verify(const void *addr, void *pdata)
1453147Sxc151355 {
1463147Sxc151355 /* The address must be a group address. */
1473147Sxc151355 if (!IEEE80211_IS_MULTICAST(addr))
1483147Sxc151355 return (EINVAL);
1493147Sxc151355 /* The address must not be the media broadcast address. */
1503147Sxc151355 if (bcmp(addr, wifi_bcastaddr, sizeof (wifi_bcastaddr)) == 0)
1513147Sxc151355 return (EINVAL);
1523147Sxc151355 return (0);
1533147Sxc151355 }
1543147Sxc151355
1553147Sxc151355 /*
1563147Sxc151355 * Verify that `sap' is valid, and return the actual SAP to bind to in
1573147Sxc151355 * `*bind_sap'. The WiFI SAP space is identical to Ethernet.
1583147Sxc151355 */
1593147Sxc151355 /* ARGSUSED */
1603147Sxc151355 static boolean_t
mac_wifi_sap_verify(uint32_t sap,uint32_t * bind_sap,void * pdata)1613147Sxc151355 mac_wifi_sap_verify(uint32_t sap, uint32_t *bind_sap, void *pdata)
1623147Sxc151355 {
1633147Sxc151355 if (sap >= ETHERTYPE_802_MIN && sap <= ETHERTYPE_MAX) {
1643147Sxc151355 if (bind_sap != NULL)
1653147Sxc151355 *bind_sap = sap;
1663147Sxc151355 return (B_TRUE);
1673147Sxc151355 }
1683147Sxc151355
1693147Sxc151355 if (sap <= ETHERMTU) {
1703147Sxc151355 if (bind_sap != NULL)
1713147Sxc151355 *bind_sap = DLS_SAP_LLC;
1723147Sxc151355 return (B_TRUE);
1733147Sxc151355 }
1743147Sxc151355 return (B_FALSE);
1753147Sxc151355 }
1763147Sxc151355
1773147Sxc151355 /*
1783147Sxc151355 * Create a template WiFi datalink header for `sap' packets between `saddr'
1793147Sxc151355 * and `daddr'. Any enabled modes and features relevant to building the
1803147Sxc151355 * header are passed via `pdata'. Return NULL on failure.
1813147Sxc151355 */
1823147Sxc151355 /* ARGSUSED */
1833147Sxc151355 static mblk_t *
mac_wifi_header(const void * saddr,const void * daddr,uint32_t sap,void * pdata,mblk_t * payload,size_t extra_len)1843147Sxc151355 mac_wifi_header(const void *saddr, const void *daddr, uint32_t sap,
1853147Sxc151355 void *pdata, mblk_t *payload, size_t extra_len)
1863147Sxc151355 {
1873147Sxc151355 struct ieee80211_frame *wh;
1883147Sxc151355 struct ieee80211_llc *llc;
1893147Sxc151355 mblk_t *mp;
1903147Sxc151355 wifi_data_t *wdp = pdata;
1913147Sxc151355
1923147Sxc151355 if (!mac_wifi_sap_verify(sap, NULL, NULL))
1933147Sxc151355 return (NULL);
1943147Sxc151355
1953147Sxc151355 if ((mp = allocb(WIFI_HDRSIZE + extra_len, BPRI_HI)) == NULL)
1963147Sxc151355 return (NULL);
1973147Sxc151355 bzero(mp->b_rptr, WIFI_HDRSIZE + extra_len);
1983147Sxc151355
1993147Sxc151355 /*
2003147Sxc151355 * Fill in the fixed parts of the ieee80211_frame.
2013147Sxc151355 */
2023147Sxc151355 wh = (struct ieee80211_frame *)mp->b_rptr;
203*10266SQuaker.Fang@Sun.COM mp->b_wptr += sizeof (struct ieee80211_frame) + wdp->wd_qospad;
2043147Sxc151355 wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA;
2053147Sxc151355
2063147Sxc151355 switch (wdp->wd_opmode) {
2073147Sxc151355 case IEEE80211_M_STA:
2083147Sxc151355 wh->i_fc[1] = IEEE80211_FC1_DIR_TODS;
2093147Sxc151355 IEEE80211_ADDR_COPY(wh->i_addr1, wdp->wd_bssid);
2103147Sxc151355 IEEE80211_ADDR_COPY(wh->i_addr2, saddr);
2113147Sxc151355 IEEE80211_ADDR_COPY(wh->i_addr3, daddr);
2123147Sxc151355 break;
2133147Sxc151355
2143147Sxc151355 case IEEE80211_M_IBSS:
2153147Sxc151355 case IEEE80211_M_AHDEMO:
2163147Sxc151355 wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
2173147Sxc151355 IEEE80211_ADDR_COPY(wh->i_addr1, daddr);
2183147Sxc151355 IEEE80211_ADDR_COPY(wh->i_addr2, saddr);
2193147Sxc151355 IEEE80211_ADDR_COPY(wh->i_addr3, wdp->wd_bssid);
2203147Sxc151355 break;
2213147Sxc151355
2223147Sxc151355 case IEEE80211_M_HOSTAP:
2233147Sxc151355 wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS;
2243147Sxc151355 IEEE80211_ADDR_COPY(wh->i_addr1, daddr);
2253147Sxc151355 IEEE80211_ADDR_COPY(wh->i_addr2, wdp->wd_bssid);
2263147Sxc151355 IEEE80211_ADDR_COPY(wh->i_addr3, saddr);
2273147Sxc151355 break;
2283147Sxc151355 }
2293147Sxc151355
230*10266SQuaker.Fang@Sun.COM if (wdp->wd_qospad) {
231*10266SQuaker.Fang@Sun.COM struct ieee80211_qosframe *qwh =
232*10266SQuaker.Fang@Sun.COM (struct ieee80211_qosframe *)wh;
233*10266SQuaker.Fang@Sun.COM qwh->i_qos[1] = 0;
234*10266SQuaker.Fang@Sun.COM qwh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_QOS;
235*10266SQuaker.Fang@Sun.COM }
236*10266SQuaker.Fang@Sun.COM
2374126Szf162725 switch (wdp->wd_secalloc) {
2384126Szf162725 case WIFI_SEC_WEP:
2394126Szf162725 /*
2404126Szf162725 * Fill in the fixed parts of the WEP-portion of the frame.
2414126Szf162725 */
2423147Sxc151355 wh->i_fc[1] |= IEEE80211_FC1_WEP;
2433147Sxc151355 /*
2443147Sxc151355 * The actual contents of the WEP-portion of the packet
2453147Sxc151355 * are computed when the packet is sent -- for now, we
2463147Sxc151355 * just need to account for the size.
2473147Sxc151355 */
2483147Sxc151355 mp->b_wptr += IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN;
2494126Szf162725 break;
2504126Szf162725
2514126Szf162725 case WIFI_SEC_WPA:
2524126Szf162725 wh->i_fc[1] |= IEEE80211_FC1_WEP;
2534126Szf162725 mp->b_wptr += IEEE80211_WEP_IVLEN +
2544126Szf162725 IEEE80211_WEP_KIDLEN + IEEE80211_WEP_EXTIVLEN;
2554126Szf162725 break;
2564126Szf162725
2574126Szf162725 default:
2584126Szf162725 break;
2593147Sxc151355 }
2603147Sxc151355
2613147Sxc151355 /*
2623147Sxc151355 * Fill in the fixed parts of the ieee80211_llc header.
2633147Sxc151355 */
2643147Sxc151355 llc = (struct ieee80211_llc *)mp->b_wptr;
2653147Sxc151355 mp->b_wptr += sizeof (struct ieee80211_llc);
2663147Sxc151355 bcopy(wifi_ietfmagic, llc, sizeof (wifi_ietfmagic));
2673147Sxc151355 llc->illc_ether_type = htons(sap);
2683147Sxc151355
2693147Sxc151355 return (mp);
2703147Sxc151355 }
2713147Sxc151355
2723147Sxc151355 /*
2733147Sxc151355 * Use the provided `mp' (which is expected to point to a WiFi header), and
2743147Sxc151355 * fill in the provided `mhp'. Return an errno on failure.
2753147Sxc151355 */
2763147Sxc151355 /* ARGSUSED */
2773147Sxc151355 static int
mac_wifi_header_info(mblk_t * mp,void * pdata,mac_header_info_t * mhp)2783147Sxc151355 mac_wifi_header_info(mblk_t *mp, void *pdata, mac_header_info_t *mhp)
2793147Sxc151355 {
2803147Sxc151355 struct ieee80211_frame *wh;
2813147Sxc151355 struct ieee80211_llc *llc;
2823147Sxc151355 uchar_t *llcp;
2834126Szf162725 wifi_data_t *wdp = pdata;
2843147Sxc151355
2853147Sxc151355 if (MBLKL(mp) < sizeof (struct ieee80211_frame))
2863147Sxc151355 return (EINVAL);
2873147Sxc151355
2883147Sxc151355 wh = (struct ieee80211_frame *)mp->b_rptr;
2893147Sxc151355 llcp = mp->b_rptr + sizeof (struct ieee80211_frame);
2903147Sxc151355
2913147Sxc151355 /*
292*10266SQuaker.Fang@Sun.COM * Generally, QoS data field takes 2 bytes, but some special hardware,
293*10266SQuaker.Fang@Sun.COM * such as Atheros, will need the 802.11 header padded to a 32-bit
294*10266SQuaker.Fang@Sun.COM * boundary for 4-address and QoS frames, at this time, it's 4 bytes.
295*10266SQuaker.Fang@Sun.COM */
296*10266SQuaker.Fang@Sun.COM if (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_QOS)
297*10266SQuaker.Fang@Sun.COM llcp += wdp->wd_qospad;
298*10266SQuaker.Fang@Sun.COM
299*10266SQuaker.Fang@Sun.COM /*
3003147Sxc151355 * When we receive frames from other hosts, the hardware will have
3013147Sxc151355 * already performed WEP decryption, and thus there will not be a WEP
3023147Sxc151355 * portion. However, when we receive a loopback copy of our own
3033147Sxc151355 * packets, it will still have a WEP portion. Skip past it to get to
3043147Sxc151355 * the LLC header.
3053147Sxc151355 */
3064126Szf162725 if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
3073147Sxc151355 llcp += IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN;
3084126Szf162725 if (wdp->wd_secalloc == WIFI_SEC_WPA)
3094126Szf162725 llcp += IEEE80211_WEP_EXTIVLEN;
3104126Szf162725 }
3113147Sxc151355
3126990Sgd78059 if ((uintptr_t)mp->b_wptr - (uintptr_t)llcp <
3136990Sgd78059 sizeof (struct ieee80211_llc))
3143147Sxc151355 return (EINVAL);
3153147Sxc151355
3163147Sxc151355 llc = (struct ieee80211_llc *)llcp;
3173147Sxc151355 mhp->mhi_origsap = ntohs(llc->illc_ether_type);
3183147Sxc151355 mhp->mhi_bindsap = mhp->mhi_origsap;
3193147Sxc151355 mhp->mhi_pktsize = 0;
3206990Sgd78059 mhp->mhi_hdrsize = (uintptr_t)llcp + sizeof (*llc) -
3216990Sgd78059 (uintptr_t)mp->b_rptr;
3223147Sxc151355
3233147Sxc151355 /*
3243147Sxc151355 * Verify the LLC header is one of the known formats. As per MSFT's
3253147Sxc151355 * convention, if the header is using IEEE 802.1H encapsulation, then
3263147Sxc151355 * treat the LLC header as data. As per DL_ETHER custom when treating
3273147Sxc151355 * the LLC header as data, set the mhi_bindsap to be DLS_SAP_LLC, and
3283147Sxc151355 * assume mhi_origsap contains the data length.
3293147Sxc151355 */
3303147Sxc151355 if (bcmp(llc, wifi_ieeemagic, sizeof (wifi_ieeemagic)) == 0) {
3313147Sxc151355 mhp->mhi_bindsap = DLS_SAP_LLC;
3323147Sxc151355 mhp->mhi_hdrsize -= sizeof (*llc);
3333147Sxc151355 mhp->mhi_pktsize = mhp->mhi_hdrsize + mhp->mhi_origsap;
3343147Sxc151355 } else if (bcmp(llc, wifi_ietfmagic, sizeof (wifi_ietfmagic)) != 0) {
3353147Sxc151355 return (EINVAL);
3363147Sxc151355 }
3373147Sxc151355
3383147Sxc151355 switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
3393147Sxc151355 case IEEE80211_FC1_DIR_NODS:
3403147Sxc151355 mhp->mhi_daddr = wh->i_addr1;
3413147Sxc151355 mhp->mhi_saddr = wh->i_addr2;
3423147Sxc151355 break;
3433147Sxc151355
3443147Sxc151355 case IEEE80211_FC1_DIR_TODS:
3453147Sxc151355 mhp->mhi_daddr = wh->i_addr3;
3463147Sxc151355 mhp->mhi_saddr = wh->i_addr2;
3473147Sxc151355 break;
3483147Sxc151355
3493147Sxc151355 case IEEE80211_FC1_DIR_FROMDS:
3503147Sxc151355 mhp->mhi_daddr = wh->i_addr1;
3513147Sxc151355 mhp->mhi_saddr = wh->i_addr3;
3523147Sxc151355 break;
3533147Sxc151355
3543147Sxc151355 case IEEE80211_FC1_DIR_DSTODS:
3553147Sxc151355 /* We don't support AP-to-AP mode yet */
3563147Sxc151355 return (ENOTSUP);
3573147Sxc151355 }
3583147Sxc151355
3593147Sxc151355 if (mac_wifi_unicst_verify(mhp->mhi_daddr, NULL) == 0)
3603147Sxc151355 mhp->mhi_dsttype = MAC_ADDRTYPE_UNICAST;
3613147Sxc151355 else if (mac_wifi_multicst_verify(mhp->mhi_daddr, NULL) == 0)
3623147Sxc151355 mhp->mhi_dsttype = MAC_ADDRTYPE_MULTICAST;
3633147Sxc151355 else
3643147Sxc151355 mhp->mhi_dsttype = MAC_ADDRTYPE_BROADCAST;
3653147Sxc151355
3663147Sxc151355 return (0);
3673147Sxc151355 }
3683147Sxc151355
3693147Sxc151355 /*
3703147Sxc151355 * Take the provided `mp' (which is expected to have an Ethernet header), and
3713147Sxc151355 * return a pointer to an mblk_t with a WiFi header. Note that the returned
3723147Sxc151355 * header will not be complete until the driver finishes filling it in prior
3733147Sxc151355 * to transmit. If the conversion cannot be performed, return NULL.
3743147Sxc151355 */
3753147Sxc151355 static mblk_t *
mac_wifi_header_cook(mblk_t * mp,void * pdata)3763147Sxc151355 mac_wifi_header_cook(mblk_t *mp, void *pdata)
3773147Sxc151355 {
3783147Sxc151355 struct ether_header *ehp;
3793147Sxc151355 mblk_t *llmp;
3803147Sxc151355
3813147Sxc151355 if (MBLKL(mp) < sizeof (struct ether_header))
3823147Sxc151355 return (NULL);
3833147Sxc151355
3846990Sgd78059 ehp = (void *)mp->b_rptr;
3853147Sxc151355 llmp = mac_wifi_header(&ehp->ether_shost, &ehp->ether_dhost,
3863147Sxc151355 ntohs(ehp->ether_type), pdata, NULL, 0);
3873147Sxc151355 if (llmp == NULL)
3883147Sxc151355 return (NULL);
3893147Sxc151355
3903147Sxc151355 /*
3913147Sxc151355 * The plugin framework guarantees that we have the only reference
3923147Sxc151355 * to the mblk_t, so we can safely modify it.
3933147Sxc151355 */
3943147Sxc151355 ASSERT(DB_REF(mp) == 1);
3953147Sxc151355 mp->b_rptr += sizeof (struct ether_header);
3963147Sxc151355 llmp->b_cont = mp;
3973147Sxc151355 return (llmp);
3983147Sxc151355 }
3993147Sxc151355
4003147Sxc151355 /*
4013147Sxc151355 * Take the provided `mp' (which is expected to have a WiFi header), and
4023147Sxc151355 * return a pointer to an mblk_t with an Ethernet header. If the conversion
4033147Sxc151355 * cannot be performed, return NULL.
4043147Sxc151355 */
4053147Sxc151355 static mblk_t *
mac_wifi_header_uncook(mblk_t * mp,void * pdata)4063147Sxc151355 mac_wifi_header_uncook(mblk_t *mp, void *pdata)
4073147Sxc151355 {
4083147Sxc151355 mac_header_info_t mhi;
4093147Sxc151355 struct ether_header eh;
4103147Sxc151355
4113147Sxc151355 if (mac_wifi_header_info(mp, pdata, &mhi) != 0) {
4123147Sxc151355 /*
4133147Sxc151355 * The plugin framework guarantees the header is properly
4143147Sxc151355 * formed, so this should never happen.
4153147Sxc151355 */
4163147Sxc151355 return (NULL);
4173147Sxc151355 }
4183147Sxc151355
4193147Sxc151355 /*
4203147Sxc151355 * The plugin framework guarantees that we have the only reference to
4213147Sxc151355 * the mblk_t and the underlying dblk_t, so we can safely modify it.
4223147Sxc151355 */
4233147Sxc151355 ASSERT(DB_REF(mp) == 1);
4243147Sxc151355
4253147Sxc151355 IEEE80211_ADDR_COPY(&eh.ether_dhost, mhi.mhi_daddr);
4263147Sxc151355 IEEE80211_ADDR_COPY(&eh.ether_shost, mhi.mhi_saddr);
4273147Sxc151355 eh.ether_type = htons(mhi.mhi_origsap);
4283147Sxc151355
4293147Sxc151355 ASSERT(mhi.mhi_hdrsize >= sizeof (struct ether_header));
4303147Sxc151355 mp->b_rptr += mhi.mhi_hdrsize - sizeof (struct ether_header);
4313147Sxc151355 bcopy(&eh, mp->b_rptr, sizeof (struct ether_header));
4323147Sxc151355 return (mp);
4333147Sxc151355 }
4343147Sxc151355
4353147Sxc151355 static mactype_ops_t mac_wifi_type_ops = {
4363147Sxc151355 MTOPS_PDATA_VERIFY | MTOPS_HEADER_COOK | MTOPS_HEADER_UNCOOK,
4373147Sxc151355 mac_wifi_unicst_verify,
4383147Sxc151355 mac_wifi_multicst_verify,
4393147Sxc151355 mac_wifi_sap_verify,
4403147Sxc151355 mac_wifi_header,
4413147Sxc151355 mac_wifi_header_info,
4423147Sxc151355 mac_wifi_pdata_verify,
4433147Sxc151355 mac_wifi_header_cook,
4443147Sxc151355 mac_wifi_header_uncook
4453147Sxc151355 };
446