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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/strsubr.h> 27 #include <inet/led.h> 28 #include <sys/softmac_impl.h> 29 30 mblk_t * 31 softmac_m_tx(void *arg, mblk_t *mp) 32 { 33 queue_t *wq = ((softmac_t *)arg)->smac_lower->sl_wq; 34 35 /* 36 * Optimize for the most common case. 37 */ 38 if (mp->b_next == NULL) { 39 if (!SOFTMAC_CANPUTNEXT(wq)) 40 return (mp); 41 42 mp->b_flag |= MSGNOLOOP; 43 putnext(wq, mp); 44 return (NULL); 45 } 46 47 while (mp != NULL) { 48 mblk_t *next = mp->b_next; 49 50 if (!SOFTMAC_CANPUTNEXT(wq)) 51 break; 52 mp->b_next = NULL; 53 mp->b_flag |= MSGNOLOOP; 54 putnext(wq, mp); 55 mp = next; 56 } 57 return (mp); 58 } 59 60 void 61 softmac_rput_process_data(softmac_lower_t *slp, mblk_t *mp) 62 { 63 /* 64 * When packets arrive, the softmac might not be fully started. 65 */ 66 ASSERT((slp->sl_softmac != NULL)); 67 ASSERT((mp->b_next == NULL) && (mp->b_prev == NULL)); 68 69 if (DB_REF(mp) > 1) { 70 mblk_t *tmp; 71 uint32_t start, stuff, end, value, flags; 72 73 if ((tmp = copymsg(mp)) == NULL) { 74 cmn_err(CE_WARN, "softmac_rput_process_data: " 75 "copymsg failed"); 76 goto failed; 77 } 78 hcksum_retrieve(mp, NULL, NULL, &start, &stuff, &end, 79 &value, &flags); 80 VERIFY(hcksum_assoc(tmp, NULL, NULL, start, stuff, end, 81 value, flags, KM_NOSLEEP) == 0); 82 freemsg(mp); 83 mp = tmp; 84 } 85 86 mac_rx(slp->sl_softmac->smac_mh, NULL, mp); 87 return; 88 89 failed: 90 freemsg(mp); 91 } 92 93 #define ACKTIMEOUT (10 * hz) 94 95 /* 96 * Serialize control message processing. 97 */ 98 static void 99 softmac_serialize_enter(softmac_lower_t *slp) 100 { 101 mutex_enter(&slp->sl_ctl_mutex); 102 while (slp->sl_ctl_inprogress) 103 cv_wait(&slp->sl_ctl_cv, &slp->sl_ctl_mutex); 104 105 ASSERT(!slp->sl_ctl_inprogress); 106 ASSERT(!slp->sl_pending_ioctl); 107 ASSERT(slp->sl_pending_prim == DL_PRIM_INVAL); 108 109 slp->sl_ctl_inprogress = B_TRUE; 110 mutex_exit(&slp->sl_ctl_mutex); 111 } 112 113 static void 114 softmac_serialize_exit(softmac_lower_t *slp) 115 { 116 mutex_enter(&slp->sl_ctl_mutex); 117 118 ASSERT(slp->sl_ctl_inprogress); 119 ASSERT(!slp->sl_pending_ioctl); 120 ASSERT(slp->sl_pending_prim == DL_PRIM_INVAL); 121 122 slp->sl_ctl_inprogress = B_FALSE; 123 cv_broadcast(&slp->sl_ctl_cv); 124 mutex_exit(&slp->sl_ctl_mutex); 125 } 126 127 static int 128 dlpi_get_errno(t_uscalar_t error, t_uscalar_t unix_errno) 129 { 130 return (error == DL_SYSERR ? unix_errno : EINVAL); 131 } 132 133 int 134 softmac_output(softmac_lower_t *slp, mblk_t *mp, t_uscalar_t dl_prim, 135 t_uscalar_t ack, mblk_t **mpp) 136 { 137 union DL_primitives *dlp; 138 int err = 0; 139 140 softmac_serialize_enter(slp); 141 142 /* 143 * Record the pending DLPI primitive. 144 */ 145 mutex_enter(&slp->sl_mutex); 146 slp->sl_pending_prim = dl_prim; 147 mutex_exit(&slp->sl_mutex); 148 149 putnext(slp->sl_wq, mp); 150 151 mutex_enter(&slp->sl_mutex); 152 while (slp->sl_pending_prim != DL_PRIM_INVAL) { 153 if (cv_timedwait(&slp->sl_cv, &slp->sl_mutex, 154 lbolt + ACKTIMEOUT) == -1) 155 break; 156 } 157 158 mp = slp->sl_ack_mp; 159 slp->sl_ack_mp = NULL; 160 161 /* 162 * If we timed out, sl_ack_mp will still be NULL, but sl_pending_prim 163 * won't be set to DL_PRIM_INVAL. 164 */ 165 ASSERT(mp != NULL || slp->sl_pending_prim != DL_PRIM_INVAL); 166 167 slp->sl_pending_prim = DL_PRIM_INVAL; 168 mutex_exit(&slp->sl_mutex); 169 170 if (mp != NULL) { 171 dlp = (union DL_primitives *)mp->b_rptr; 172 173 if (dlp->dl_primitive == DL_ERROR_ACK) { 174 err = dlpi_get_errno(dlp->error_ack.dl_errno, 175 dlp->error_ack.dl_unix_errno); 176 } else { 177 ASSERT(dlp->dl_primitive == ack); 178 } 179 } else { 180 err = ENOMSG; 181 } 182 183 if (mpp != NULL) 184 *mpp = mp; 185 else 186 freemsg(mp); 187 188 softmac_serialize_exit(slp); 189 return (err); 190 } 191 192 void 193 softmac_ioctl_tx(softmac_lower_t *slp, mblk_t *mp, mblk_t **mpp) 194 { 195 softmac_serialize_enter(slp); 196 197 /* 198 * Record that ioctl processing is currently in progress. 199 */ 200 mutex_enter(&slp->sl_mutex); 201 slp->sl_pending_ioctl = B_TRUE; 202 mutex_exit(&slp->sl_mutex); 203 204 putnext(slp->sl_wq, mp); 205 206 mutex_enter(&slp->sl_mutex); 207 while (slp->sl_pending_ioctl) 208 cv_wait(&slp->sl_cv, &slp->sl_mutex); 209 mp = slp->sl_ack_mp; 210 slp->sl_ack_mp = NULL; 211 mutex_exit(&slp->sl_mutex); 212 213 ASSERT(mpp != NULL && mp != NULL); 214 *mpp = mp; 215 216 softmac_serialize_exit(slp); 217 } 218 219 int 220 softmac_mexchange_error_ack(mblk_t **mpp, t_uscalar_t error_primitive, 221 t_uscalar_t error, t_uscalar_t unix_errno) 222 { 223 union DL_primitives *dlp; 224 225 if ((*mpp = mexchange(NULL, *mpp, sizeof (dl_error_ack_t), M_PCPROTO, 226 DL_ERROR_ACK)) == NULL) 227 return (ENOMEM); 228 229 dlp = (union DL_primitives *)(*mpp)->b_rptr; 230 dlp->error_ack.dl_error_primitive = error_primitive; 231 dlp->error_ack.dl_errno = error; 232 dlp->error_ack.dl_unix_errno = unix_errno; 233 234 return (0); 235 } 236 237 int 238 softmac_proto_tx(softmac_lower_t *slp, mblk_t *mp, mblk_t **mpp) 239 { 240 int err = 0; 241 t_uscalar_t dl_prim; 242 243 dl_prim = ((union DL_primitives *)mp->b_rptr)->dl_primitive; 244 245 ASSERT(slp->sl_softmac != NULL); 246 247 switch (dl_prim) { 248 case DL_ENABMULTI_REQ: 249 case DL_DISABMULTI_REQ: 250 case DL_SET_PHYS_ADDR_REQ: 251 case DL_UNBIND_REQ: 252 case DL_UDQOS_REQ: 253 case DL_PROMISCON_REQ: 254 case DL_PROMISCOFF_REQ: 255 err = softmac_output(slp, mp, dl_prim, DL_OK_ACK, mpp); 256 break; 257 case DL_BIND_REQ: 258 err = softmac_output(slp, mp, dl_prim, DL_BIND_ACK, mpp); 259 break; 260 case DL_NOTIFY_REQ: 261 err = softmac_output(slp, mp, dl_prim, DL_NOTIFY_ACK, mpp); 262 break; 263 case DL_CONTROL_REQ: 264 err = softmac_output(slp, mp, dl_prim, DL_CONTROL_ACK, mpp); 265 break; 266 case DL_CAPABILITY_REQ: 267 err = softmac_output(slp, mp, dl_prim, DL_CAPABILITY_ACK, mpp); 268 break; 269 default: 270 if (mpp != NULL) { 271 *mpp = mp; 272 err = softmac_mexchange_error_ack(mpp, dl_prim, 273 DL_UNSUPPORTED, 0); 274 } 275 break; 276 } 277 return (err); 278 } 279