1*2b24ab6bSSebastien Roy /*
2*2b24ab6bSSebastien Roy  * CDDL HEADER START
3*2b24ab6bSSebastien Roy  *
4*2b24ab6bSSebastien Roy  * The contents of this file are subject to the terms of the
5*2b24ab6bSSebastien Roy  * Common Development and Distribution License (the "License").
6*2b24ab6bSSebastien Roy  * You may not use this file except in compliance with the License.
7*2b24ab6bSSebastien Roy  *
8*2b24ab6bSSebastien Roy  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*2b24ab6bSSebastien Roy  * or http://www.opensolaris.org/os/licensing.
10*2b24ab6bSSebastien Roy  * See the License for the specific language governing permissions
11*2b24ab6bSSebastien Roy  * and limitations under the License.
12*2b24ab6bSSebastien Roy  *
13*2b24ab6bSSebastien Roy  * When distributing Covered Code, include this CDDL HEADER in each
14*2b24ab6bSSebastien Roy  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*2b24ab6bSSebastien Roy  * If applicable, add the following below this CDDL HEADER, with the
16*2b24ab6bSSebastien Roy  * fields enclosed by brackets "[]" replaced with your own identifying
17*2b24ab6bSSebastien Roy  * information: Portions Copyright [yyyy] [name of copyright owner]
18*2b24ab6bSSebastien Roy  *
19*2b24ab6bSSebastien Roy  * CDDL HEADER END
20*2b24ab6bSSebastien Roy  */
21*2b24ab6bSSebastien Roy /*
22*2b24ab6bSSebastien Roy  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23*2b24ab6bSSebastien Roy  * Use is subject to license terms.
24*2b24ab6bSSebastien Roy  */
25*2b24ab6bSSebastien Roy 
26*2b24ab6bSSebastien Roy /*
27*2b24ab6bSSebastien Roy  * DL_IPV4 MAC Type plugin for the Nemo mac module
28*2b24ab6bSSebastien Roy  */
29*2b24ab6bSSebastien Roy 
30*2b24ab6bSSebastien Roy #include <sys/types.h>
31*2b24ab6bSSebastien Roy #include <sys/modctl.h>
32*2b24ab6bSSebastien Roy #include <sys/dlpi.h>
33*2b24ab6bSSebastien Roy #include <sys/mac.h>
34*2b24ab6bSSebastien Roy #include <sys/mac_ipv4.h>
35*2b24ab6bSSebastien Roy #include <sys/byteorder.h>
36*2b24ab6bSSebastien Roy #include <sys/strsun.h>
37*2b24ab6bSSebastien Roy #include <netinet/in.h>
38*2b24ab6bSSebastien Roy #include <netinet/ip.h>
39*2b24ab6bSSebastien Roy #include <inet/common.h>
40*2b24ab6bSSebastien Roy #include <inet/ip.h>
41*2b24ab6bSSebastien Roy #include <inet/iptun.h>
42*2b24ab6bSSebastien Roy 
43*2b24ab6bSSebastien Roy static struct modlmisc mac_ipv4_modlmisc = {
44*2b24ab6bSSebastien Roy 	&mod_miscops,
45*2b24ab6bSSebastien Roy 	"IPv4 tunneling MAC plugin"
46*2b24ab6bSSebastien Roy };
47*2b24ab6bSSebastien Roy 
48*2b24ab6bSSebastien Roy static struct modlinkage mac_ipv4_modlinkage = {
49*2b24ab6bSSebastien Roy 	MODREV_1,
50*2b24ab6bSSebastien Roy 	&mac_ipv4_modlmisc,
51*2b24ab6bSSebastien Roy 	NULL
52*2b24ab6bSSebastien Roy };
53*2b24ab6bSSebastien Roy 
54*2b24ab6bSSebastien Roy static mactype_ops_t mac_ipv4_type_ops;
55*2b24ab6bSSebastien Roy 
56*2b24ab6bSSebastien Roy int
_init(void)57*2b24ab6bSSebastien Roy _init(void)
58*2b24ab6bSSebastien Roy {
59*2b24ab6bSSebastien Roy 	mactype_register_t *mtrp;
60*2b24ab6bSSebastien Roy 	int	err;
61*2b24ab6bSSebastien Roy 
62*2b24ab6bSSebastien Roy 	if ((mtrp = mactype_alloc(MACTYPE_VERSION)) == NULL)
63*2b24ab6bSSebastien Roy 		return (ENOTSUP);
64*2b24ab6bSSebastien Roy 	mtrp->mtr_ident = MAC_PLUGIN_IDENT_IPV4;
65*2b24ab6bSSebastien Roy 	mtrp->mtr_ops = &mac_ipv4_type_ops;
66*2b24ab6bSSebastien Roy 	mtrp->mtr_mactype = DL_IPV4;
67*2b24ab6bSSebastien Roy 	mtrp->mtr_nativetype = DL_IPV4;
68*2b24ab6bSSebastien Roy 	mtrp->mtr_addrlen = sizeof (ipaddr_t);
69*2b24ab6bSSebastien Roy 	if ((err = mactype_register(mtrp)) == 0) {
70*2b24ab6bSSebastien Roy 		if ((err = mod_install(&mac_ipv4_modlinkage)) != 0)
71*2b24ab6bSSebastien Roy 			(void) mactype_unregister(MAC_PLUGIN_IDENT_IPV4);
72*2b24ab6bSSebastien Roy 	}
73*2b24ab6bSSebastien Roy 	mactype_free(mtrp);
74*2b24ab6bSSebastien Roy 	return (err);
75*2b24ab6bSSebastien Roy }
76*2b24ab6bSSebastien Roy 
77*2b24ab6bSSebastien Roy int
_fini(void)78*2b24ab6bSSebastien Roy _fini(void)
79*2b24ab6bSSebastien Roy {
80*2b24ab6bSSebastien Roy 	int	err;
81*2b24ab6bSSebastien Roy 	if ((err = mactype_unregister(MAC_PLUGIN_IDENT_IPV4)) != 0)
82*2b24ab6bSSebastien Roy 		return (err);
83*2b24ab6bSSebastien Roy 	return (mod_remove(&mac_ipv4_modlinkage));
84*2b24ab6bSSebastien Roy }
85*2b24ab6bSSebastien Roy 
86*2b24ab6bSSebastien Roy int
_info(struct modinfo * modinfop)87*2b24ab6bSSebastien Roy _info(struct modinfo *modinfop)
88*2b24ab6bSSebastien Roy {
89*2b24ab6bSSebastien Roy 	return (mod_info(&mac_ipv4_modlinkage, modinfop));
90*2b24ab6bSSebastien Roy }
91*2b24ab6bSSebastien Roy 
92*2b24ab6bSSebastien Roy /*
93*2b24ab6bSSebastien Roy  * MAC Type plugin operations
94*2b24ab6bSSebastien Roy  */
95*2b24ab6bSSebastien Roy 
96*2b24ab6bSSebastien Roy /* ARGSUSED */
97*2b24ab6bSSebastien Roy int
mac_ipv4_unicst_verify(const void * addr,void * pdata)98*2b24ab6bSSebastien Roy mac_ipv4_unicst_verify(const void *addr, void *pdata)
99*2b24ab6bSSebastien Roy {
100*2b24ab6bSSebastien Roy 	const ipaddr_t *ipaddr = addr;
101*2b24ab6bSSebastien Roy 	return ((CLASSD(*ipaddr) || (*ipaddr == INADDR_BROADCAST)) ?
102*2b24ab6bSSebastien Roy 	    EINVAL : 0);
103*2b24ab6bSSebastien Roy }
104*2b24ab6bSSebastien Roy 
105*2b24ab6bSSebastien Roy /* ARGSUSED */
106*2b24ab6bSSebastien Roy int
mac_ipv4_multicst_verify(const void * addr,void * pdata)107*2b24ab6bSSebastien Roy mac_ipv4_multicst_verify(const void *addr, void *pdata)
108*2b24ab6bSSebastien Roy {
109*2b24ab6bSSebastien Roy 	/*
110*2b24ab6bSSebastien Roy 	 * IPv4 configured tunnels do not have the concept of link-layer
111*2b24ab6bSSebastien Roy 	 * multicast.
112*2b24ab6bSSebastien Roy 	 */
113*2b24ab6bSSebastien Roy 	return (ENOTSUP);
114*2b24ab6bSSebastien Roy }
115*2b24ab6bSSebastien Roy 
116*2b24ab6bSSebastien Roy /*
117*2b24ab6bSSebastien Roy  * Check the legality of an IPv4 tunnel SAP value.  The only two acceptable
118*2b24ab6bSSebastien Roy  * values are IPPROTO_ENCAP (IPv4 in IPv4) and IPPROTO_IPV6 (IPv6 in IPv4).
119*2b24ab6bSSebastien Roy  */
120*2b24ab6bSSebastien Roy /* ARGSUSED */
121*2b24ab6bSSebastien Roy boolean_t
mac_ipv4_sap_verify(uint32_t sap,uint32_t * bind_sap,void * pdata)122*2b24ab6bSSebastien Roy mac_ipv4_sap_verify(uint32_t sap, uint32_t *bind_sap, void *pdata)
123*2b24ab6bSSebastien Roy {
124*2b24ab6bSSebastien Roy 	if (sap == IPPROTO_ENCAP || sap == IPPROTO_IPV6 || sap == 0) {
125*2b24ab6bSSebastien Roy 		if (bind_sap != NULL)
126*2b24ab6bSSebastien Roy 			*bind_sap = sap;
127*2b24ab6bSSebastien Roy 		return (B_TRUE);
128*2b24ab6bSSebastien Roy 	}
129*2b24ab6bSSebastien Roy 	return (B_FALSE);
130*2b24ab6bSSebastien Roy }
131*2b24ab6bSSebastien Roy 
132*2b24ab6bSSebastien Roy /*
133*2b24ab6bSSebastien Roy  * Build an IPv4 link-layer header for tunneling.  If provided, the
134*2b24ab6bSSebastien Roy  * template header provided by the driver supplies the header length, type
135*2b24ab6bSSebastien Roy  * of service, don't fragment flag, ttl, and potential options (depending
136*2b24ab6bSSebastien Roy  * on the header length).
137*2b24ab6bSSebastien Roy  */
138*2b24ab6bSSebastien Roy /* ARGSUSED */
139*2b24ab6bSSebastien Roy mblk_t *
mac_ipv4_header(const void * saddr,const void * daddr,uint32_t sap,void * pdata,mblk_t * payload,size_t extra_len)140*2b24ab6bSSebastien Roy mac_ipv4_header(const void *saddr, const void *daddr, uint32_t sap, void *pdata,
141*2b24ab6bSSebastien Roy     mblk_t *payload, size_t extra_len)
142*2b24ab6bSSebastien Roy {
143*2b24ab6bSSebastien Roy 	struct ip	*iphp;
144*2b24ab6bSSebastien Roy 	struct ip	*tmpl_iphp = pdata;
145*2b24ab6bSSebastien Roy 	mblk_t		*mp;
146*2b24ab6bSSebastien Roy 	size_t		hdr_len = sizeof (struct ip);
147*2b24ab6bSSebastien Roy 
148*2b24ab6bSSebastien Roy 	if (!mac_ipv4_sap_verify(sap, NULL, NULL))
149*2b24ab6bSSebastien Roy 		return (NULL);
150*2b24ab6bSSebastien Roy 
151*2b24ab6bSSebastien Roy 	if (tmpl_iphp != NULL)
152*2b24ab6bSSebastien Roy 		hdr_len = tmpl_iphp->ip_hl * sizeof (uint32_t);
153*2b24ab6bSSebastien Roy 
154*2b24ab6bSSebastien Roy 	if ((mp = allocb(hdr_len + extra_len, BPRI_HI)) == NULL)
155*2b24ab6bSSebastien Roy 		return (NULL);
156*2b24ab6bSSebastien Roy 
157*2b24ab6bSSebastien Roy 	iphp = (struct ip *)mp->b_rptr;
158*2b24ab6bSSebastien Roy 
159*2b24ab6bSSebastien Roy 	bzero(iphp, hdr_len + extra_len);
160*2b24ab6bSSebastien Roy 	if (tmpl_iphp != NULL) {
161*2b24ab6bSSebastien Roy 		bcopy(tmpl_iphp, iphp, hdr_len);
162*2b24ab6bSSebastien Roy 	} else {
163*2b24ab6bSSebastien Roy 		iphp->ip_hl = IP_SIMPLE_HDR_LENGTH_IN_WORDS;
164*2b24ab6bSSebastien Roy 		iphp->ip_off = htons(IP_DF);
165*2b24ab6bSSebastien Roy 		iphp->ip_ttl = IPTUN_DEFAULT_HOPLIMIT;
166*2b24ab6bSSebastien Roy 	}
167*2b24ab6bSSebastien Roy 
168*2b24ab6bSSebastien Roy 	iphp->ip_v = IPVERSION;
169*2b24ab6bSSebastien Roy 	iphp->ip_len = 0;
170*2b24ab6bSSebastien Roy 	iphp->ip_p = (uint8_t)sap;
171*2b24ab6bSSebastien Roy 	bcopy(saddr, &(iphp->ip_src), sizeof (struct in_addr));
172*2b24ab6bSSebastien Roy 	bcopy(daddr, &(iphp->ip_dst), sizeof (struct in_addr));
173*2b24ab6bSSebastien Roy 
174*2b24ab6bSSebastien Roy 	mp->b_wptr += hdr_len;
175*2b24ab6bSSebastien Roy 	return (mp);
176*2b24ab6bSSebastien Roy }
177*2b24ab6bSSebastien Roy 
178*2b24ab6bSSebastien Roy /* ARGSUSED */
179*2b24ab6bSSebastien Roy int
mac_ipv4_header_info(mblk_t * mp,void * pdata,mac_header_info_t * hdr_info)180*2b24ab6bSSebastien Roy mac_ipv4_header_info(mblk_t *mp, void *pdata, mac_header_info_t *hdr_info)
181*2b24ab6bSSebastien Roy {
182*2b24ab6bSSebastien Roy 	struct ip	*iphp;
183*2b24ab6bSSebastien Roy 
184*2b24ab6bSSebastien Roy 	if (MBLKL(mp) < sizeof (struct ip))
185*2b24ab6bSSebastien Roy 		return (EINVAL);
186*2b24ab6bSSebastien Roy 
187*2b24ab6bSSebastien Roy 	iphp = (struct ip *)mp->b_rptr;
188*2b24ab6bSSebastien Roy 
189*2b24ab6bSSebastien Roy 	/*
190*2b24ab6bSSebastien Roy 	 * IPv4 tunnels don't have a concept of link-layer multicast since
191*2b24ab6bSSebastien Roy 	 * they have fixed unicast endpoints.
192*2b24ab6bSSebastien Roy 	 */
193*2b24ab6bSSebastien Roy 	if (mac_ipv4_unicst_verify(&iphp->ip_dst, NULL) != 0)
194*2b24ab6bSSebastien Roy 		return (EINVAL);
195*2b24ab6bSSebastien Roy 
196*2b24ab6bSSebastien Roy 	hdr_info->mhi_hdrsize = iphp->ip_hl * sizeof (uint32_t);
197*2b24ab6bSSebastien Roy 	hdr_info->mhi_pktsize = 0;
198*2b24ab6bSSebastien Roy 	hdr_info->mhi_daddr = (const uint8_t *)&(iphp->ip_dst);
199*2b24ab6bSSebastien Roy 	hdr_info->mhi_saddr = (const uint8_t *)&(iphp->ip_src);
200*2b24ab6bSSebastien Roy 	hdr_info->mhi_origsap = hdr_info->mhi_bindsap = iphp->ip_p;
201*2b24ab6bSSebastien Roy 	hdr_info->mhi_dsttype = MAC_ADDRTYPE_UNICAST;
202*2b24ab6bSSebastien Roy 	return (0);
203*2b24ab6bSSebastien Roy }
204*2b24ab6bSSebastien Roy 
205*2b24ab6bSSebastien Roy /*
206*2b24ab6bSSebastien Roy  * Plugin data is either NULL or a pointer to an IPv4 header.
207*2b24ab6bSSebastien Roy  */
208*2b24ab6bSSebastien Roy boolean_t
mac_ipv4_pdata_verify(void * pdata,size_t pdata_size)209*2b24ab6bSSebastien Roy mac_ipv4_pdata_verify(void *pdata, size_t pdata_size)
210*2b24ab6bSSebastien Roy {
211*2b24ab6bSSebastien Roy 	const struct ip	*iphp = pdata;
212*2b24ab6bSSebastien Roy 
213*2b24ab6bSSebastien Roy 	if (pdata == NULL)
214*2b24ab6bSSebastien Roy 		return (pdata_size == 0);
215*2b24ab6bSSebastien Roy 	if (pdata_size < sizeof (struct ip))
216*2b24ab6bSSebastien Roy 		return (B_FALSE);
217*2b24ab6bSSebastien Roy 	/* Make sure that the header length field matches pdata_size */
218*2b24ab6bSSebastien Roy 	return (pdata_size == iphp->ip_hl * sizeof (uint32_t));
219*2b24ab6bSSebastien Roy }
220*2b24ab6bSSebastien Roy 
221*2b24ab6bSSebastien Roy static mactype_ops_t	mac_ipv4_type_ops = {
222*2b24ab6bSSebastien Roy 	MTOPS_PDATA_VERIFY,
223*2b24ab6bSSebastien Roy 	mac_ipv4_unicst_verify,
224*2b24ab6bSSebastien Roy 	mac_ipv4_multicst_verify,
225*2b24ab6bSSebastien Roy 	mac_ipv4_sap_verify,
226*2b24ab6bSSebastien Roy 	mac_ipv4_header,
227*2b24ab6bSSebastien Roy 	mac_ipv4_header_info,
228*2b24ab6bSSebastien Roy 	mac_ipv4_pdata_verify,
229*2b24ab6bSSebastien Roy 	NULL,
230*2b24ab6bSSebastien Roy 	NULL,
231*2b24ab6bSSebastien Roy 	NULL
232*2b24ab6bSSebastien Roy };
233