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 nh = OvsGetPacketBytes(packet, sizeof *nh, ofs, &ipv6HdrStorage);
98 return NDIS_STATUS_FAILURE;
101 nextHdr = nh->nexthdr;
102 memcpy(&flow->ipv6Src, nh->saddr.s6_addr, 16);
103 memcpy(&flow->ipv6Dst, nh->daddr.s6_addr, 16);
105 flow->nwTos = ((nh->flow_lbl[0] & 0xF0) >> 4) | (nh->priority << 4);
107 ((nh->flow_lbl[0] & 0x0F) << 16) | (nh->flow_lbl[1] << 8) | nh->flow_lbl[2];
108 flow->nwTtl = nh->hop_limit;
109 flow->nwProto = SOCKET_IPPROTO_NONE;
110 flow->nwFrag = OVS_FRAG_TYPE_NONE;
112 // Parse extended headers and compute L4 offset
113 ofs += sizeof(IPv6Hdr);
115 if ((nextHdr != SOCKET_IPPROTO_HOPOPTS)
116 && (nextHdr != SOCKET_IPPROTO_ROUTING)
117 && (nextHdr != SOCKET_IPPROTO_DSTOPTS)
118 && (nextHdr != SOCKET_IPPROTO_AH)
119 && (nextHdr != SOCKET_IPPROTO_FRAGMENT)) {
121 * It's either a terminal header (e.g., TCP, UDP) or one we
122 * don't understand. In either case, we're done with the
123 * packet, so use it to fill in 'nw_proto'.
128 if (nextHdr == SOCKET_IPPROTO_HOPOPTS
129 || nextHdr == SOCKET_IPPROTO_ROUTING
130 || nextHdr == SOCKET_IPPROTO_DSTOPTS
131 || nextHdr == SOCKET_IPPROTO_AH) {
132 IPv6ExtHdr extHdrStorage;
133 const IPv6ExtHdr *extHdr;
136 extHdr = OvsGetPacketBytes(packet, sizeof *extHdr, ofs, &extHdrStorage);
138 return NDIS_STATUS_FAILURE;
141 len = extHdr->hdrExtLen;
142 ofs += nextHdr == SOCKET_IPPROTO_AH ? (len + 2) * 4 : (len + 1) * 8;
143 nextHdr = extHdr->nextHeader;
144 if (OvsPacketLenNBL(packet) < ofs) {
145 return NDIS_STATUS_FAILURE;
147 } else if (nextHdr == SOCKET_IPPROTO_FRAGMENT) {
148 IPv6FragHdr fragHdrStorage;
149 const IPv6FragHdr *fragHdr;
151 fragHdr = OvsGetPacketBytes(packet, sizeof *fragHdr, ofs,
154 return NDIS_STATUS_FAILURE;
157 nextHdr = fragHdr->nextHeader;
158 ofs += sizeof *fragHdr;
160 /* We only process the first fragment. */
161 if (fragHdr->offlg != htons(0)) {
162 if ((fragHdr->offlg & IP6F_OFF_HOST_ORDER_MASK) == htons(0)) {
163 flow->nwFrag = OVS_FRAG_TYPE_FIRST;
165 flow->nwFrag = OVS_FRAG_TYPE_LATER;
166 nextHdr = SOCKET_IPPROTO_FRAGMENT;
173 flow->nwProto = (UINT8)nextHdr;
174 layers->l4Offset = ofs;
175 return NDIS_STATUS_SUCCESS;
179 OvsParseTcp(const NET_BUFFER_LIST *packet,
181 POVS_PACKET_HDR_INFO layers)
184 const TCPHdr *tcp = OvsGetTcp(packet, layers->l4Offset, &tcpStorage);
186 flow->tpSrc = tcp->source;
187 flow->tpDst = tcp->dest;
189 layers->l7Offset = layers->l4Offset + 4 * tcp->doff;
194 OvsParseSctp(const NET_BUFFER_LIST *packet,
196 POVS_PACKET_HDR_INFO layers)
199 const SCTPHdr *sctp = OvsGetSctp(packet, layers->l4Offset, &sctpStorage);
201 flow->tpSrc = sctp->source;
202 flow->tpDst = sctp->dest;
204 layers->l7Offset = layers->l4Offset + sizeof *sctp;
209 OvsParseUdp(const NET_BUFFER_LIST *packet,
211 POVS_PACKET_HDR_INFO layers)
214 const UDPHdr *udp = OvsGetUdp(packet, layers->l4Offset, &udpStorage);
216 flow->tpSrc = udp->source;
217 flow->tpDst = udp->dest;
219 if (udp->check == 0) {
220 layers->udpCsumZero = 1;
222 layers->l7Offset = layers->l4Offset + sizeof *udp;
227 OvsParseIcmpV6(const NET_BUFFER_LIST *packet,
229 POVS_PACKET_HDR_INFO layers)
231 UINT16 ofs = layers->l4Offset;
234 Icmp6Key *flow = &key->icmp6Key;
236 memset(&flow->ndTarget, 0, sizeof(flow->ndTarget));
237 memset(flow->arpSha, 0, sizeof(flow->arpSha));
238 memset(flow->arpTha, 0, sizeof(flow->arpTha));
240 icmp = OvsGetIcmp(packet, ofs, &icmpStorage);
242 return NDIS_STATUS_FAILURE;
247 * The ICMPv6 type and code fields use the 16-bit transport port
248 * fields, so we need to store them in 16-bit network byte order.
250 key->ipv6Key.l4.tpSrc = htons(icmp->type);
251 key->ipv6Key.l4.tpDst = htons(icmp->code);
253 if (icmp->code == 0 &&
254 (icmp->type == ND_NEIGHBOR_SOLICIT ||
255 icmp->type == ND_NEIGHBOR_ADVERT)) {
256 struct in6_addr ndTargetStorage;
257 const struct in6_addr *ndTarget;
259 ndTarget = OvsGetPacketBytes(packet, sizeof *ndTarget, ofs,
262 return NDIS_STATUS_FAILURE;
264 flow->ndTarget = *ndTarget;
266 while ((UINT32)(ofs + 8) <= OvsPacketLenNBL(packet)) {
268 * The minimum size of an option is 8 bytes, which also is
269 * the size of Ethernet link-layer options.
271 IPv6NdOptHdr ndOptStorage;
272 const IPv6NdOptHdr *ndOpt;
275 ndOpt = OvsGetPacketBytes(packet, sizeof *ndOpt, ofs, &ndOptStorage);
277 return NDIS_STATUS_FAILURE;
280 optLen = ndOpt->len * 8;
281 if (!optLen || (UINT32)(ofs + optLen) > OvsPacketLenNBL(packet)) {
286 * Store the link layer address if the appropriate option is
287 * provided. It is considered an error if the same link
288 * layer option is specified twice.
290 if (ndOpt->type == ND_OPT_SOURCE_LINKADDR && optLen == 8) {
291 if (Eth_IsNullAddr(flow->arpSha)) {
292 memcpy(flow->arpSha, ndOpt + 1, ETH_ADDR_LENGTH);
296 } else if (ndOpt->type == ND_OPT_TARGET_LINKADDR && optLen == 8) {
297 if (Eth_IsNullAddr(flow->arpTha)) {
298 memcpy(flow->arpTha, ndOpt + 1, ETH_ADDR_LENGTH);
308 layers->l7Offset = ofs;
309 return NDIS_STATUS_SUCCESS;
312 memset(&flow->ndTarget, 0, sizeof(flow->ndTarget));
313 memset(flow->arpSha, 0, sizeof(flow->arpSha));
314 memset(flow->arpTha, 0, sizeof(flow->arpTha));
316 return NDIS_STATUS_FAILURE;