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