/* *=========================================================================== * ipcom_sysvar_pqueue_insert_cb *=========================================================================== * Description: * Parameters: * Returns: */ IP_STATIC void ipcom_sysvar_pqueue_insert_cb(Ipcom_sysvar_entry *s, Ipcom_pqueue *pq) { s->refcount++; ipcom_pqueue_insert(pq, s); }
/* *=========================================================================== * ipnet_gre_input *=========================================================================== * Description: Handler for received GRE packets. * Parameters: pkt - Received GRE packet. * Returns: 0 = success, <0 = error code. * */ IP_GLOBAL int ipnet_gre_input(Ipnet_netif *netif, Ipcom_pkt *pkt) { Ipnet_pkt_gre *gre_hdr; int gre_hdr_start = pkt->start; IP_BIT_CLR(pkt->flags, IPCOM_PKT_FLAG_IPV4 | IPCOM_PKT_FLAG_IPV6); gre_hdr = (Ipnet_pkt_gre *)&pkt->data[pkt->start]; pkt->start += IPNET_GRE_HDR_SIZE; /* First 16-bits non-null, verify bits and version. */ if (gre_hdr->flags_reserved0_ver) { /* RFC 2784: 2.3. Reserved0 (bits 1-12) A receiver MUST discard a packet where any of bits 1-5 are non-zero, unless that receiver implements RFC 1701. Bits 6-12 are reserved for future use. These bits MUST be sent as zero and MUST be ignored on receipt. RFC 2890: 2. Extensions to GRE Header Key present (bit 2) Sequence Number Present (bit 3) */ if (IP_BIT_ISSET(gre_hdr->flags_reserved0_ver, IPNET_GRE_FLAG_MUSTBE0)) goto cleanup; /* RFC 2784: 2.3.1. Version Number (bits 13-15) The Version Number field MUST contain the value zero. */ if (IP_BIT_ISSET(gre_hdr->flags_reserved0_ver, IPNET_GRE_FLAG_VERSION)) goto cleanup; /* RFC 2784: 2.5. Checksum (2 octets) The Checksum field contains the IP (one's complement) checksum sum of the all the 16 bit words in the GRE header and the payload packet. For purposes of computing the checksum, the value of the checksum field is zero. This field is present only if the Checksum Present bit is set to one. */ if (IPNET_GRE_CHECKSUM_PRESENT(gre_hdr)) { pkt->start += IPNET_GRE_OPT_CSUM_SIZE; /* IP checksum must be ok. */ if (ipcom_in_checksum(&gre_hdr->flags_reserved0_ver, pkt->end - gre_hdr_start) != 0) goto cleanup; } #ifdef IPNET_USE_RFC2890 /* RFC 2890: 2.1. Key Field (4 octets) The Key field contains a four octet number which was inserted by the encapsulator. The actual method by which this Key is obtained is beyond the scope of the document. The Key field is intended to be used for identifying an individual traffic flow within a tunnel. For example, packets may need to be routed based on context information not present in the encapsulated data. The Key field provides this context and defines a logical traffic flow between encapsulator and decapsulator. Packets belonging to a traffic flow are encapsulated using the same Key value and the decapsulating tunnel endpoint identifies packets belonging to a traffic flow based on the Key Field value. */ if (IPNET_GRE_KEY_PRESENT(gre_hdr)) { Ip_u32 key; key = IP_GET_NTOHL(&pkt->data[pkt->start]); IPNET_GRE_PKT_SET_KEY(pkt, key); pkt->start += IPNET_GRE_OPT_KEY_SIZE; } /* RFC 2890: 2.2. Sequence Number (4 octets) The Sequence Number field is a four byte field and is inserted by the encapsulator when Sequence Number Present Bit is set. The Sequence Number MUST be used by the receiver to establish the order in which packets have been transmitted from the encapsulator to the receiver. The intended use of the Sequence Field is to provide unreliable but in-order delivery. If the Key present bit (bit 2) is set, the sequence number is specific to the traffic flow identified by the Key field. Note that packets without the sequence bit set can be interleaved with packets with the sequence bit set. */ if (IPNET_GRE_SEQNUM_PRESENT(gre_hdr)) { Ipnet_gre_t *gre = netif->ipcom.pdrv; Ip_u32 seqnum; seqnum = IP_GET_NTOHL(&pkt->data[pkt->start]); if (seqnum == gre->recv_seqnum) /* In order segment */ ++gre->recv_seqnum; else if (IPCOM_IS_LT(seqnum, gre->recv_seqnum)) /* Out of order */ goto cleanup; else { Ip_u32 outoforder_timer; int max_perflow_buffer; max_perflow_buffer = ipcom_sysvar_get_as_int0("ipnet.gre.MAX_PERFLOW_BUFFER", 3); outoforder_timer = ipcom_sysvar_get_as_int0("ipnet.gre.OUTOFORDER_TIMER", 1000); if (max_perflow_buffer <= 0) /* No buffering allowed */ goto cleanup; while (ipcom_pqueue_size(gre->reassembly_queue) >= max_perflow_buffer) { ipnet_timeout_cancel(gre->reassembly_tmo); /* Call the timeout handler to force the oldest packet(s) to be inputted to the stack and the receive sequence number to advanced */ ipnet_gre_seq_tmo(netif); } if (gre_hdr->protocol_type == ip_htons(0x0800)) IP_BIT_SET(pkt->flags, IPCOM_PKT_FLAG_IPV4); else if (gre_hdr->protocol_type == ip_htons(0x86DD)) IP_BIT_SET(pkt->flags, IPCOM_PKT_FLAG_IPV6); IPNET_PKT_SET_TIMEOUT_ABS(pkt, ipnet->msec_now + outoforder_timer); if (gre->reassembly_tmo == IP_NULL) if (ipnet_timeout_schedule(outoforder_timer, (Ipnet_timeout_handler) ipnet_gre_seq_tmo, netif, &gre->reassembly_tmo) < 0) goto cleanup; if (ipcom_pqueue_insert(gre->reassembly_queue, pkt) != IPCOM_SUCCESS) { ipnet_timeout_cancel(gre->reassembly_tmo); goto cleanup; } return 0; } pkt->start += IPNET_GRE_OPT_SEQNUM_SIZE; } #endif /* IPNET_USE_RFC2890 */ } /**/ if (netif->ipcom.link_tap) /* start is PAYLOAD == the inner IP header; ipstart points to the PREVIOUS * IP header */ netif->ipcom.link_tap(&netif->ipcom, pkt, IP_PACKET_HOST, gre_hdr->protocol_type, pkt->start, pkt->start); #ifdef IPCOM_USE_INET /* IPv4 in GRE. */ if (gre_hdr->protocol_type == ip_htons(0x0800)) return ipnet_ip4_input(netif, pkt); #endif #ifdef IPCOM_USE_INET6 /* IPv6 in GRE. */ if (gre_hdr->protocol_type == ip_htons(0x86DD)) return ipnet_ip6_input(netif, pkt); #endif /* Unsupported Protocol Type, drop. */ cleanup: ipcom_pkt_free(pkt); return -IP_ERRNO_EINVAL; }