1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/stropts.h> 29 #include <sys/softmac_impl.h> 30 31 int 32 softmac_send_notify_req(softmac_lower_t *slp, uint32_t notifications) 33 { 34 mblk_t *reqmp; 35 36 /* 37 * create notify req message and send it down 38 */ 39 reqmp = mexchange(NULL, NULL, DL_NOTIFY_REQ_SIZE, M_PROTO, 40 DL_NOTIFY_REQ); 41 if (reqmp == NULL) 42 return (ENOMEM); 43 44 ((dl_notify_req_t *)reqmp->b_rptr)->dl_notifications = notifications; 45 46 return (softmac_proto_tx(slp, reqmp, NULL)); 47 } 48 49 int 50 softmac_send_bind_req(softmac_lower_t *slp, uint_t sap) 51 { 52 dl_bind_req_t *bind; 53 mblk_t *reqmp; 54 55 /* 56 * create bind req message and send it down 57 */ 58 reqmp = mexchange(NULL, NULL, DL_BIND_REQ_SIZE, M_PROTO, DL_BIND_REQ); 59 if (reqmp == NULL) 60 return (ENOMEM); 61 62 bind = (dl_bind_req_t *)reqmp->b_rptr; 63 bind->dl_sap = sap; 64 bind->dl_conn_mgmt = 0; 65 bind->dl_max_conind = 0; 66 bind->dl_xidtest_flg = 0; 67 bind->dl_service_mode = DL_CLDLS; 68 69 return (softmac_proto_tx(slp, reqmp, NULL)); 70 } 71 72 int 73 softmac_send_promisc_req(softmac_lower_t *slp, t_uscalar_t level, boolean_t on) 74 { 75 mblk_t *reqmp; 76 size_t size; 77 t_uscalar_t dl_prim; 78 79 /* 80 * create promisc message and send it down 81 */ 82 if (on) { 83 dl_prim = DL_PROMISCON_REQ; 84 size = DL_PROMISCON_REQ_SIZE; 85 } else { 86 dl_prim = DL_PROMISCOFF_REQ; 87 size = DL_PROMISCOFF_REQ_SIZE; 88 } 89 90 reqmp = mexchange(NULL, NULL, size, M_PROTO, dl_prim); 91 if (reqmp == NULL) 92 return (ENOMEM); 93 94 if (on) 95 ((dl_promiscon_req_t *)reqmp->b_rptr)->dl_level = level; 96 else 97 ((dl_promiscoff_req_t *)reqmp->b_rptr)->dl_level = level; 98 99 return (softmac_proto_tx(slp, reqmp, NULL)); 100 } 101 102 int 103 softmac_m_promisc(void *arg, boolean_t on) 104 { 105 softmac_t *softmac = arg; 106 softmac_lower_t *slp = softmac->smac_lower; 107 108 ASSERT(slp != NULL); 109 return (softmac_send_promisc_req(slp, DL_PROMISC_PHYS, on)); 110 } 111 112 int 113 softmac_m_multicst(void *arg, boolean_t add, const uint8_t *mca) 114 { 115 softmac_t *softmac = arg; 116 softmac_lower_t *slp; 117 dl_enabmulti_req_t *enabmulti; 118 dl_disabmulti_req_t *disabmulti; 119 mblk_t *reqmp; 120 t_uscalar_t dl_prim; 121 uint32_t size, addr_length; 122 123 /* 124 * create multicst message and send it down 125 */ 126 addr_length = softmac->smac_addrlen; 127 if (add) { 128 size = sizeof (dl_enabmulti_req_t) + addr_length; 129 dl_prim = DL_ENABMULTI_REQ; 130 } else { 131 size = sizeof (dl_disabmulti_req_t) + addr_length; 132 dl_prim = DL_DISABMULTI_REQ; 133 } 134 135 reqmp = mexchange(NULL, NULL, size, M_PROTO, dl_prim); 136 if (reqmp == NULL) 137 return (ENOMEM); 138 139 if (add) { 140 enabmulti = (dl_enabmulti_req_t *)reqmp->b_rptr; 141 enabmulti->dl_addr_offset = sizeof (dl_enabmulti_req_t); 142 enabmulti->dl_addr_length = addr_length; 143 (void) memcpy(&enabmulti[1], mca, addr_length); 144 } else { 145 disabmulti = (dl_disabmulti_req_t *)reqmp->b_rptr; 146 disabmulti->dl_addr_offset = sizeof (dl_disabmulti_req_t); 147 disabmulti->dl_addr_length = addr_length; 148 (void) memcpy(&disabmulti[1], mca, addr_length); 149 } 150 151 slp = softmac->smac_lower; 152 ASSERT(slp != NULL); 153 return (softmac_proto_tx(slp, reqmp, NULL)); 154 } 155 156 int 157 softmac_m_unicst(void *arg, const uint8_t *macaddr) 158 { 159 softmac_t *softmac = arg; 160 softmac_lower_t *slp; 161 dl_set_phys_addr_req_t *phyaddr; 162 mblk_t *reqmp; 163 size_t size; 164 165 /* 166 * create set_phys_addr message and send it down 167 */ 168 size = DL_SET_PHYS_ADDR_REQ_SIZE + softmac->smac_addrlen; 169 reqmp = mexchange(NULL, NULL, size, M_PROTO, DL_SET_PHYS_ADDR_REQ); 170 if (reqmp == NULL) 171 return (ENOMEM); 172 173 phyaddr = (dl_set_phys_addr_req_t *)reqmp->b_rptr; 174 phyaddr->dl_addr_offset = sizeof (dl_set_phys_addr_req_t); 175 phyaddr->dl_addr_length = softmac->smac_addrlen; 176 (void) memcpy(&phyaddr[1], macaddr, softmac->smac_addrlen); 177 178 slp = softmac->smac_lower; 179 ASSERT(slp != NULL); 180 return (softmac_proto_tx(slp, reqmp, NULL)); 181 } 182 183 void 184 softmac_m_ioctl(void *arg, queue_t *wq, mblk_t *mp) 185 { 186 softmac_lower_t *slp = ((softmac_t *)arg)->smac_lower; 187 mblk_t *ackmp; 188 189 ASSERT(slp != NULL); 190 softmac_ioctl_tx(slp, mp, &ackmp); 191 qreply(wq, ackmp); 192 } 193 194 static void 195 softmac_process_notify_ind(queue_t *rq, mblk_t *mp) 196 { 197 softmac_lower_t *slp = rq->q_ptr; 198 dl_notify_ind_t *dlnip = (dl_notify_ind_t *)mp->b_rptr; 199 softmac_t *softmac = slp->sl_softmac; 200 uint_t addroff, addrlen; 201 202 ASSERT(dlnip->dl_primitive == DL_NOTIFY_IND); 203 204 switch (dlnip->dl_notification) { 205 case DL_NOTE_PHYS_ADDR: 206 if (dlnip->dl_data != DL_CURR_PHYS_ADDR) 207 break; 208 209 addroff = dlnip->dl_addr_offset; 210 addrlen = dlnip->dl_addr_length - softmac->smac_saplen; 211 if (addroff == 0 || addrlen != softmac->smac_addrlen || 212 !MBLKIN(mp, addroff, addrlen)) { 213 cmn_err(CE_NOTE, "softmac: got malformed " 214 "DL_NOTIFY_IND; length/offset %d/%d", 215 addrlen, addroff); 216 break; 217 } 218 219 mac_unicst_update(softmac->smac_mh, mp->b_rptr + addroff); 220 break; 221 222 case DL_NOTE_LINK_UP: 223 mac_link_update(softmac->smac_mh, LINK_STATE_UP); 224 break; 225 226 case DL_NOTE_LINK_DOWN: 227 mac_link_update(softmac->smac_mh, LINK_STATE_DOWN); 228 break; 229 } 230 231 freemsg(mp); 232 } 233 234 static void 235 softmac_process_dlpi(softmac_lower_t *slp, mblk_t *mp, uint_t minlen, 236 t_uscalar_t reqprim) 237 { 238 const char *ackname; 239 240 ackname = dl_primstr(((union DL_primitives *)mp->b_rptr)->dl_primitive); 241 242 if (MBLKL(mp) < minlen) { 243 cmn_err(CE_WARN, "softmac: got short %s", ackname); 244 freemsg(mp); 245 return; 246 } 247 248 mutex_enter(&slp->sl_mutex); 249 if (slp->sl_pending_prim != reqprim) { 250 cmn_err(CE_NOTE, "softmac: got unexpected %s", ackname); 251 mutex_exit(&slp->sl_mutex); 252 freemsg(mp); 253 return; 254 } 255 256 slp->sl_pending_prim = DL_PRIM_INVAL; 257 slp->sl_ack_mp = mp; 258 cv_signal(&slp->sl_cv); 259 mutex_exit(&slp->sl_mutex); 260 } 261 262 void 263 softmac_rput_process_proto(queue_t *rq, mblk_t *mp) 264 { 265 softmac_lower_t *slp = rq->q_ptr; 266 union DL_primitives *dlp = (union DL_primitives *)mp->b_rptr; 267 ssize_t len = MBLKL(mp); 268 const char *primstr; 269 270 if (len < sizeof (t_uscalar_t)) { 271 cmn_err(CE_WARN, "softmac: got runt DLPI message"); 272 goto exit; 273 } 274 275 primstr = dl_primstr(dlp->dl_primitive); 276 277 switch (dlp->dl_primitive) { 278 case DL_OK_ACK: 279 if (len < DL_OK_ACK_SIZE) 280 goto runt; 281 282 softmac_process_dlpi(slp, mp, DL_OK_ACK_SIZE, 283 dlp->ok_ack.dl_correct_primitive); 284 return; 285 286 case DL_ERROR_ACK: 287 if (len < DL_ERROR_ACK_SIZE) 288 goto runt; 289 290 softmac_process_dlpi(slp, mp, DL_ERROR_ACK_SIZE, 291 dlp->error_ack.dl_error_primitive); 292 return; 293 294 case DL_NOTIFY_IND: 295 if (len < DL_NOTIFY_IND_SIZE) 296 goto runt; 297 298 softmac_process_notify_ind(rq, mp); 299 return; 300 301 case DL_NOTIFY_ACK: 302 softmac_process_dlpi(slp, mp, DL_NOTIFY_ACK_SIZE, 303 DL_NOTIFY_REQ); 304 return; 305 306 case DL_CAPABILITY_ACK: 307 softmac_process_dlpi(slp, mp, DL_CAPABILITY_ACK_SIZE, 308 DL_CAPABILITY_REQ); 309 return; 310 311 case DL_BIND_ACK: 312 softmac_process_dlpi(slp, mp, DL_BIND_ACK_SIZE, DL_BIND_REQ); 313 return; 314 315 case DL_CONTROL_ACK: 316 softmac_process_dlpi(slp, mp, DL_CONTROL_ACK_SIZE, 317 DL_CONTROL_REQ); 318 return; 319 320 case DL_UNITDATA_IND: 321 case DL_PHYS_ADDR_ACK: 322 /* 323 * a. Because the stream is in DLIOCRAW mode, 324 * DL_UNITDATA_IND messages are not expected. 325 * b. The lower stream should not receive DL_PHYS_ADDR_REQ, 326 * so DL_PHYS_ADDR_ACK messages are also unexpected. 327 */ 328 default: 329 cmn_err(CE_WARN, "softmac: got unexpected %s", primstr); 330 break; 331 } 332 exit: 333 freemsg(mp); 334 return; 335 runt: 336 cmn_err(CE_WARN, "softmac: got runt %s", primstr); 337 freemsg(mp); 338 } 339 340 void 341 softmac_rput_process_notdata(queue_t *rq, mblk_t *mp) 342 { 343 softmac_lower_t *slp = rq->q_ptr; 344 345 switch (DB_TYPE(mp)) { 346 case M_PROTO: 347 case M_PCPROTO: 348 softmac_rput_process_proto(rq, mp); 349 break; 350 351 case M_FLUSH: 352 if (*mp->b_rptr & FLUSHR) 353 flushq(rq, FLUSHDATA); 354 if (*mp->b_rptr & FLUSHW) 355 flushq(OTHERQ(rq), FLUSHDATA); 356 putnext(rq, mp); 357 break; 358 359 case M_IOCACK: 360 case M_IOCNAK: 361 case M_COPYIN: 362 case M_COPYOUT: 363 mutex_enter(&slp->sl_mutex); 364 if (!slp->sl_pending_ioctl) { 365 mutex_exit(&slp->sl_mutex); 366 cmn_err(CE_NOTE, "softmac: got unexpected mblk " 367 "type 0x%x", DB_TYPE(mp)); 368 freemsg(mp); 369 break; 370 } 371 372 slp->sl_pending_ioctl = B_FALSE; 373 slp->sl_ack_mp = mp; 374 cv_broadcast(&slp->sl_cv); 375 mutex_exit(&slp->sl_mutex); 376 return; 377 378 default: 379 cmn_err(CE_NOTE, "softmac: got unsupported mblk type 0x%x", 380 DB_TYPE(mp)); 381 freemsg(mp); 382 break; 383 } 384 } 385