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_IPV4 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_ipv4.h>
35 #include <sys/byteorder.h>
36 #include <sys/strsun.h>
37 #include <netinet/in.h>
38 #include <netinet/ip.h>
39 #include <inet/common.h>
40 #include <inet/ip.h>
41 #include <inet/iptun.h>
42 
43 static struct modlmisc mac_ipv4_modlmisc = {
44 	&mod_miscops,
45 	"IPv4 tunneling MAC plugin"
46 };
47 
48 static struct modlinkage mac_ipv4_modlinkage = {
49 	MODREV_1,
50 	&mac_ipv4_modlmisc,
51 	NULL
52 };
53 
54 static mactype_ops_t mac_ipv4_type_ops;
55 
56 int
_init(void)57 _init(void)
58 {
59 	mactype_register_t *mtrp;
60 	int	err;
61 
62 	if ((mtrp = mactype_alloc(MACTYPE_VERSION)) == NULL)
63 		return (ENOTSUP);
64 	mtrp->mtr_ident = MAC_PLUGIN_IDENT_IPV4;
65 	mtrp->mtr_ops = &mac_ipv4_type_ops;
66 	mtrp->mtr_mactype = DL_IPV4;
67 	mtrp->mtr_nativetype = DL_IPV4;
68 	mtrp->mtr_addrlen = sizeof (ipaddr_t);
69 	if ((err = mactype_register(mtrp)) == 0) {
70 		if ((err = mod_install(&mac_ipv4_modlinkage)) != 0)
71 			(void) mactype_unregister(MAC_PLUGIN_IDENT_IPV4);
72 	}
73 	mactype_free(mtrp);
74 	return (err);
75 }
76 
77 int
_fini(void)78 _fini(void)
79 {
80 	int	err;
81 	if ((err = mactype_unregister(MAC_PLUGIN_IDENT_IPV4)) != 0)
82 		return (err);
83 	return (mod_remove(&mac_ipv4_modlinkage));
84 }
85 
86 int
_info(struct modinfo * modinfop)87 _info(struct modinfo *modinfop)
88 {
89 	return (mod_info(&mac_ipv4_modlinkage, modinfop));
90 }
91 
92 /*
93  * MAC Type plugin operations
94  */
95 
96 /* ARGSUSED */
97 int
mac_ipv4_unicst_verify(const void * addr,void * pdata)98 mac_ipv4_unicst_verify(const void *addr, void *pdata)
99 {
100 	const ipaddr_t *ipaddr = addr;
101 	return ((CLASSD(*ipaddr) || (*ipaddr == INADDR_BROADCAST)) ?
102 	    EINVAL : 0);
103 }
104 
105 /* ARGSUSED */
106 int
mac_ipv4_multicst_verify(const void * addr,void * pdata)107 mac_ipv4_multicst_verify(const void *addr, void *pdata)
108 {
109 	/*
110 	 * IPv4 configured tunnels do not have the concept of link-layer
111 	 * multicast.
112 	 */
113 	return (ENOTSUP);
114 }
115 
116 /*
117  * Check the legality of an IPv4 tunnel SAP value.  The only two acceptable
118  * values are IPPROTO_ENCAP (IPv4 in IPv4) and IPPROTO_IPV6 (IPv6 in IPv4).
119  */
120 /* ARGSUSED */
121 boolean_t
mac_ipv4_sap_verify(uint32_t sap,uint32_t * bind_sap,void * pdata)122 mac_ipv4_sap_verify(uint32_t sap, uint32_t *bind_sap, void *pdata)
123 {
124 	if (sap == IPPROTO_ENCAP || sap == IPPROTO_IPV6 || sap == 0) {
125 		if (bind_sap != NULL)
126 			*bind_sap = sap;
127 		return (B_TRUE);
128 	}
129 	return (B_FALSE);
130 }
131 
132 /*
133  * Build an IPv4 link-layer header for tunneling.  If provided, the
134  * template header provided by the driver supplies the header length, type
135  * of service, don't fragment flag, ttl, and potential options (depending
136  * on the header length).
137  */
138 /* ARGSUSED */
139 mblk_t *
mac_ipv4_header(const void * saddr,const void * daddr,uint32_t sap,void * pdata,mblk_t * payload,size_t extra_len)140 mac_ipv4_header(const void *saddr, const void *daddr, uint32_t sap, void *pdata,
141     mblk_t *payload, size_t extra_len)
142 {
143 	struct ip	*iphp;
144 	struct ip	*tmpl_iphp = pdata;
145 	mblk_t		*mp;
146 	size_t		hdr_len = sizeof (struct ip);
147 
148 	if (!mac_ipv4_sap_verify(sap, NULL, NULL))
149 		return (NULL);
150 
151 	if (tmpl_iphp != NULL)
152 		hdr_len = tmpl_iphp->ip_hl * sizeof (uint32_t);
153 
154 	if ((mp = allocb(hdr_len + extra_len, BPRI_HI)) == NULL)
155 		return (NULL);
156 
157 	iphp = (struct ip *)mp->b_rptr;
158 
159 	bzero(iphp, hdr_len + extra_len);
160 	if (tmpl_iphp != NULL) {
161 		bcopy(tmpl_iphp, iphp, hdr_len);
162 	} else {
163 		iphp->ip_hl = IP_SIMPLE_HDR_LENGTH_IN_WORDS;
164 		iphp->ip_off = htons(IP_DF);
165 		iphp->ip_ttl = IPTUN_DEFAULT_HOPLIMIT;
166 	}
167 
168 	iphp->ip_v = IPVERSION;
169 	iphp->ip_len = 0;
170 	iphp->ip_p = (uint8_t)sap;
171 	bcopy(saddr, &(iphp->ip_src), sizeof (struct in_addr));
172 	bcopy(daddr, &(iphp->ip_dst), sizeof (struct in_addr));
173 
174 	mp->b_wptr += hdr_len;
175 	return (mp);
176 }
177 
178 /* ARGSUSED */
179 int
mac_ipv4_header_info(mblk_t * mp,void * pdata,mac_header_info_t * hdr_info)180 mac_ipv4_header_info(mblk_t *mp, void *pdata, mac_header_info_t *hdr_info)
181 {
182 	struct ip	*iphp;
183 
184 	if (MBLKL(mp) < sizeof (struct ip))
185 		return (EINVAL);
186 
187 	iphp = (struct ip *)mp->b_rptr;
188 
189 	/*
190 	 * IPv4 tunnels don't have a concept of link-layer multicast since
191 	 * they have fixed unicast endpoints.
192 	 */
193 	if (mac_ipv4_unicst_verify(&iphp->ip_dst, NULL) != 0)
194 		return (EINVAL);
195 
196 	hdr_info->mhi_hdrsize = iphp->ip_hl * sizeof (uint32_t);
197 	hdr_info->mhi_pktsize = 0;
198 	hdr_info->mhi_daddr = (const uint8_t *)&(iphp->ip_dst);
199 	hdr_info->mhi_saddr = (const uint8_t *)&(iphp->ip_src);
200 	hdr_info->mhi_origsap = hdr_info->mhi_bindsap = iphp->ip_p;
201 	hdr_info->mhi_dsttype = MAC_ADDRTYPE_UNICAST;
202 	return (0);
203 }
204 
205 /*
206  * Plugin data is either NULL or a pointer to an IPv4 header.
207  */
208 boolean_t
mac_ipv4_pdata_verify(void * pdata,size_t pdata_size)209 mac_ipv4_pdata_verify(void *pdata, size_t pdata_size)
210 {
211 	const struct ip	*iphp = pdata;
212 
213 	if (pdata == NULL)
214 		return (pdata_size == 0);
215 	if (pdata_size < sizeof (struct ip))
216 		return (B_FALSE);
217 	/* Make sure that the header length field matches pdata_size */
218 	return (pdata_size == iphp->ip_hl * sizeof (uint32_t));
219 }
220 
221 static mactype_ops_t	mac_ipv4_type_ops = {
222 	MTOPS_PDATA_VERIFY,
223 	mac_ipv4_unicst_verify,
224 	mac_ipv4_multicst_verify,
225 	mac_ipv4_sap_verify,
226 	mac_ipv4_header,
227 	mac_ipv4_header_info,
228 	mac_ipv4_pdata_verify,
229 	NULL,
230 	NULL,
231 	NULL
232 };
233