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 /* 27 * DL_IPV6 MAC Type plugin for the Nemo mac module 28 */ 29 30 #include <sys/types.h> 31 #include <sys/modctl.h> 32 #include <sys/dlpi.h> 33 #include <sys/mac.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> 41 #include <inet/ip.h> 42 #include <inet/ip6.h> 43 #include <inet/iptun.h> 44 45 static struct modlmisc mac_ipv6_modlmisc = { 46 &mod_miscops, 47 "IPv6 tunneling MAC plugin" 48 }; 49 50 static struct modlinkage mac_ipv6_modlinkage = { 51 MODREV_1, 52 { &mac_ipv6_modlmisc, 53 NULL } 54 }; 55 56 static mactype_ops_t mac_ipv6_type_ops; 57 58 int 59 _init(void) 60 { 61 mactype_register_t *mtrp; 62 int err; 63 64 if ((mtrp = mactype_alloc(MACTYPE_VERSION)) == NULL) 65 return (EINVAL); 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); 74 } 75 mactype_free(mtrp); 76 return (err); 77 } 78 79 int 80 _fini(void) 81 { 82 int err; 83 if ((err = mactype_unregister(MAC_PLUGIN_IDENT_IPV6)) != 0) 84 return (err); 85 return (mod_remove(&mac_ipv6_modlinkage)); 86 } 87 88 int 89 _info(struct modinfo *modinfop) 90 { 91 return (mod_info(&mac_ipv6_modlinkage, modinfop)); 92 } 93 94 95 /* 96 * MAC Type plugin operations 97 */ 98 99 /* ARGSUSED */ 100 int 101 mac_ipv6_unicst_verify(const void *addr, void *pdata) 102 { 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)) { 109 return (EINVAL); 110 } 111 return (0); 112 } 113 114 /* 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.) 123 */ 124 /* ARGSUSED */ 125 mblk_t * 126 mac_ipv6_header(const void *saddr, const void *daddr, uint32_t sap, void *pdata, 127 mblk_t *payload, size_t extra_len) 128 { 129 ip6_t *ip6hp; 130 ip6_t *tmpl_ip6hp = pdata; 131 mblk_t *mp; 132 size_t hdr_len = sizeof (ip6_t); 133 uint8_t *nxt_proto; 134 135 if (!mac_ipv4_sap_verify(sap, NULL, NULL)) 136 return (NULL); 137 138 if (tmpl_ip6hp != NULL) 139 hdr_len = sizeof (ip6_t) + tmpl_ip6hp->ip6_plen; 140 141 if ((mp = allocb(hdr_len + extra_len, BPRI_HI)) == NULL) 142 return (NULL); 143 144 ip6hp = (ip6_t *)mp->b_rptr; 145 146 bzero(ip6hp, hdr_len + extra_len); 147 if (tmpl_ip6hp != NULL) { 148 bcopy(tmpl_ip6hp, ip6hp, hdr_len); 149 } else { 150 ip6hp->ip6_nxt = IPPROTO_NONE; 151 ip6hp->ip6_hlim = IPTUN_DEFAULT_HOPLIMIT; 152 } 153 154 ip6hp->ip6_vcf = IPV6_DEFAULT_VERS_AND_FLOW; 155 ip6hp->ip6_plen = 0; 156 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; 165 } 166 } 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)); 170 171 mp->b_wptr += hdr_len; 172 return (mp); 173 } 174 175 /* ARGSUSED */ 176 int 177 mac_ipv6_header_info(mblk_t *mp, void *pdata, mac_header_info_t *hdr_info) 178 { 179 ip6_t *ip6hp; 180 uint8_t *whereptr, *endptr; 181 uint8_t nexthdr; 182 183 if (MBLKL(mp) < sizeof (ip6_t)) 184 return (EINVAL); 185 186 ip6hp = (ip6_t *)mp->b_rptr; 187 188 /* 189 * IPv6 tunnels don't have a concept of link-layer multicast since 190 * they have fixed unicast endpoints. 191 */ 192 if (mac_ipv6_unicst_verify(&ip6hp->ip6_dst, NULL) != 0) 193 return (EINVAL); 194 195 nexthdr = ip6hp->ip6_nxt; 196 whereptr = (uint8_t *)(ip6hp + 1); 197 endptr = mp->b_wptr; 198 while (nexthdr != IPPROTO_ENCAP && nexthdr != IPPROTO_IPV6) { 199 ip6_dest_t *exthdrptr = (ip6_dest_t *)whereptr; 200 201 if (whereptr + sizeof (ip6_dest_t) >= endptr) 202 return (EINVAL); 203 204 nexthdr = exthdrptr->ip6d_nxt; 205 whereptr += 8 * (exthdrptr->ip6d_len + 1); 206 207 if (whereptr > endptr) 208 return (EINVAL); 209 } 210 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; 217 return (0); 218 } 219 220 /* 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. 226 */ 227 boolean_t 228 mac_ipv6_pdata_verify(void *pdata, size_t pdata_size) 229 { 230 ip6_t *ip6hp = pdata; 231 uint8_t *whereptr, *endptr; 232 uint8_t nexthdr; 233 234 /* 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. 238 */ 239 if (pdata == NULL) 240 return (pdata_size == 0); 241 242 /* First verify that we have enough data to hold an IPv6 header. */ 243 if (pdata_size < sizeof (ip6_t)) 244 return (B_FALSE); 245 /* Make sure that pdata_size is consistent with the payload length. */ 246 if (pdata_size != sizeof (ip6_t) + ip6hp->ip6_plen) 247 return (B_FALSE); 248 249 /* 250 * Make sure that the header chain is terminated by a header with a 251 * next header value of IPPROTO_NONE. 252 */ 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; 258 259 while (nexthdr != IPPROTO_NONE && whereptr < endptr) { 260 ip6_dest_t *hdrptr = (ip6_dest_t *)whereptr; 261 262 /* make sure we're pointing at a complete header */ 263 if (whereptr + sizeof (ip6_dest_t) > endptr) 264 break; 265 nexthdr = hdrptr->ip6d_nxt; 266 whereptr += 8 * (hdrptr->ip6d_len + 1); 267 } 268 269 return (nexthdr == IPPROTO_NONE && whereptr == endptr); 270 } 271 272 static mactype_ops_t mac_ipv6_type_ops = { 273 MTOPS_PDATA_VERIFY, 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 */ 277 mac_ipv6_header, 278 mac_ipv6_header_info, 279 mac_ipv6_pdata_verify, 280 NULL, 281 NULL, 282 NULL 283 };