static __wsum lro_tcp_data_csum(struct iphdr *iph, struct tcphdr *tcph, int len) { __wsum tcp_csum; __wsum tcp_hdr_csum; __wsum tcp_ps_hdr_csum; tcp_csum = ~csum_unfold(tcph->check); tcp_hdr_csum = csum_partial((u8 *)tcph, TCP_HDR_LEN(tcph), tcp_csum); tcp_ps_hdr_csum = csum_tcpudp_nofold(iph->saddr, iph->daddr, len + TCP_HDR_LEN(tcph), IPPROTO_TCP, 0); return csum_sub(csum_sub(tcp_csum, tcp_hdr_csum), tcp_ps_hdr_csum); }
static void lro_update_tcp_ip_header(struct net_lro_desc *lro_desc) { struct iphdr *iph = lro_desc->iph; struct tcphdr *tcph = lro_desc->tcph; __be32 *p; __wsum tcp_hdr_csum; tcph->ack_seq = lro_desc->tcp_ack; tcph->window = lro_desc->tcp_window; if (lro_desc->tcp_saw_tstamp) { p = (__be32 *)(tcph + 1); *(p+2) = lro_desc->tcp_rcv_tsecr; } iph->tot_len = htons(lro_desc->ip_tot_len); iph->check = 0; iph->check = ip_fast_csum((u8 *)lro_desc->iph, iph->ihl); tcph->check = 0; tcp_hdr_csum = csum_partial((u8 *)tcph, TCP_HDR_LEN(tcph), 0); lro_desc->data_csum = csum_add(lro_desc->data_csum, tcp_hdr_csum); tcph->check = csum_tcpudp_magic(iph->saddr, iph->daddr, lro_desc->ip_tot_len - IP_HDR_LEN(iph), IPPROTO_TCP, lro_desc->data_csum); }
/* * -------------------------------------------------------------------------- * FixSegmentHeader * * Fix IP length, IP checksum, TCP sequence number and TCP checksum * in the segment. * -------------------------------------------------------------------------- */ static NDIS_STATUS FixSegmentHeader(PNET_BUFFER nb, UINT16 segmentSize, UINT32 seqNumber) { EthHdr *dstEth; IPHdr *dstIP; TCPHdr *dstTCP; PMDL mdl; PUINT8 bufferStart; mdl = NET_BUFFER_FIRST_MDL(nb); bufferStart = (PUINT8)MmGetSystemAddressForMdlSafe(mdl, LowPagePriority); if (!bufferStart) { return NDIS_STATUS_RESOURCES; } dstEth = (EthHdr *)(bufferStart + NET_BUFFER_CURRENT_MDL_OFFSET(nb)); ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb) >= sizeof(EthHdr) + sizeof(IPHdr) + sizeof(TCPHdr)); dstIP = (IPHdr *)((PCHAR)dstEth + sizeof *dstEth); dstTCP = (TCPHdr *)((PCHAR)dstIP + dstIP->ihl * 4); ASSERT((INT)MmGetMdlByteCount(mdl) - NET_BUFFER_CURRENT_MDL_OFFSET(nb) >= sizeof(EthHdr) + dstIP->ihl * 4 + TCP_HDR_LEN(dstTCP)); /* Fix IP length and checksum */ ASSERT(dstIP->protocol == IPPROTO_TCP); dstIP->tot_len = htons(segmentSize + dstIP->ihl * 4 + TCP_HDR_LEN(dstTCP)); dstIP->check = 0; dstIP->check = IPChecksum((UINT8 *)dstIP, dstIP->ihl * 4, 0); /* Fix TCP checksum */ dstTCP->seq = htonl(seqNumber); dstTCP->check = IPPseudoChecksum((UINT32 *)&dstIP->saddr, (UINT32 *)&dstIP->daddr, IPPROTO_TCP, segmentSize + TCP_HDR_LEN(dstTCP)); dstTCP->check = CalculateChecksumNB(nb, (UINT16)(NET_BUFFER_DATA_LENGTH(nb) - sizeof *dstEth - dstIP->ihl * 4), sizeof *dstEth + dstIP->ihl * 4); return STATUS_SUCCESS; }
/* * -------------------------------------------------------------------------- * GetSegmentHeaderInfo * * Extract header size and sequence number for the segment. * -------------------------------------------------------------------------- */ static NDIS_STATUS GetSegmentHeaderInfo(PNET_BUFFER_LIST nbl, const POVS_PACKET_HDR_INFO hdrInfo, UINT32 *hdrSize, UINT32 *seqNumber) { TCPHdr tcpStorage; const TCPHdr *tcp; /* Parse the orginal Eth/IP/TCP header */ tcp = OvsGetPacketBytes(nbl, sizeof *tcp, hdrInfo->l4Offset, &tcpStorage); if (tcp == NULL) { return NDIS_STATUS_FAILURE; } *seqNumber = ntohl(tcp->seq); *hdrSize = hdrInfo->l4Offset + TCP_HDR_LEN(tcp); return NDIS_STATUS_SUCCESS; }
static int decode_tcp(packet_t *p, const _uint8 *bytes, size_t len) { int status = DECODE_OK; unsigned int totlen = 0; tcp_t *tcp = NULL; if (sizeof(tcp_t) > len) goto err; tcp = (tcp_t *)bytes; totlen = TCP_HDR_LEN(tcp); if (totlen > len) goto err; packet_append_header(p, PROTO_NAME_TCP, (void *)tcp, totlen); p->src_port = tcp->src_port; p->dst_port = tcp->dest_port; /* If there is more data */ if ((len - totlen) > 0) { status += call_decoder_byport(ntohs(tcp->src_port), p, (bytes + totlen), (len - totlen)); if (status == DECODER_NOT_FOUND) status += call_decoder_byport(ntohs(tcp->dest_port), p, (bytes + totlen), (len - totlen)); if (status == DECODER_NOT_FOUND) status += call_decoder(PROTO_NAME_RAW, p, (bytes + totlen), (len - totlen)); } return status; err: decoder_add_error(p, "invalid TCP header length"); return call_decoder(PROTO_NAME_RAW, p, bytes, len); }
static struct sk_buff *__lro_proc_segment(struct net_lro_mgr *lro_mgr, struct skb_frag_struct *frags, int len, int true_size, struct vlan_group *vgrp, u16 vlan_tag, void *priv, __wsum sum) { struct net_lro_desc *lro_desc; struct iphdr *iph; struct tcphdr *tcph; struct sk_buff *skb; u64 flags; void *mac_hdr; int mac_hdr_len; int hdr_len = LRO_MAX_PG_HLEN; int vlan_hdr_len = 0; if (!lro_mgr->get_frag_header || lro_mgr->get_frag_header(frags, (void *)&mac_hdr, (void *)&iph, (void *)&tcph, &flags, priv)) { mac_hdr = page_address(frags->page) + frags->page_offset; goto out1; } if (!(flags & LRO_IPV4) || !(flags & LRO_TCP)) goto out1; hdr_len = (int)((void *)(tcph) + TCP_HDR_LEN(tcph) - mac_hdr); mac_hdr_len = (int)((void *)(iph) - mac_hdr); lro_desc = lro_get_desc(lro_mgr, lro_mgr->lro_arr, iph, tcph); if (!lro_desc) goto out1; if (!lro_desc->active) { /* start new lro session */ if (lro_tcp_ip_check(iph, tcph, len - mac_hdr_len, NULL)) goto out1; skb = lro_gen_skb(lro_mgr, frags, len, true_size, mac_hdr, hdr_len, 0, lro_mgr->ip_summed_aggr); if (!skb) goto out; if ((skb->protocol == htons(ETH_P_8021Q)) && !(lro_mgr->features & LRO_F_EXTRACT_VLAN_ID)) vlan_hdr_len = VLAN_HLEN; iph = (void *)(skb->data + vlan_hdr_len); tcph = (void *)((u8 *)skb->data + vlan_hdr_len + IP_HDR_LEN(iph)); lro_init_desc(lro_desc, skb, iph, tcph, 0, NULL); LRO_INC_STATS(lro_mgr, aggregated); return NULL; } if (lro_desc->tcp_next_seq != ntohl(tcph->seq)) goto out2; if (lro_tcp_ip_check(iph, tcph, len - mac_hdr_len, lro_desc)) goto out2; lro_add_frags(lro_desc, len, hdr_len, true_size, frags, iph, tcph); LRO_INC_STATS(lro_mgr, aggregated); if ((skb_shinfo(lro_desc->parent)->nr_frags >= lro_mgr->max_aggr) || lro_desc->parent->len > (0xFFFF - lro_mgr->dev->mtu)) lro_flush(lro_mgr, lro_desc); return NULL; out2: /* send aggregated packets to the stack */ lro_flush(lro_mgr, lro_desc); out1: /* Original packet has to be posted to the stack */ skb = lro_gen_skb(lro_mgr, frags, len, true_size, mac_hdr, hdr_len, sum, lro_mgr->ip_summed); out: return skb; }
/* *---------------------------------------------------------------------------- * OvsCtHandleFtp * Extract the FTP control data from the packet and created a related * entry if it's a valid connection. This method doesn't support extended * FTP yet. Supports PORT and PASV commands. * Eg: * 'PORT 192,168,137,103,192,22\r\n' -> '192.168.137.103' and 49174 * '227 Entering Passive Mode (192,168,137,104,194,14)\r\n' gets extracted * to '192.168.137.104' and 49678 *---------------------------------------------------------------------------- */ NDIS_STATUS OvsCtHandleFtp(PNET_BUFFER_LIST curNbl, OvsFlowKey *key, OVS_PACKET_HDR_INFO *layers, UINT64 currentTime, POVS_CT_ENTRY entry, BOOLEAN request) { NDIS_STATUS status; FTP_TYPE ftpType = 0; const char *buf; char temp[256] = { 0 }; char ftpMsg[256] = { 0 }; TCPHdr tcpStorage; const TCPHdr *tcp; tcp = OvsGetTcp(curNbl, layers->l4Offset, &tcpStorage); if (!tcp) { return NDIS_STATUS_INVALID_PACKET; } UINT32 len = OvsGetTcpPayloadLength(curNbl); if (len > sizeof(temp)) { /* We only care up to 256 */ len = sizeof(temp); } buf = OvsGetPacketBytes(curNbl, len, layers->l4Offset + TCP_HDR_LEN(tcp), temp); if (buf == NULL) { return NDIS_STATUS_INVALID_PACKET; } OvsStrlcpy((char *)ftpMsg, (char *)buf, min(len, sizeof(ftpMsg))); char *req = NULL; if (request) { if ((len >= 5) && (OvsStrncmp("PORT", ftpMsg, 4) == 0)) { ftpType = FTP_TYPE_ACTIVE; req = ftpMsg + 4; } } else { if ((len >= 4) && (OvsStrncmp(FTP_PASV_RSP_PREFIX, ftpMsg, 3) == 0)) { ftpType = FTP_TYPE_PASV; /* There are various formats for PASV command. We try to support * some of them. This has been addressed by RFC 2428 - EPSV. * Eg: * 227 Entering Passive Mode (h1,h2,h3,h4,p1,p2). * 227 Entering Passive Mode (h1,h2,h3,h4,p1,p2 * 227 Entering Passive Mode. h1,h2,h3,h4,p1,p2 * 227 =h1,h2,h3,h4,p1,p2 */ char *paren; paren = strchr(ftpMsg, '('); if (paren) { req = paren + 1; } else { /* PASV command without ( */ req = ftpMsg + 3; } } } if (req == NULL) { /* Not a PORT/PASV control packet */ return NDIS_STATUS_SUCCESS; } UINT32 arr[6] = {0}; status = OvsCtExtractNumbers(req, len, arr, 6, ','); if (status != NDIS_STATUS_SUCCESS) { return status; } UINT32 ip = ntohl((arr[0] << 24) | (arr[1] << 16) | (arr[2] << 8) | arr[3]); UINT16 port = ntohs(((arr[4] << 8) | arr[5])); switch (ftpType) { case FTP_TYPE_PASV: /* Ensure that the command states Server's IP address */ ASSERT(ip == key->ipKey.nwSrc); OvsCtRelatedEntryCreate(key->ipKey.nwProto, key->l2.dlType, /* Server's IP */ ip, /* Use intended client's IP */ key->ipKey.nwDst, /* Dynamic port opened on server */ port, /* We don't know the client port */ 0, currentTime, entry); break; case FTP_TYPE_ACTIVE: OvsCtRelatedEntryCreate(key->ipKey.nwProto, key->l2.dlType, /* Server's default IP address */ key->ipKey.nwDst, /* Client's IP address */ ip, /* FTP Data Port is 20 */ ntohs(IPPORT_FTP_DATA), /* Port opened up on Client */ port, currentTime, entry); break; default: OVS_LOG_ERROR("invalid ftp type:%d", ftpType); status = NDIS_STATUS_INVALID_PARAMETER; break; } return status; }