]>
Commit | Line | Data |
---|---|---|
c803536e SS |
1 | /* |
2 | * Copyright (c) 2014 VMware, Inc. | |
3 | * | |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | * you may not use this file except in compliance with the License. | |
6 | * You may obtain a copy of the License at: | |
7 | * | |
8 | * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | * | |
10 | * Unless required by applicable law or agreed to in writing, software | |
11 | * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | * See the License for the specific language governing permissions and | |
14 | * limitations under the License. | |
15 | */ | |
16 | ||
fa1324c9 | 17 | #include "PacketParser.h" |
c803536e SS |
18 | |
19 | //XXX consider moving to NdisGetDataBuffer. | |
20 | const VOID * | |
21 | OvsGetPacketBytes(const NET_BUFFER_LIST *nbl, | |
22 | UINT32 len, | |
23 | UINT32 srcOffset, | |
24 | VOID *storage) | |
25 | { | |
26 | NDIS_STATUS status = NDIS_STATUS_SUCCESS; | |
27 | PNET_BUFFER netBuffer = NET_BUFFER_LIST_FIRST_NB(nbl); | |
28 | PMDL currentMdl; | |
29 | BOOLEAN firstMDL = TRUE; | |
30 | ULONG destOffset = 0; | |
31 | VOID *dest = storage; | |
32 | const UINT32 copyLen = len; | |
33 | ULONG packetLen; | |
34 | ||
35 | packetLen = NET_BUFFER_DATA_LENGTH(netBuffer); | |
36 | // Start copy from current MDL | |
37 | currentMdl = NET_BUFFER_CURRENT_MDL(netBuffer); | |
38 | ||
39 | // Data on current MDL may be offset from start of MDL | |
40 | while (destOffset < copyLen && currentMdl) { | |
41 | PUCHAR srcMemory = MmGetSystemAddressForMdlSafe(currentMdl, | |
42 | LowPagePriority); | |
43 | ULONG length = MmGetMdlByteCount(currentMdl); | |
44 | if (!srcMemory) { | |
45 | status = NDIS_STATUS_RESOURCES; | |
46 | break; | |
47 | } | |
48 | ||
49 | if (firstMDL) { | |
50 | ULONG mdlOffset = NET_BUFFER_CURRENT_MDL_OFFSET(netBuffer); | |
51 | srcMemory += mdlOffset; | |
52 | length -= mdlOffset; | |
53 | firstMDL = FALSE; | |
54 | } | |
55 | length = MIN(length, packetLen); | |
56 | packetLen -= length; | |
57 | ASSERT((INT)packetLen >= 0); | |
58 | ||
59 | if (srcOffset >= length) { | |
60 | currentMdl = NDIS_MDL_LINKAGE(currentMdl); | |
61 | srcOffset -= length; | |
62 | continue; | |
63 | } else { | |
64 | srcMemory += srcOffset; | |
65 | length -= srcOffset; | |
66 | srcOffset = 0; | |
67 | } | |
68 | ||
69 | length = min(length, copyLen-destOffset); | |
70 | ||
71 | NdisMoveMemory((PUCHAR)dest+destOffset, srcMemory, length); | |
72 | destOffset += length; | |
73 | ||
74 | currentMdl = NDIS_MDL_LINKAGE(currentMdl); | |
75 | } | |
76 | ||
77 | if (destOffset == copyLen) { | |
78 | ASSERT(status == NDIS_STATUS_SUCCESS); | |
79 | return storage; | |
80 | } | |
81 | ||
82 | return NULL; | |
83 | } | |
84 | ||
85 | NDIS_STATUS | |
86 | OvsParseIPv6(const NET_BUFFER_LIST *packet, | |
87 | OvsFlowKey *key, | |
88 | POVS_PACKET_HDR_INFO layers) | |
89 | { | |
90 | UINT16 ofs = layers->l3Offset; | |
91 | IPv6Hdr ipv6HdrStorage; | |
92 | const IPv6Hdr *nh; | |
93 | UINT32 nextHdr; | |
94 | Ipv6Key *flow= &key->ipv6Key; | |
95 | ||
96 | ofs = layers->l3Offset; | |
97 | nh = OvsGetPacketBytes(packet, sizeof *nh, ofs, &ipv6HdrStorage); | |
98 | if (!nh) { | |
99 | return NDIS_STATUS_FAILURE; | |
100 | } | |
101 | ||
102 | nextHdr = nh->nexthdr; | |
103 | memcpy(&flow->ipv6Src, nh->saddr.s6_addr, 16); | |
104 | memcpy(&flow->ipv6Dst, nh->daddr.s6_addr, 16); | |
105 | ||
106 | flow->nwTos = ((nh->flow_lbl[0] & 0xF0) >> 4) | (nh->priority << 4); | |
107 | flow->ipv6Label = | |
108 | ((nh->flow_lbl[0] & 0x0F) << 16) | (nh->flow_lbl[1] << 8) | nh->flow_lbl[2]; | |
109 | flow->nwTtl = nh->hop_limit; | |
110 | flow->nwProto = SOCKET_IPPROTO_NONE; | |
111 | flow->nwFrag = 0; | |
112 | ||
113 | // Parse extended headers and compute L4 offset | |
114 | ofs += sizeof(IPv6Hdr); | |
115 | for (;;) { | |
116 | if ((nextHdr != SOCKET_IPPROTO_HOPOPTS) | |
117 | && (nextHdr != SOCKET_IPPROTO_ROUTING) | |
118 | && (nextHdr != SOCKET_IPPROTO_DSTOPTS) | |
119 | && (nextHdr != SOCKET_IPPROTO_AH) | |
120 | && (nextHdr != SOCKET_IPPROTO_FRAGMENT)) { | |
121 | /* | |
122 | * It's either a terminal header (e.g., TCP, UDP) or one we | |
123 | * don't understand. In either case, we're done with the | |
124 | * packet, so use it to fill in 'nw_proto'. | |
125 | */ | |
126 | break; | |
127 | } | |
128 | ||
129 | if (nextHdr == SOCKET_IPPROTO_HOPOPTS | |
130 | || nextHdr == SOCKET_IPPROTO_ROUTING | |
131 | || nextHdr == SOCKET_IPPROTO_DSTOPTS | |
132 | || nextHdr == SOCKET_IPPROTO_AH) { | |
133 | IPv6ExtHdr extHdrStorage; | |
134 | const IPv6ExtHdr *extHdr; | |
135 | UINT8 len; | |
136 | ||
137 | extHdr = OvsGetPacketBytes(packet, sizeof *extHdr, ofs, &extHdrStorage); | |
138 | if (!extHdr) { | |
139 | return NDIS_STATUS_FAILURE; | |
140 | } | |
141 | ||
142 | len = extHdr->hdrExtLen; | |
143 | ofs += nextHdr == SOCKET_IPPROTO_AH ? (len + 2) * 4 : (len + 1) * 8; | |
144 | nextHdr = extHdr->nextHeader; | |
145 | if (OvsPacketLenNBL(packet) < ofs) { | |
146 | return NDIS_STATUS_FAILURE; | |
147 | } | |
148 | } else if (nextHdr == SOCKET_IPPROTO_FRAGMENT) { | |
149 | IPv6FragHdr fragHdrStorage; | |
150 | const IPv6FragHdr *fragHdr; | |
151 | ||
152 | fragHdr = OvsGetPacketBytes(packet, sizeof *fragHdr, ofs, | |
153 | &fragHdrStorage); | |
154 | if (!fragHdr) { | |
155 | return NDIS_STATUS_FAILURE; | |
156 | } | |
157 | ||
158 | nextHdr = fragHdr->nextHeader; | |
159 | ofs += sizeof *fragHdr; | |
160 | ||
161 | /* We only process the first fragment. */ | |
162 | if (fragHdr->offlg != htons(0)) { | |
163 | if ((fragHdr->offlg & IP6F_OFF_HOST_ORDER_MASK) == htons(0)) { | |
164 | flow->nwFrag = OVSWIN_NW_FRAG_ANY; | |
165 | } else { | |
166 | flow->nwFrag |= OVSWIN_NW_FRAG_LATER; | |
167 | nextHdr = SOCKET_IPPROTO_FRAGMENT; | |
168 | break; | |
169 | } | |
170 | } | |
171 | } | |
172 | } | |
173 | ||
174 | flow->nwProto = (UINT8)nextHdr; | |
175 | layers->l4Offset = ofs; | |
176 | return NDIS_STATUS_SUCCESS; | |
177 | } | |
178 | ||
179 | VOID | |
180 | OvsParseTcp(const NET_BUFFER_LIST *packet, | |
181 | L4Key *flow, | |
182 | POVS_PACKET_HDR_INFO layers) | |
183 | { | |
184 | TCPHdr tcpStorage; | |
185 | const TCPHdr *tcp = OvsGetTcp(packet, layers->l4Offset, &tcpStorage); | |
186 | if (tcp) { | |
187 | flow->tpSrc = tcp->source; | |
188 | flow->tpDst = tcp->dest; | |
189 | layers->isTcp = 1; | |
190 | layers->l7Offset = layers->l4Offset + 4 * tcp->doff; | |
191 | } | |
192 | } | |
193 | ||
194 | VOID | |
195 | OvsParseUdp(const NET_BUFFER_LIST *packet, | |
196 | L4Key *flow, | |
197 | POVS_PACKET_HDR_INFO layers) | |
198 | { | |
199 | UDPHdr udpStorage; | |
200 | const UDPHdr *udp = OvsGetUdp(packet, layers->l4Offset, &udpStorage); | |
201 | if (udp) { | |
202 | flow->tpSrc = udp->source; | |
203 | flow->tpDst = udp->dest; | |
204 | layers->isUdp = 1; | |
205 | if (udp->check == 0) { | |
206 | layers->udpCsumZero = 1; | |
207 | } | |
208 | layers->l7Offset = layers->l4Offset + sizeof *udp; | |
209 | } | |
210 | } | |
211 | ||
212 | NDIS_STATUS | |
213 | OvsParseIcmpV6(const NET_BUFFER_LIST *packet, | |
214 | OvsFlowKey *key, | |
215 | POVS_PACKET_HDR_INFO layers) | |
216 | { | |
217 | UINT16 ofs = layers->l4Offset; | |
218 | ICMPHdr icmpStorage; | |
219 | const ICMPHdr *icmp; | |
220 | Icmp6Key *flow = &key->icmp6Key; | |
221 | ||
222 | memset(&flow->ndTarget, 0, sizeof(flow->ndTarget)); | |
223 | memset(flow->arpSha, 0, sizeof(flow->arpSha)); | |
224 | memset(flow->arpTha, 0, sizeof(flow->arpTha)); | |
225 | ||
226 | icmp = OvsGetIcmp(packet, ofs, &icmpStorage); | |
227 | if (!icmp) { | |
228 | return NDIS_STATUS_FAILURE; | |
229 | } | |
230 | ofs += sizeof *icmp; | |
231 | ||
232 | /* | |
233 | * The ICMPv6 type and code fields use the 16-bit transport port | |
234 | * fields, so we need to store them in 16-bit network byte order. | |
235 | */ | |
236 | key->ipv6Key.l4.tpSrc = htons(icmp->type); | |
237 | key->ipv6Key.l4.tpDst = htons(icmp->code); | |
238 | ||
239 | if (icmp->code == 0 && | |
240 | (icmp->type == ND_NEIGHBOR_SOLICIT || | |
241 | icmp->type == ND_NEIGHBOR_ADVERT)) { | |
242 | struct in6_addr ndTargetStorage; | |
243 | const struct in6_addr *ndTarget; | |
244 | ||
245 | ndTarget = OvsGetPacketBytes(packet, sizeof *ndTarget, ofs, | |
246 | &ndTargetStorage); | |
247 | if (!ndTarget) { | |
248 | return NDIS_STATUS_FAILURE; | |
249 | } | |
250 | flow->ndTarget = *ndTarget; | |
251 | ||
252 | while ((UINT32)(ofs + 8) <= OvsPacketLenNBL(packet)) { | |
253 | /* | |
254 | * The minimum size of an option is 8 bytes, which also is | |
255 | * the size of Ethernet link-layer options. | |
256 | */ | |
257 | IPv6NdOptHdr ndOptStorage; | |
258 | const IPv6NdOptHdr *ndOpt; | |
259 | UINT16 optLen; | |
260 | ||
261 | ndOpt = OvsGetPacketBytes(packet, sizeof *ndOpt, ofs, &ndOptStorage); | |
262 | if (!ndOpt) { | |
263 | return NDIS_STATUS_FAILURE; | |
264 | } | |
265 | ||
266 | optLen = ndOpt->len * 8; | |
267 | if (!optLen || (UINT32)(ofs + optLen) > OvsPacketLenNBL(packet)) { | |
268 | goto invalid; | |
269 | } | |
270 | ||
271 | /* | |
272 | * Store the link layer address if the appropriate option is | |
273 | * provided. It is considered an error if the same link | |
274 | * layer option is specified twice. | |
275 | */ | |
276 | if (ndOpt->type == ND_OPT_SOURCE_LINKADDR && optLen == 8) { | |
277 | if (Eth_IsNullAddr(flow->arpSha)) { | |
278 | memcpy(flow->arpSha, ndOpt + 1, ETH_ADDR_LENGTH); | |
279 | } else { | |
280 | goto invalid; | |
281 | } | |
282 | } else if (ndOpt->type == ND_OPT_TARGET_LINKADDR && optLen == 8) { | |
283 | if (Eth_IsNullAddr(flow->arpTha)) { | |
284 | memcpy(flow->arpTha, ndOpt + 1, ETH_ADDR_LENGTH); | |
285 | } else { | |
286 | goto invalid; | |
287 | } | |
288 | } | |
289 | ||
290 | ofs += optLen; | |
291 | } | |
292 | } | |
293 | ||
294 | layers->l7Offset = ofs; | |
295 | return NDIS_STATUS_SUCCESS; | |
296 | ||
297 | invalid: | |
298 | memset(&flow->ndTarget, 0, sizeof(flow->ndTarget)); | |
299 | memset(flow->arpSha, 0, sizeof(flow->arpSha)); | |
300 | memset(flow->arpTha, 0, sizeof(flow->arpTha)); | |
301 | ||
302 | return NDIS_STATUS_FAILURE; | |
303 | } |