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