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.
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.
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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * DL_IPV6 MAC Type plugin for the Nemo mac module
30 #include <sys/types.h>
31 #include <sys/modctl.h>
34 #include <sys/mac_ipv6.h>
35 #include <sys/mac_ipv4_impl.h>
36 #include <sys/byteorder.h>
37 #include <sys/strsun.h>
38 #include <netinet/ip6.h>
39 #include <inet/common.h>
40 #include <inet/mib2.h>
43 #include <inet/iptun.h>
45 static struct modlmisc mac_ipv6_modlmisc
= {
47 "IPv6 tunneling MAC plugin"
50 static struct modlinkage mac_ipv6_modlinkage
= {
56 static mactype_ops_t mac_ipv6_type_ops
;
61 mactype_register_t
*mtrp
;
64 if ((mtrp
= mactype_alloc(MACTYPE_VERSION
)) == NULL
)
66 mtrp
->mtr_ident
= MAC_PLUGIN_IDENT_IPV6
;
67 mtrp
->mtr_ops
= &mac_ipv6_type_ops
;
68 mtrp
->mtr_mactype
= DL_IPV6
;
69 mtrp
->mtr_nativetype
= DL_IPV6
;
70 mtrp
->mtr_addrlen
= sizeof (in6_addr_t
);
71 if ((err
= mactype_register(mtrp
)) == 0) {
72 if ((err
= mod_install(&mac_ipv6_modlinkage
)) != 0)
73 (void) mactype_unregister(MAC_PLUGIN_IDENT_IPV6
);
83 if ((err
= mactype_unregister(MAC_PLUGIN_IDENT_IPV6
)) != 0)
85 return (mod_remove(&mac_ipv6_modlinkage
));
89 _info(struct modinfo
*modinfop
)
91 return (mod_info(&mac_ipv6_modlinkage
, modinfop
));
96 * MAC Type plugin operations
101 mac_ipv6_unicst_verify(const void *addr
, void *pdata
)
103 const in6_addr_t
*in6addr
= addr
;
104 if (IN6_IS_ADDR_UNSPECIFIED(in6addr
) ||
105 IN6_IS_ADDR_LOOPBACK(in6addr
) ||
106 IN6_IS_ADDR_MULTICAST(in6addr
) ||
107 IN6_IS_ADDR_V4MAPPED(in6addr
) ||
108 IN6_IS_ADDR_V4COMPAT(in6addr
)) {
115 * Build an IPv6 link-layer header for tunneling. If provided, the
116 * template header provided by the driver supplies the traffic class, flow
117 * label, hop limit, and potential options. The template's payload length
118 * must either be 0 if there are no extension headers, or reflect the size
119 * of the extension headers if present. The template's next header value
120 * must either be IPPROTO_NONE if no extension headers are present, or
121 * reflect the type of extension header that follows (the same is true for
122 * the field values of the extension headers themselves.)
126 mac_ipv6_header(const void *saddr
, const void *daddr
, uint32_t sap
, void *pdata
,
127 mblk_t
*payload
, size_t extra_len
)
130 ip6_t
*tmpl_ip6hp
= pdata
;
132 size_t hdr_len
= sizeof (ip6_t
);
135 if (!mac_ipv4_sap_verify(sap
, NULL
, NULL
))
138 if (tmpl_ip6hp
!= NULL
)
139 hdr_len
= sizeof (ip6_t
) + tmpl_ip6hp
->ip6_plen
;
141 if ((mp
= allocb(hdr_len
+ extra_len
, BPRI_HI
)) == NULL
)
144 ip6hp
= (ip6_t
*)mp
->b_rptr
;
146 bzero(ip6hp
, hdr_len
+ extra_len
);
147 if (tmpl_ip6hp
!= NULL
) {
148 bcopy(tmpl_ip6hp
, ip6hp
, hdr_len
);
150 ip6hp
->ip6_nxt
= IPPROTO_NONE
;
151 ip6hp
->ip6_hlim
= IPTUN_DEFAULT_HOPLIMIT
;
154 ip6hp
->ip6_vcf
= IPV6_DEFAULT_VERS_AND_FLOW
;
157 nxt_proto
= &ip6hp
->ip6_nxt
;
158 if (*nxt_proto
!= IPPROTO_NONE
) {
159 ip6_dest_t
*hdrptr
= (ip6_dest_t
*)(ip6hp
+ 1);
160 nxt_proto
= &hdrptr
->ip6d_nxt
;
161 while (*nxt_proto
!= IPPROTO_NONE
) {
162 hdrptr
= (ip6_dest_t
*)((uint8_t *)hdrptr
+
163 (8 * (hdrptr
->ip6d_len
+ 1)));
164 nxt_proto
= &hdrptr
->ip6d_nxt
;
167 *nxt_proto
= (uint8_t)sap
;
168 bcopy(saddr
, &(ip6hp
->ip6_src
), sizeof (in6_addr_t
));
169 bcopy(daddr
, &(ip6hp
->ip6_dst
), sizeof (in6_addr_t
));
171 mp
->b_wptr
+= hdr_len
;
177 mac_ipv6_header_info(mblk_t
*mp
, void *pdata
, mac_header_info_t
*hdr_info
)
180 uint8_t *whereptr
, *endptr
;
183 if (MBLKL(mp
) < sizeof (ip6_t
))
186 ip6hp
= (ip6_t
*)mp
->b_rptr
;
189 * IPv6 tunnels don't have a concept of link-layer multicast since
190 * they have fixed unicast endpoints.
192 if (mac_ipv6_unicst_verify(&ip6hp
->ip6_dst
, NULL
) != 0)
195 nexthdr
= ip6hp
->ip6_nxt
;
196 whereptr
= (uint8_t *)(ip6hp
+ 1);
198 while (nexthdr
!= IPPROTO_ENCAP
&& nexthdr
!= IPPROTO_IPV6
) {
199 ip6_dest_t
*exthdrptr
= (ip6_dest_t
*)whereptr
;
201 if (whereptr
+ sizeof (ip6_dest_t
) >= endptr
)
204 nexthdr
= exthdrptr
->ip6d_nxt
;
205 whereptr
+= 8 * (exthdrptr
->ip6d_len
+ 1);
207 if (whereptr
> endptr
)
211 hdr_info
->mhi_hdrsize
= whereptr
- mp
->b_rptr
;
212 hdr_info
->mhi_pktsize
= 0;
213 hdr_info
->mhi_daddr
= (const uint8_t *)&(ip6hp
->ip6_dst
);
214 hdr_info
->mhi_saddr
= (const uint8_t *)&(ip6hp
->ip6_src
);
215 hdr_info
->mhi_bindsap
= hdr_info
->mhi_origsap
= nexthdr
;
216 hdr_info
->mhi_dsttype
= MAC_ADDRTYPE_UNICAST
;
221 * This plugin's MAC plugin data is a template IPv6 header followed by
222 * optional extension headers. The chain of headers must be terminated by
223 * a header with a next header value of IPPROTO_NONE. The payload length
224 * of the IPv6 header must be 0 if there are no extension headers, or must
225 * reflect the total size of extension headers present.
228 mac_ipv6_pdata_verify(void *pdata
, size_t pdata_size
)
230 ip6_t
*ip6hp
= pdata
;
231 uint8_t *whereptr
, *endptr
;
235 * Since the plugin does not require plugin data, it is acceptable
236 * for drivers to pass in NULL plugin data as long as the plugin
237 * data size is consistent.
240 return (pdata_size
== 0);
242 /* First verify that we have enough data to hold an IPv6 header. */
243 if (pdata_size
< sizeof (ip6_t
))
245 /* Make sure that pdata_size is consistent with the payload length. */
246 if (pdata_size
!= sizeof (ip6_t
) + ip6hp
->ip6_plen
)
250 * Make sure that the header chain is terminated by a header with a
251 * next header value of IPPROTO_NONE.
253 nexthdr
= ip6hp
->ip6_nxt
;
254 if (nexthdr
== IPPROTO_NONE
)
255 return (ip6hp
->ip6_plen
== 0);
256 whereptr
= (uint8_t *)(ip6hp
+ 1);
257 endptr
= (uint8_t *)pdata
+ pdata_size
;
259 while (nexthdr
!= IPPROTO_NONE
&& whereptr
< endptr
) {
260 ip6_dest_t
*hdrptr
= (ip6_dest_t
*)whereptr
;
262 /* make sure we're pointing at a complete header */
263 if (whereptr
+ sizeof (ip6_dest_t
) > endptr
)
265 nexthdr
= hdrptr
->ip6d_nxt
;
266 whereptr
+= 8 * (hdrptr
->ip6d_len
+ 1);
269 return (nexthdr
== IPPROTO_NONE
&& whereptr
== endptr
);
272 static mactype_ops_t mac_ipv6_type_ops
= {
274 mac_ipv6_unicst_verify
,
275 mac_ipv4_multicst_verify
, /* neither plugin supports multicast */
276 mac_ipv4_sap_verify
, /* same set of legal SAP values */
278 mac_ipv6_header_info
,
279 mac_ipv6_pdata_verify
,