xref: /titanic_50/usr/src/uts/sun4v/io/vnet_common.c (revision 356f72340a69936724c69f2f87fffa6f5887f885)
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
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
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 *
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 *
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
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
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