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 /*
27 * Data-Link Services Module
28 */
29
30 #include <sys/strsun.h>
31 #include <sys/vlan.h>
32 #include <sys/dld_impl.h>
33 #include <sys/mac_client_priv.h>
34
35 int
36 dls_open(dls_link_t *dlp, dls_dl_handle_t ddh, dld_str_t *dsp)
37 {
38 zoneid_t zid = getzoneid();
39 boolean_t local;
40 int err;
41
42 /*
43 * Check whether this client belongs to the zone of this dlp. Note that
65 * Cache a copy of the MAC interface handle, a pointer to the
66 * immutable MAC info.
67 */
68 dsp->ds_dlp = dlp;
69 dsp->ds_mh = dlp->dl_mh;
70 dsp->ds_mch = dlp->dl_mch;
71 dsp->ds_mip = dlp->dl_mip;
72 dsp->ds_ddh = ddh;
73 dsp->ds_local = local;
74
75 ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
76 return (0);
77 }
78
79 void
80 dls_close(dld_str_t *dsp)
81 {
82 dls_link_t *dlp = dsp->ds_dlp;
83 dls_multicst_addr_t *p;
84 dls_multicst_addr_t *nextp;
85 uint32_t old_flags;
86
87 ASSERT(dsp->ds_datathr_cnt == 0);
88 ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
89
90 if (dsp->ds_local)
91 dlp->dl_zone_ref--;
92 dsp->ds_local = B_FALSE;
93
94 /*
95 * Walk the list of multicast addresses, disabling each at the MAC.
96 * Note that we must remove multicast address before
97 * mac_unicast_remove() (called by dls_active_clear()) because
98 * mac_multicast_remove() relies on the unicast flows on the mac
99 * client.
100 */
101 for (p = dsp->ds_dmap; p != NULL; p = nextp) {
102 (void) mac_multicast_remove(dsp->ds_mch, p->dma_addr);
103 nextp = p->dma_nextp;
104 kmem_free(p, sizeof (dls_multicst_addr_t));
105 }
106 dsp->ds_dmap = NULL;
107
108 dls_active_clear(dsp, B_TRUE);
109
110 /*
111 * If the dld_str_t is bound then unbind it.
112 */
113 if (dsp->ds_dlstate == DL_IDLE) {
114 dls_unbind(dsp);
115 dsp->ds_dlstate = DL_UNBOUND;
116 }
117
118 /*
119 * If the MAC has been set in promiscuous mode then disable it.
120 * This needs to be done before resetting ds_rx.
121 */
122 old_flags = dsp->ds_promisc;
123 dsp->ds_promisc = 0;
124 (void) dls_promisc(dsp, old_flags);
125
126 /*
127 * At this point we have cutoff inbound packet flow from the mac
128 * for this 'dsp'. The dls_link_remove above cut off packets meant
129 * for us and waited for upcalls to finish. Similarly the dls_promisc
130 * reset above waited for promisc callbacks to finish. Now we can
131 * safely reset ds_rx to NULL
132 */
133 dsp->ds_rx = NULL;
134 dsp->ds_rx_arg = NULL;
135
136 dsp->ds_dlp = NULL;
137
138 if (!mac_capab_get(dsp->ds_mh, MAC_CAPAB_LEGACY, NULL))
139 mac_stop(dsp->ds_mh);
140
141 /*
142 * Release our reference to the dls_link_t allowing that to be
143 * destroyed if there are no more dls_impl_t.
144 */
217
218 /*
219 * For VLAN SAP, there was a promisc handle registered when dls_bind.
220 * When unbind this dls link, we need to remove the promisc handle.
221 * See comments in dls_bind().
222 */
223 if (dsp->ds_vlan_mph != NULL) {
224 mac_promisc_remove(dsp->ds_vlan_mph);
225 dsp->ds_vlan_mph = NULL;
226 return;
227 }
228
229 /*
230 * Unbind the dld_str_t by removing it from the hash table in the
231 * dls_link_t.
232 */
233 dls_link_remove(dsp->ds_dlp, dsp);
234 dsp->ds_sap = 0;
235 }
236
237 int
238 dls_promisc(dld_str_t *dsp, uint32_t old_flags)
239 {
240 int err = 0;
241
242 ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
243 ASSERT(!(dsp->ds_promisc & ~(DLS_PROMISC_SAP | DLS_PROMISC_MULTI |
244 DLS_PROMISC_PHYS)));
245
246 if (old_flags == 0 && dsp->ds_promisc != 0) {
247 /*
248 * If only DLS_PROMISC_SAP, we don't turn on the
249 * physical promisc mode
250 */
251 err = mac_promisc_add(dsp->ds_mch, MAC_CLIENT_PROMISC_ALL,
252 dls_rx_promisc, dsp, &dsp->ds_mph,
253 (dsp->ds_promisc != DLS_PROMISC_SAP) ? 0 :
254 MAC_PROMISC_FLAGS_NO_PHYS);
255 if (err != 0)
256 return (err);
257
258 /* Remove vlan promisc handle to avoid sending dup copy up */
259 if (dsp->ds_vlan_mph != NULL) {
260 mac_promisc_remove(dsp->ds_vlan_mph);
261 dsp->ds_vlan_mph = NULL;
262 }
263 } else if (old_flags != 0 && dsp->ds_promisc == 0) {
264 ASSERT(dsp->ds_mph != NULL);
265
266 mac_promisc_remove(dsp->ds_mph);
267 dsp->ds_mph = NULL;
268
269 if (dsp->ds_sap == ETHERTYPE_VLAN &&
270 dsp->ds_dlstate != DL_UNBOUND) {
271 int err;
272
273 if (dsp->ds_vlan_mph != NULL)
274 return (EINVAL);
275 err = mac_promisc_add(dsp->ds_mch,
276 MAC_CLIENT_PROMISC_ALL, dls_rx_vlan_promisc, dsp,
277 &dsp->ds_vlan_mph, MAC_PROMISC_FLAGS_NO_PHYS);
278 return (err);
279 }
280 } else if (old_flags == DLS_PROMISC_SAP && dsp->ds_promisc != 0 &&
281 dsp->ds_promisc != old_flags) {
282 /*
283 * If the old flag is PROMISC_SAP, but the current flag has
284 * changed to some new non-zero value, we need to turn the
285 * physical promiscuous mode.
286 */
287 ASSERT(dsp->ds_mph != NULL);
288 mac_promisc_remove(dsp->ds_mph);
289 err = mac_promisc_add(dsp->ds_mch, MAC_CLIENT_PROMISC_ALL,
290 dls_rx_promisc, dsp, &dsp->ds_mph, 0);
291 }
292
293 return (err);
294 }
295
296 int
297 dls_multicst_add(dld_str_t *dsp, const uint8_t *addr)
298 {
299 int err;
300 dls_multicst_addr_t **pp;
301 dls_multicst_addr_t *p;
302 uint_t addr_length;
303
304 ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
305
306 /*
307 * Check whether the address is in the list of enabled addresses for
308 * this dld_str_t.
309 */
310 addr_length = dsp->ds_mip->mi_addr_length;
|
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 * Copyright 2011, Nexenta Systems, Inc. All rights reserved.
25 */
26
27 /*
28 * Data-Link Services Module
29 */
30
31 #include <sys/strsun.h>
32 #include <sys/vlan.h>
33 #include <sys/dld_impl.h>
34 #include <sys/mac_client_priv.h>
35
36 int
37 dls_open(dls_link_t *dlp, dls_dl_handle_t ddh, dld_str_t *dsp)
38 {
39 zoneid_t zid = getzoneid();
40 boolean_t local;
41 int err;
42
43 /*
44 * Check whether this client belongs to the zone of this dlp. Note that
66 * Cache a copy of the MAC interface handle, a pointer to the
67 * immutable MAC info.
68 */
69 dsp->ds_dlp = dlp;
70 dsp->ds_mh = dlp->dl_mh;
71 dsp->ds_mch = dlp->dl_mch;
72 dsp->ds_mip = dlp->dl_mip;
73 dsp->ds_ddh = ddh;
74 dsp->ds_local = local;
75
76 ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
77 return (0);
78 }
79
80 void
81 dls_close(dld_str_t *dsp)
82 {
83 dls_link_t *dlp = dsp->ds_dlp;
84 dls_multicst_addr_t *p;
85 dls_multicst_addr_t *nextp;
86
87 ASSERT(dsp->ds_datathr_cnt == 0);
88 ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
89
90 if (dsp->ds_local)
91 dlp->dl_zone_ref--;
92 dsp->ds_local = B_FALSE;
93
94 /*
95 * Walk the list of multicast addresses, disabling each at the MAC.
96 * Note that we must remove multicast address before
97 * mac_unicast_remove() (called by dls_active_clear()) because
98 * mac_multicast_remove() relies on the unicast flows on the mac
99 * client.
100 */
101 for (p = dsp->ds_dmap; p != NULL; p = nextp) {
102 (void) mac_multicast_remove(dsp->ds_mch, p->dma_addr);
103 nextp = p->dma_nextp;
104 kmem_free(p, sizeof (dls_multicst_addr_t));
105 }
106 dsp->ds_dmap = NULL;
107
108 dls_active_clear(dsp, B_TRUE);
109
110 /*
111 * If the dld_str_t is bound then unbind it.
112 */
113 if (dsp->ds_dlstate == DL_IDLE) {
114 dls_unbind(dsp);
115 dsp->ds_dlstate = DL_UNBOUND;
116 }
117
118 /*
119 * If the MAC has been set in promiscuous mode then disable it.
120 * This needs to be done before resetting ds_rx.
121 */
122 (void) dls_promisc(dsp, 0);
123
124 /*
125 * At this point we have cutoff inbound packet flow from the mac
126 * for this 'dsp'. The dls_link_remove above cut off packets meant
127 * for us and waited for upcalls to finish. Similarly the dls_promisc
128 * reset above waited for promisc callbacks to finish. Now we can
129 * safely reset ds_rx to NULL
130 */
131 dsp->ds_rx = NULL;
132 dsp->ds_rx_arg = NULL;
133
134 dsp->ds_dlp = NULL;
135
136 if (!mac_capab_get(dsp->ds_mh, MAC_CAPAB_LEGACY, NULL))
137 mac_stop(dsp->ds_mh);
138
139 /*
140 * Release our reference to the dls_link_t allowing that to be
141 * destroyed if there are no more dls_impl_t.
142 */
215
216 /*
217 * For VLAN SAP, there was a promisc handle registered when dls_bind.
218 * When unbind this dls link, we need to remove the promisc handle.
219 * See comments in dls_bind().
220 */
221 if (dsp->ds_vlan_mph != NULL) {
222 mac_promisc_remove(dsp->ds_vlan_mph);
223 dsp->ds_vlan_mph = NULL;
224 return;
225 }
226
227 /*
228 * Unbind the dld_str_t by removing it from the hash table in the
229 * dls_link_t.
230 */
231 dls_link_remove(dsp->ds_dlp, dsp);
232 dsp->ds_sap = 0;
233 }
234
235 /*
236 * In order to prevent promiscuous-mode processing with dsp->ds_promisc
237 * set to inaccurate values, this function sets dsp->ds_promisc with new
238 * flags. For enabling (mac_promisc_add), the flags are set prior to the
239 * actual enabling. For disabling (mac_promisc_remove), the flags are set
240 * after the actual disabling.
241 */
242 int
243 dls_promisc(dld_str_t *dsp, uint32_t new_flags)
244 {
245 int err = 0;
246 uint32_t old_flags = dsp->ds_promisc;
247
248 ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
249 ASSERT(!(new_flags & ~(DLS_PROMISC_SAP | DLS_PROMISC_MULTI |
250 DLS_PROMISC_PHYS)));
251
252 if (dsp->ds_promisc == 0 && new_flags != 0) {
253 /*
254 * If only DLS_PROMISC_SAP, we don't turn on the
255 * physical promisc mode
256 */
257 dsp->ds_promisc = new_flags;
258 err = mac_promisc_add(dsp->ds_mch, MAC_CLIENT_PROMISC_ALL,
259 dls_rx_promisc, dsp, &dsp->ds_mph,
260 (new_flags != DLS_PROMISC_SAP) ? 0 :
261 MAC_PROMISC_FLAGS_NO_PHYS);
262 if (err != 0) {
263 dsp->ds_promisc = old_flags;
264 return (err);
265 }
266
267 /* Remove vlan promisc handle to avoid sending dup copy up */
268 if (dsp->ds_vlan_mph != NULL) {
269 mac_promisc_remove(dsp->ds_vlan_mph);
270 dsp->ds_vlan_mph = NULL;
271 }
272 } else if (dsp->ds_promisc != 0 && new_flags == 0) {
273 ASSERT(dsp->ds_mph != NULL);
274
275 mac_promisc_remove(dsp->ds_mph);
276 dsp->ds_promisc = new_flags;
277 dsp->ds_mph = NULL;
278
279 if (dsp->ds_sap == ETHERTYPE_VLAN &&
280 dsp->ds_dlstate != DL_UNBOUND) {
281 if (dsp->ds_vlan_mph != NULL)
282 return (EINVAL);
283 err = mac_promisc_add(dsp->ds_mch,
284 MAC_CLIENT_PROMISC_ALL, dls_rx_vlan_promisc, dsp,
285 &dsp->ds_vlan_mph, MAC_PROMISC_FLAGS_NO_PHYS);
286 }
287 } else if (dsp->ds_promisc == DLS_PROMISC_SAP && new_flags != 0 &&
288 new_flags != dsp->ds_promisc) {
289 /*
290 * If the old flag is PROMISC_SAP, but the current flag has
291 * changed to some new non-zero value, we need to turn the
292 * physical promiscuous mode.
293 */
294 ASSERT(dsp->ds_mph != NULL);
295 mac_promisc_remove(dsp->ds_mph);
296 /* Honors both after-remove and before-add semantics! */
297 dsp->ds_promisc = new_flags;
298 err = mac_promisc_add(dsp->ds_mch, MAC_CLIENT_PROMISC_ALL,
299 dls_rx_promisc, dsp, &dsp->ds_mph, 0);
300 if (err != 0)
301 dsp->ds_promisc = old_flags;
302 } else {
303 /* No adding or removing, but record the new flags anyway. */
304 dsp->ds_promisc = new_flags;
305 }
306
307 return (err);
308 }
309
310 int
311 dls_multicst_add(dld_str_t *dsp, const uint8_t *addr)
312 {
313 int err;
314 dls_multicst_addr_t **pp;
315 dls_multicst_addr_t *p;
316 uint_t addr_length;
317
318 ASSERT(MAC_PERIM_HELD(dsp->ds_mh));
319
320 /*
321 * Check whether the address is in the list of enabled addresses for
322 * this dld_str_t.
323 */
324 addr_length = dsp->ds_mip->mi_addr_length;
|