2 * Copyright (c) 2014 VMware, Inc.
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:
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "PacketParser.h"
19 //XXX consider moving to NdisGetDataBuffer.
21 OvsGetPacketBytes(const NET_BUFFER_LIST *nbl,
26 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
27 PNET_BUFFER netBuffer = NET_BUFFER_LIST_FIRST_NB(nbl);
29 BOOLEAN firstMDL = TRUE;
32 const UINT32 copyLen = len;
35 packetLen = NET_BUFFER_DATA_LENGTH(netBuffer);
36 // Start copy from current MDL
37 currentMdl = NET_BUFFER_CURRENT_MDL(netBuffer);
39 // Data on current MDL may be offset from start of MDL
40 while (destOffset < copyLen && currentMdl) {
41 PUCHAR srcMemory = MmGetSystemAddressForMdlSafe(currentMdl,
43 ULONG length = MmGetMdlByteCount(currentMdl);
45 status = NDIS_STATUS_RESOURCES;
50 ULONG mdlOffset = NET_BUFFER_CURRENT_MDL_OFFSET(netBuffer);
51 srcMemory += mdlOffset;
55 length = MIN(length, packetLen);
57 ASSERT((INT)packetLen >= 0);
59 if (srcOffset >= length) {
60 currentMdl = NDIS_MDL_LINKAGE(currentMdl);
64 srcMemory += srcOffset;
69 length = min(length, copyLen-destOffset);
71 NdisMoveMemory((PUCHAR)dest+destOffset, srcMemory, length);
74 currentMdl = NDIS_MDL_LINKAGE(currentMdl);
77 if (destOffset == copyLen) {
78 ASSERT(status == NDIS_STATUS_SUCCESS);
86 OvsParseIPv6(const NET_BUFFER_LIST *packet,
88 POVS_PACKET_HDR_INFO layers)
90 UINT16 ofs = layers->l3Offset;
91 IPv6Hdr ipv6HdrStorage;
94 Ipv6Key *flow= &key->ipv6Key;
96 ofs = layers->l3Offset;
97 nh = OvsGetPacketBytes(packet, sizeof *nh, ofs, &ipv6HdrStorage);
99 return NDIS_STATUS_FAILURE;
102 nextHdr = nh->nexthdr;
103 memcpy(&flow->ipv6Src, nh->saddr.s6_addr, 16);
104 memcpy(&flow->ipv6Dst, nh->daddr.s6_addr, 16);
106 flow->nwTos = ((nh->flow_lbl[0] & 0xF0) >> 4) | (nh->priority << 4);
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 = OVS_FRAG_TYPE_NONE;
113 // Parse extended headers and compute L4 offset
114 ofs += sizeof(IPv6Hdr);
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)) {
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'.
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;
137 extHdr = OvsGetPacketBytes(packet, sizeof *extHdr, ofs, &extHdrStorage);
139 return NDIS_STATUS_FAILURE;
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;
148 } else if (nextHdr == SOCKET_IPPROTO_FRAGMENT) {
149 IPv6FragHdr fragHdrStorage;
150 const IPv6FragHdr *fragHdr;
152 fragHdr = OvsGetPacketBytes(packet, sizeof *fragHdr, ofs,
155 return NDIS_STATUS_FAILURE;
158 nextHdr = fragHdr->nextHeader;
159 ofs += sizeof *fragHdr;
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 = OVS_FRAG_TYPE_FIRST;
166 flow->nwFrag = OVS_FRAG_TYPE_LATER;
167 nextHdr = SOCKET_IPPROTO_FRAGMENT;
174 flow->nwProto = (UINT8)nextHdr;
175 layers->l4Offset = ofs;
176 return NDIS_STATUS_SUCCESS;
180 OvsParseTcp(const NET_BUFFER_LIST *packet,
182 POVS_PACKET_HDR_INFO layers)
185 const TCPHdr *tcp = OvsGetTcp(packet, layers->l4Offset, &tcpStorage);
187 flow->tpSrc = tcp->source;
188 flow->tpDst = tcp->dest;
190 layers->l7Offset = layers->l4Offset + 4 * tcp->doff;
195 OvsParseSctp(const NET_BUFFER_LIST *packet,
197 POVS_PACKET_HDR_INFO layers)
200 const SCTPHdr *sctp = OvsGetSctp(packet, layers->l4Offset, &sctpStorage);
202 flow->tpSrc = sctp->source;
203 flow->tpDst = sctp->dest;
205 layers->l7Offset = layers->l4Offset + sizeof *sctp;
210 OvsParseUdp(const NET_BUFFER_LIST *packet,
212 POVS_PACKET_HDR_INFO layers)
215 const UDPHdr *udp = OvsGetUdp(packet, layers->l4Offset, &udpStorage);
217 flow->tpSrc = udp->source;
218 flow->tpDst = udp->dest;
220 if (udp->check == 0) {
221 layers->udpCsumZero = 1;
223 layers->l7Offset = layers->l4Offset + sizeof *udp;
228 OvsParseIcmpV6(const NET_BUFFER_LIST *packet,
230 POVS_PACKET_HDR_INFO layers)
232 UINT16 ofs = layers->l4Offset;
235 Icmp6Key *flow = &key->icmp6Key;
237 memset(&flow->ndTarget, 0, sizeof(flow->ndTarget));
238 memset(flow->arpSha, 0, sizeof(flow->arpSha));
239 memset(flow->arpTha, 0, sizeof(flow->arpTha));
241 icmp = OvsGetIcmp(packet, ofs, &icmpStorage);
243 return NDIS_STATUS_FAILURE;
248 * The ICMPv6 type and code fields use the 16-bit transport port
249 * fields, so we need to store them in 16-bit network byte order.
251 key->ipv6Key.l4.tpSrc = htons(icmp->type);
252 key->ipv6Key.l4.tpDst = htons(icmp->code);
254 if (icmp->code == 0 &&
255 (icmp->type == ND_NEIGHBOR_SOLICIT ||
256 icmp->type == ND_NEIGHBOR_ADVERT)) {
257 struct in6_addr ndTargetStorage;
258 const struct in6_addr *ndTarget;
260 ndTarget = OvsGetPacketBytes(packet, sizeof *ndTarget, ofs,
263 return NDIS_STATUS_FAILURE;
265 flow->ndTarget = *ndTarget;
267 while ((UINT32)(ofs + 8) <= OvsPacketLenNBL(packet)) {
269 * The minimum size of an option is 8 bytes, which also is
270 * the size of Ethernet link-layer options.
272 IPv6NdOptHdr ndOptStorage;
273 const IPv6NdOptHdr *ndOpt;
276 ndOpt = OvsGetPacketBytes(packet, sizeof *ndOpt, ofs, &ndOptStorage);
278 return NDIS_STATUS_FAILURE;
281 optLen = ndOpt->len * 8;
282 if (!optLen || (UINT32)(ofs + optLen) > OvsPacketLenNBL(packet)) {
287 * Store the link layer address if the appropriate option is
288 * provided. It is considered an error if the same link
289 * layer option is specified twice.
291 if (ndOpt->type == ND_OPT_SOURCE_LINKADDR && optLen == 8) {
292 if (Eth_IsNullAddr(flow->arpSha)) {
293 memcpy(flow->arpSha, ndOpt + 1, ETH_ADDR_LENGTH);
297 } else if (ndOpt->type == ND_OPT_TARGET_LINKADDR && optLen == 8) {
298 if (Eth_IsNullAddr(flow->arpTha)) {
299 memcpy(flow->arpTha, ndOpt + 1, ETH_ADDR_LENGTH);
309 layers->l7Offset = ofs;
310 return NDIS_STATUS_SUCCESS;
313 memset(&flow->ndTarget, 0, sizeof(flow->ndTarget));
314 memset(flow->arpSha, 0, sizeof(flow->arpSha));
315 memset(flow->arpTha, 0, sizeof(flow->arpTha));
317 return NDIS_STATUS_FAILURE;