1*49ef7e06SGarrett D'Amore /*
2*49ef7e06SGarrett D'Amore  * Copyright (c) 2008-2016 Solarflare Communications Inc.
3*49ef7e06SGarrett D'Amore  * All rights reserved.
4*49ef7e06SGarrett D'Amore  *
5*49ef7e06SGarrett D'Amore  * Redistribution and use in source and binary forms, with or without
6*49ef7e06SGarrett D'Amore  * modification, are permitted provided that the following conditions are met:
7*49ef7e06SGarrett D'Amore  *
8*49ef7e06SGarrett D'Amore  * 1. Redistributions of source code must retain the above copyright notice,
9*49ef7e06SGarrett D'Amore  *    this list of conditions and the following disclaimer.
10*49ef7e06SGarrett D'Amore  * 2. Redistributions in binary form must reproduce the above copyright notice,
11*49ef7e06SGarrett D'Amore  *    this list of conditions and the following disclaimer in the documentation
12*49ef7e06SGarrett D'Amore  *    and/or other materials provided with the distribution.
13*49ef7e06SGarrett D'Amore  *
14*49ef7e06SGarrett D'Amore  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15*49ef7e06SGarrett D'Amore  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16*49ef7e06SGarrett D'Amore  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17*49ef7e06SGarrett D'Amore  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18*49ef7e06SGarrett D'Amore  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19*49ef7e06SGarrett D'Amore  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20*49ef7e06SGarrett D'Amore  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21*49ef7e06SGarrett D'Amore  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22*49ef7e06SGarrett D'Amore  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23*49ef7e06SGarrett D'Amore  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24*49ef7e06SGarrett D'Amore  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25*49ef7e06SGarrett D'Amore  *
26*49ef7e06SGarrett D'Amore  * The views and conclusions contained in the software and documentation are
27*49ef7e06SGarrett D'Amore  * those of the authors and should not be interpreted as representing official
28*49ef7e06SGarrett D'Amore  * policies, either expressed or implied, of the FreeBSD Project.
29*49ef7e06SGarrett D'Amore  */
30*49ef7e06SGarrett D'Amore 
31*49ef7e06SGarrett D'Amore #include <sys/types.h>
32*49ef7e06SGarrett D'Amore #include <sys/sysmacros.h>
33*49ef7e06SGarrett D'Amore #include <sys/ddi.h>
34*49ef7e06SGarrett D'Amore #include <sys/sunddi.h>
35*49ef7e06SGarrett D'Amore #include <sys/stream.h>
36*49ef7e06SGarrett D'Amore #include <sys/strsun.h>
37*49ef7e06SGarrett D'Amore #include <sys/strsubr.h>
38*49ef7e06SGarrett D'Amore #include <sys/pattr.h>
39*49ef7e06SGarrett D'Amore 
40*49ef7e06SGarrett D'Amore #include <sys/ethernet.h>
41*49ef7e06SGarrett D'Amore #include <inet/ip.h>
42*49ef7e06SGarrett D'Amore 
43*49ef7e06SGarrett D'Amore #include <netinet/in.h>
44*49ef7e06SGarrett D'Amore #include <netinet/ip.h>
45*49ef7e06SGarrett D'Amore #include <netinet/tcp.h>
46*49ef7e06SGarrett D'Amore #include <netinet/udp.h>
47*49ef7e06SGarrett D'Amore #include <netinet/sctp.h>
48*49ef7e06SGarrett D'Amore 
49*49ef7e06SGarrett D'Amore #include "sfxge.h"
50*49ef7e06SGarrett D'Amore 
51*49ef7e06SGarrett D'Amore #include "efx.h"
52*49ef7e06SGarrett D'Amore 
53*49ef7e06SGarrett D'Amore 
54*49ef7e06SGarrett D'Amore /*
55*49ef7e06SGarrett D'Amore  * Parse packet headers and return:
56*49ef7e06SGarrett D'Amore  *	etherhpp	Ethernet MAC header
57*49ef7e06SGarrett D'Amore  *	iphpp		IPv4 header (NULL for non-IPv4 packet)
58*49ef7e06SGarrett D'Amore  *	thpp		TCP header (NULL for non-TCP packet)
59*49ef7e06SGarrett D'Amore  *	offp		Offset to TCP payload
60*49ef7e06SGarrett D'Amore  *	sizep		Size of TCP payload
61*49ef7e06SGarrett D'Amore  *	dportp		TCP/UDP/SCTP dest. port (network order), otherwise zero
62*49ef7e06SGarrett D'Amore  *	sportp		TCP/UDP/SCTP source port, (network order) otherwise zero
63*49ef7e06SGarrett D'Amore  */
64*49ef7e06SGarrett D'Amore sfxge_packet_type_t
sfxge_pkthdr_parse(mblk_t * mp,struct ether_header ** etherhpp,struct ip ** iphpp,struct tcphdr ** thpp,size_t * offp,size_t * sizep,uint16_t * sportp,uint16_t * dportp)65*49ef7e06SGarrett D'Amore sfxge_pkthdr_parse(mblk_t *mp, struct ether_header **etherhpp,
66*49ef7e06SGarrett D'Amore     struct ip **iphpp, struct tcphdr **thpp,
67*49ef7e06SGarrett D'Amore     size_t *offp, size_t *sizep,
68*49ef7e06SGarrett D'Amore     uint16_t *sportp, uint16_t *dportp)
69*49ef7e06SGarrett D'Amore {
70*49ef7e06SGarrett D'Amore 	struct ether_header *etherhp;
71*49ef7e06SGarrett D'Amore 	uint16_t ether_type;
72*49ef7e06SGarrett D'Amore 	size_t etherhs;
73*49ef7e06SGarrett D'Amore 	struct ip *iphp;
74*49ef7e06SGarrett D'Amore 	size_t iphs;
75*49ef7e06SGarrett D'Amore 	struct tcphdr *thp;
76*49ef7e06SGarrett D'Amore 	size_t len;
77*49ef7e06SGarrett D'Amore 	size_t ths;
78*49ef7e06SGarrett D'Amore 	size_t off;
79*49ef7e06SGarrett D'Amore 	size_t size;
80*49ef7e06SGarrett D'Amore 	uint16_t sport;
81*49ef7e06SGarrett D'Amore 	uint16_t dport;
82*49ef7e06SGarrett D'Amore 	sfxge_packet_type_t pkt_type = SFXGE_PACKET_TYPE_UNKNOWN;
83*49ef7e06SGarrett D'Amore 
84*49ef7e06SGarrett D'Amore 	etherhp = NULL;
85*49ef7e06SGarrett D'Amore 	iphp = NULL;
86*49ef7e06SGarrett D'Amore 	thp = NULL;
87*49ef7e06SGarrett D'Amore 	off = 0;
88*49ef7e06SGarrett D'Amore 	size = 0;
89*49ef7e06SGarrett D'Amore 	sport = 0;
90*49ef7e06SGarrett D'Amore 	dport = 0;
91*49ef7e06SGarrett D'Amore 
92*49ef7e06SGarrett D'Amore 	/* Grab the MAC header */
93*49ef7e06SGarrett D'Amore 	etherhs = sizeof (struct ether_header);
94*49ef7e06SGarrett D'Amore 	if ((MBLKL(mp) < etherhs) && (pullupmsg(mp, etherhs) == 0))
95*49ef7e06SGarrett D'Amore 		goto done;
96*49ef7e06SGarrett D'Amore 
97*49ef7e06SGarrett D'Amore 	/*LINTED*/
98*49ef7e06SGarrett D'Amore 	etherhp = (struct ether_header *)(mp->b_rptr);
99*49ef7e06SGarrett D'Amore 	ether_type = etherhp->ether_type;
100*49ef7e06SGarrett D'Amore 
101*49ef7e06SGarrett D'Amore 	if (ether_type == htons(ETHERTYPE_VLAN)) {
102*49ef7e06SGarrett D'Amore 		struct ether_vlan_header *ethervhp;
103*49ef7e06SGarrett D'Amore 
104*49ef7e06SGarrett D'Amore 		etherhs = sizeof (struct ether_vlan_header);
105*49ef7e06SGarrett D'Amore 		if ((MBLKL(mp) < etherhs) && (pullupmsg(mp, etherhs) == 0))
106*49ef7e06SGarrett D'Amore 			goto done;
107*49ef7e06SGarrett D'Amore 
108*49ef7e06SGarrett D'Amore 		/*LINTED*/
109*49ef7e06SGarrett D'Amore 		ethervhp = (struct ether_vlan_header *)(mp->b_rptr);
110*49ef7e06SGarrett D'Amore 		ether_type = ethervhp->ether_type;
111*49ef7e06SGarrett D'Amore 	}
112*49ef7e06SGarrett D'Amore 
113*49ef7e06SGarrett D'Amore 	if (ether_type != htons(ETHERTYPE_IP))
114*49ef7e06SGarrett D'Amore 		goto done;
115*49ef7e06SGarrett D'Amore 
116*49ef7e06SGarrett D'Amore 	/* Skip over the MAC header */
117*49ef7e06SGarrett D'Amore 	off += etherhs;
118*49ef7e06SGarrett D'Amore 
119*49ef7e06SGarrett D'Amore 	/* Grab the IP header */
120*49ef7e06SGarrett D'Amore 	len = off + sizeof (struct ip);
121*49ef7e06SGarrett D'Amore 	if ((MBLKL(mp) < len) && (pullupmsg(mp, len) == 0))
122*49ef7e06SGarrett D'Amore 		goto done;
123*49ef7e06SGarrett D'Amore 
124*49ef7e06SGarrett D'Amore 	/*LINTED*/
125*49ef7e06SGarrett D'Amore 	iphp = (struct ip *)(mp->b_rptr + off);
126*49ef7e06SGarrett D'Amore 	iphs = iphp->ip_hl * 4;
127*49ef7e06SGarrett D'Amore 
128*49ef7e06SGarrett D'Amore 	if (iphp->ip_v != IPV4_VERSION)
129*49ef7e06SGarrett D'Amore 		goto done;
130*49ef7e06SGarrett D'Amore 
131*49ef7e06SGarrett D'Amore 	/* Get the size of the packet */
132*49ef7e06SGarrett D'Amore 	size = ntohs(iphp->ip_len);
133*49ef7e06SGarrett D'Amore 
134*49ef7e06SGarrett D'Amore 	ASSERT3U(etherhs + size, <=, msgdsize(mp));
135*49ef7e06SGarrett D'Amore 
136*49ef7e06SGarrett D'Amore 	pkt_type = SFXGE_PACKET_TYPE_IPV4_OTHER;
137*49ef7e06SGarrett D'Amore 
138*49ef7e06SGarrett D'Amore 	/* Skip over the IP header */
139*49ef7e06SGarrett D'Amore 	off += iphs;
140*49ef7e06SGarrett D'Amore 	size -= iphs;
141*49ef7e06SGarrett D'Amore 
142*49ef7e06SGarrett D'Amore 	if (iphp->ip_p == IPPROTO_TCP) {
143*49ef7e06SGarrett D'Amore 		/* Grab the TCP header */
144*49ef7e06SGarrett D'Amore 		len = off + sizeof (struct tcphdr);
145*49ef7e06SGarrett D'Amore 		if ((MBLKL(mp) < len) && (pullupmsg(mp, len) == 0))
146*49ef7e06SGarrett D'Amore 			goto done;
147*49ef7e06SGarrett D'Amore 
148*49ef7e06SGarrett D'Amore 		/*LINTED*/
149*49ef7e06SGarrett D'Amore 		thp = (struct tcphdr *)(mp->b_rptr + off);
150*49ef7e06SGarrett D'Amore 		ths = thp->th_off * 4;
151*49ef7e06SGarrett D'Amore 
152*49ef7e06SGarrett D'Amore 		dport = thp->th_dport;
153*49ef7e06SGarrett D'Amore 		sport = thp->th_sport;
154*49ef7e06SGarrett D'Amore 
155*49ef7e06SGarrett D'Amore 		/* Skip over the TCP header */
156*49ef7e06SGarrett D'Amore 		off += ths;
157*49ef7e06SGarrett D'Amore 		size -= ths;
158*49ef7e06SGarrett D'Amore 
159*49ef7e06SGarrett D'Amore 		pkt_type = SFXGE_PACKET_TYPE_IPV4_TCP;
160*49ef7e06SGarrett D'Amore 
161*49ef7e06SGarrett D'Amore 	} else if (iphp->ip_p == IPPROTO_UDP) {
162*49ef7e06SGarrett D'Amore 		struct udphdr *uhp;
163*49ef7e06SGarrett D'Amore 
164*49ef7e06SGarrett D'Amore 		/* Grab the UDP header */
165*49ef7e06SGarrett D'Amore 		len = off + sizeof (struct udphdr);
166*49ef7e06SGarrett D'Amore 		if ((MBLKL(mp) < len) && (pullupmsg(mp, len) == 0))
167*49ef7e06SGarrett D'Amore 			goto done;
168*49ef7e06SGarrett D'Amore 
169*49ef7e06SGarrett D'Amore 		/*LINTED*/
170*49ef7e06SGarrett D'Amore 		uhp = (struct udphdr *)(mp->b_rptr + off);
171*49ef7e06SGarrett D'Amore 		dport = uhp->uh_dport;
172*49ef7e06SGarrett D'Amore 		sport = uhp->uh_sport;
173*49ef7e06SGarrett D'Amore 
174*49ef7e06SGarrett D'Amore 		/* Skip over the UDP header */
175*49ef7e06SGarrett D'Amore 		off += sizeof (struct udphdr);
176*49ef7e06SGarrett D'Amore 		size -= sizeof (struct udphdr);
177*49ef7e06SGarrett D'Amore 
178*49ef7e06SGarrett D'Amore 		pkt_type = SFXGE_PACKET_TYPE_IPV4_UDP;
179*49ef7e06SGarrett D'Amore 
180*49ef7e06SGarrett D'Amore 	} else if (iphp->ip_p == IPPROTO_SCTP) {
181*49ef7e06SGarrett D'Amore 		struct sctp_hdr *shp;
182*49ef7e06SGarrett D'Amore 
183*49ef7e06SGarrett D'Amore 		/* Grab the SCTP header */
184*49ef7e06SGarrett D'Amore 		len = off + sizeof (struct sctp_hdr);
185*49ef7e06SGarrett D'Amore 		if ((MBLKL(mp) < len) && (pullupmsg(mp, len) == 0))
186*49ef7e06SGarrett D'Amore 			goto done;
187*49ef7e06SGarrett D'Amore 
188*49ef7e06SGarrett D'Amore 		/*LINTED*/
189*49ef7e06SGarrett D'Amore 		shp = (struct sctp_hdr *)(mp->b_rptr + off);
190*49ef7e06SGarrett D'Amore 		dport = shp->sh_dport;
191*49ef7e06SGarrett D'Amore 		sport = shp->sh_sport;
192*49ef7e06SGarrett D'Amore 
193*49ef7e06SGarrett D'Amore 		/* Skip over the SCTP header */
194*49ef7e06SGarrett D'Amore 		off += sizeof (struct sctp_hdr);
195*49ef7e06SGarrett D'Amore 		size -= sizeof (struct sctp_hdr);
196*49ef7e06SGarrett D'Amore 
197*49ef7e06SGarrett D'Amore 		pkt_type = SFXGE_PACKET_TYPE_IPV4_SCTP;
198*49ef7e06SGarrett D'Amore 	}
199*49ef7e06SGarrett D'Amore 
200*49ef7e06SGarrett D'Amore 	if (MBLKL(mp) < off)
201*49ef7e06SGarrett D'Amore 		(void) pullupmsg(mp, off);
202*49ef7e06SGarrett D'Amore 
203*49ef7e06SGarrett D'Amore done:
204*49ef7e06SGarrett D'Amore 	*etherhpp = etherhp;
205*49ef7e06SGarrett D'Amore 	*iphpp = iphp;
206*49ef7e06SGarrett D'Amore 	*thpp = thp;
207*49ef7e06SGarrett D'Amore 	*offp = off;
208*49ef7e06SGarrett D'Amore 	*sizep = size;
209*49ef7e06SGarrett D'Amore 	*sportp = sport;
210*49ef7e06SGarrett D'Amore 	*dportp = dport;
211*49ef7e06SGarrett D'Amore 
212*49ef7e06SGarrett D'Amore 	return (pkt_type);
213*49ef7e06SGarrett D'Amore }
214