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 /*
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 #include <sys/types.h>
30 #include <sys/ethernet.h>
31 #include <sys/vnet_common.h>
32 #include <sys/vlan.h>
33 #include <sys/stream.h>
34 #include <sys/strsun.h>
35 #include <sys/byteorder.h>
36
37 /* convert mac address from string to uint64_t */
38 uint64_t
vnet_macaddr_strtoul(const uint8_t * macaddr)39 vnet_macaddr_strtoul(const uint8_t *macaddr)
40 {
41 uint64_t val = 0;
42 int i;
43
44 for (i = 0; i < ETHERADDRL; i++) {
45 val <<= 8;
46 val |= macaddr[i];
47 }
48
49 return (val);
50 }
51
52 /* convert mac address from uint64_t to string */
53 void
vnet_macaddr_ultostr(uint64_t val,uint8_t * macaddr)54 vnet_macaddr_ultostr(uint64_t val, uint8_t *macaddr)
55 {
56 int i;
57 uint64_t value;
58
59 value = val;
60 for (i = ETHERADDRL - 1; i >= 0; i--) {
61 macaddr[i] = value & 0xFF;
62 value >>= 8;
63 }
64 }
65
66 mblk_t *
vnet_vlan_insert_tag(mblk_t * mp,uint16_t vid)67 vnet_vlan_insert_tag(mblk_t *mp, uint16_t vid)
68 {
69 struct ether_vlan_header *evhp;
70 mblk_t *nmp;
71 size_t n;
72 uint_t pri = 0;
73
74 if (DB_REF(mp) == 1 && MBLKHEAD(mp) >= VLAN_TAGSZ) {
75
76 /* mblk has space to insert tag */
77
78 /*
79 * move src and dst mac addrs in the header back by VLAN_TAGSZ.
80 */
81 ovbcopy(mp->b_rptr, mp->b_rptr - VLAN_TAGSZ, 2 * ETHERADDRL);
82 mp->b_rptr -= VLAN_TAGSZ;
83
84 /* now insert tpid and tci */
85 evhp = (struct ether_vlan_header *)mp->b_rptr;
86 evhp->ether_tpid = htons(ETHERTYPE_VLAN);
87 evhp->ether_tci = htons(VLAN_TCI(pri, ETHER_CFI, vid));
88
89 } else { /* no space in the mblk for tag */
90
91 /*
92 * allocate a mblk to create a new frame hdr with the tag
93 */
94 nmp = allocb(sizeof (struct ether_vlan_header),
95 BPRI_MED);
96 if (nmp == NULL) {
97 freemsg(mp);
98 return (NULL);
99 }
100
101 /*
102 * copy the src and dst mac addrs in the header to the new mblk
103 */
104 n = 2 * ETHERADDRL;
105 bcopy(mp->b_rptr, nmp->b_rptr, n);
106
107 /* initialize the vlan tag in the new mblk */
108 evhp = (struct ether_vlan_header *)nmp->b_rptr;
109 evhp->ether_tpid = htons(ETHERTYPE_VLAN);
110 evhp->ether_tci = htons(VLAN_TCI(pri, ETHER_CFI, vid));
111
112 /* copy ethertype to new mblk */
113 bcopy(mp->b_rptr + n, nmp->b_rptr + n + VLAN_TAGSZ,
114 sizeof (evhp->ether_type));
115
116 /* skip over the header in the original mblk */
117 mp->b_rptr += sizeof (struct ether_header);
118
119 /* fix the end of frame header in the new mblk */
120 nmp->b_wptr += sizeof (struct ether_vlan_header);
121
122 /*
123 * now link the new mblk which contains just the frame
124 * header with the original mblk which contains rest of
125 * the frame.
126 */
127 nmp->b_cont = mp;
128 mp = nmp;
129
130 }
131
132 return (mp);
133 }
134
135 mblk_t *
vnet_vlan_remove_tag(mblk_t * mp)136 vnet_vlan_remove_tag(mblk_t *mp)
137 {
138 size_t n;
139 mblk_t *nmp;
140
141 if (DB_REF(mp) == 1) { /* mblk can be modified to untag(not shared) */
142
143 /* move src & dst addrs in the header forward by VLAN_TAGSZ */
144 ovbcopy(mp->b_rptr, mp->b_rptr + VLAN_TAGSZ, 2 * ETHERADDRL);
145 mp->b_rptr += VLAN_TAGSZ;
146
147 } else {
148
149 /* allocate a new header */
150 nmp = allocb(sizeof (struct ether_header), BPRI_MED);
151 if (nmp == NULL) {
152 freemsg(mp);
153 return (NULL);
154 }
155
156 /*
157 * copy the src and dst mac addrs in the header to the new mblk
158 */
159 n = 2 * ETHERADDRL;
160 bcopy(mp->b_rptr, nmp->b_rptr, n);
161
162 /* skip over vlan tag and copy ethertype to new mblk */
163 bcopy(mp->b_rptr + n + VLAN_TAGSZ, nmp->b_rptr + n,
164 sizeof (uint16_t));
165
166 /* skip over the header in the original mblk */
167 mp->b_rptr += sizeof (struct ether_vlan_header);
168
169 /* fix the end of frame header in the new mblk */
170 nmp->b_wptr += sizeof (struct ether_header);
171
172 /*
173 * now link the new mblk which contains the frame header
174 * without vlan tag and the original mblk which contains rest
175 * of the frame.
176 */
177 nmp->b_cont = mp;
178 mp = nmp;
179
180 }
181
182 return (mp);
183 }
184
185 int
vnet_dring_entry_copy(vnet_public_desc_t * from,vnet_public_desc_t * to,uint8_t mtype,ldc_dring_handle_t handle,uint64_t start,uint64_t stop)186 vnet_dring_entry_copy(vnet_public_desc_t *from, vnet_public_desc_t *to,
187 uint8_t mtype, ldc_dring_handle_t handle, uint64_t start, uint64_t stop)
188 {
189 int rv;
190 on_trap_data_t otd;
191
192 if ((rv = VIO_DRING_ACQUIRE(&otd, mtype, handle, start, stop)) != 0)
193 return (rv);
194
195 *to = *from;
196
197 rv = VIO_DRING_RELEASE_NOCOPYOUT(mtype);
198
199 return (rv);
200 }
201
202 int
vnet_dring_entry_set_dstate(vnet_public_desc_t * descp,uint8_t mtype,ldc_dring_handle_t handle,uint64_t start,uint64_t stop,uint8_t dstate)203 vnet_dring_entry_set_dstate(vnet_public_desc_t *descp, uint8_t mtype,
204 ldc_dring_handle_t handle, uint64_t start, uint64_t stop, uint8_t dstate)
205 {
206 int rv;
207 on_trap_data_t otd;
208
209 rv = VIO_DRING_ACQUIRE_NOCOPYIN(&otd, mtype);
210 if (rv)
211 return (rv);
212
213 descp->hdr.dstate = dstate;
214
215 rv = VIO_DRING_RELEASE(mtype, handle, start, stop);
216
217 return (rv);
218 }
219