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
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 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