/* iprohc_parser.h - ROHC parsing head file */ /* * Copyright (c) 20013 Wind River Systems, Inc. * * The right to copy, distribute or otherwise make use of this software * may be licensed only pursuant to the terms of an applicable Wind River * license agreement. No license to Wind River intellectual property rights * is granted herein. All rights not licensed by Wind River are reserved * by Wind River. */ /* modification history -------------------- 01h,30jul13,j_y Clean medium impact code review defects 01g,15dec10,ggz Fix for defect WIND00254509 01f,10apr10,ggz Resolve 64bit compiler warnings 01e,20apr09,tlu Fix Linux build warnings for mips64 gcc (cav_ebt5800) 01d,04jul08,tlu Add to handle IP extension headers 01c,11jun08,tlu Fix to parse large CID 01b,14may08,tlu Change function prototyping for parsing pkt types 01a,04apr08,tlu Created. */ #ifndef IPROHC_PARSER_H #define IPROHC_PARSER_H /* **************************************************************************** * INCLUDE FILES **************************************************************************** */ #include #include #include #include #include "iprohc_constant.h" /* **************************************************************************** * DEFINES **************************************************************************** */ #ifdef __cplusplus extern "C" { #endif /* *=========================================================================== * IPROHC_GET_CID *=========================================================================== * Get CID from a received compressed packet. pointer will be moved to * point to Body. type_data will store (type indication + body) octet. * * Passed in packet has the following general format: * RFC 3095, 5.2 * * -------------------------- * : Add-CID octet : if (CID 1-15) and (small CIDs) * -------------------------- * | type indication | body | * -------------------------- * : : * / 0 - 2 octets of CID / 1 or 2 octets if (large CIDs) * : : * -------------------------- * / Body / variable length * -------------------------- * */ #define IPROHC_GET_CID(pkt, pointer, cid, type_data) \ { \ pointer = pkt->ipstart; \ if ((pkt->data[pointer] >> ROHC_PKT_ADD_CID_SHIFT) == \ ROHC_PKT_ADD_CID) \ { \ /* small CID */ \ cid = (Ip_u16)(pkt->data[pointer] & 0x0F); \ type_data = pkt->data[pointer+1]; \ pointer += 2; \ } \ else \ { \ /* large CID */ \ type_data = pkt->data[pointer]; \ \ /* \ * Decode cid according to RFC 3095, 4.5.6. \ * RFC 3095, section 5.2.2: If the first bit is 0, the CID uses \ * one octet. If the first bit is 1, the CID uses two octet. \ */ \ if ((pkt->data[pointer+1] & 0x80) == 0) \ { \ cid = pkt->data[pointer+1]; \ pointer += 2; \ } \ else \ { \ ipcom_memcpy(&cid, &(pkt->data[pointer+1]), 2); \ cid = ip_ntohs(cid); \ cid = (Ip_u16)(cid & 0x7fff); \ pointer += 3; \ } \ } \ } /* *=========================================================================== * IPROHC_GET_LIST_ET0 *=========================================================================== * Parse the compressed list encoding type 0 * * 5.8.6.1 Encoding Type 0 (generic scheme) * * --------------------------------- * | ET=0 |GP|PS| CC = m | * --------------------------------- * : gen_id : 1 octet, if GP = 1 * --------------------------------- * | XI 1, ..., XI m | m octets, or m * 4 bits * / -----------------/ * | : Padding : if PS = 0 and m is odd * --------------------------------- * / item1, ..., item n / variable * --------------------------------- * */ #define IPROHC_GET_LIST_ET0(ip_head, ptype, pointer, pkt, updated) \ { \ int i, et_type; \ Iprohc_ref_list *ref_list; \ \ et_type = pkt->data[pointer]; \ ip_head.has_exten = IP_TRUE; \ ip_head.ref_num = (Ip_u8)(et_type & 0x0F); \ ip_head.gen_id = pkt->data[pointer+1]; \ /* move the item pointer to items */ \ if (ip_head.ref_num < 8) \ pointer += 2 + (int)(ip_head.ref_num/2) + (ip_head.ref_num%2); \ else \ pointer += 2 + ip_head.ref_num; \ \ /* create extension header list */ \ for (i = 1; i <= ip_head.ref_num; i++) \ { \ /* Record the reference list */ \ ref_list = (Iprohc_ref_list *)ipcom_malloc(sizeof(Iprohc_ref_list)); \ if (ref_list == IP_NULL) \ { \ IPCOM_LOG0(ERR, "IPROHC_GET_LIST_ET0, out of memory(ref_list)"); \ updated = IP_FALSE; \ break; \ } \ \ ipcom_memset(ref_list, 0, sizeof(Iprohc_ref_list)); \ \ /* Add the ref list structure to ROHC IP header structure */ \ ipcom_list_insert_last(&ip_head.ref_head, &ref_list->ref_list); \ \ /* Record the IP extension header */ \ ref_list->type = ptype; \ if (IPROHC_IP6_EXT(ptype)) \ /* \ * IPv6 ext header, Hdr-ext-len (second octet of the ext header) \ * is the length of the extension header in 8-octet units, not \ * including the first 8 octets. \ */ \ ref_list->length = (Ip_u8)(8 * (pkt->data[pointer+1] + 1)); \ else \ { \ /* minimal encapsulation header */ \ if (pkt->data[pointer+1] & 0x80) \ ref_list->length = 12; \ else \ ref_list->length = 8; \ } \ \ ip_head.ref_len = (Ip_u16)(ip_head.ref_len + ref_list->length); \ ref_list->data = ipcom_malloc(ref_list->length); \ if (ref_list->data == IP_NULL) \ { \ IPCOM_LOG0(ERR, "IPROHC_GET_LIST_ET0, out of memory(ref->data)"); \ updated = IP_FALSE; \ break; \ } \ \ /* Make a copy of the ext header */ \ ipcom_memcpy(ref_list->data, &pkt->data[pointer], ref_list->length); \ \ /* Move the pointer to next item */ \ ptype = pkt->data[pointer]; \ pointer += ref_list->length; \ } \ } /* *=========================================================================== * IPROHC_UPD_LIST_ET0 *=========================================================================== * Update the compressed list encoding type 0 * */ #define IPROHC_UPD_LIST_ET0(iprohc_header, protocol, pointer, pkt) \ { \ Iprohc_ip_header tmp_ip_header; \ Ip_bool updated = IP_TRUE; \ Ip_u8 proto = protocol; \ \ /* Get the new reference list */ \ ipcom_memset(&tmp_ip_header,0,sizeof(tmp_ip_header)); \ ipcom_list_init(&tmp_ip_header.ref_head); \ IPROHC_GET_LIST_ET0(tmp_ip_header, proto, pointer, pkt, updated); \ if (updated) \ { \ /* Free the old reference list */ \ IPROHC_FREE_REF_LIST(iprohc_header); \ \ /* Record the new one */ \ IPROHC_COPY_REF_LIST(iprohc_header, (&tmp_ip_header)); \ } \ else \ { \ /* Free the new reference list */ \ IPROHC_FREE_REF_LIST((&tmp_ip_header)); \ } \ } /* *=========================================================================== * IPROHC_GET_IPV4_STATIC *=========================================================================== * Get an IPv4 static part in Static chain from a IR packet * * 5.7.7.4 IPv4 header static part format * * --------------------------------- * | version = 4 | 0 | * --------------------------------- * | Protocol | * --------------------------------- * / Source Address / 4 octets * --------------------------------- * / Destination Address / 4 octets * --------------------------------- * */ #ifdef IPCOM_USE_INET #define IPROHC_GET_IPV4_STATIC(iprohc_header, pointer, pkt) \ { \ Ipcom_ip_header *ip4_header = &(iprohc_header->header.ip4); \ \ iprohc_header->packet_type = ROHC_PKT_IPV4; \ /* version = 4, IHL = 5 */ \ ip4_header->vers_len = 0x45; \ ip4_header->protocol = pkt->data[pointer+1]; \ \ if (IPROHC_PROC_EXT(ip4_header->protocol)) \ iprohc_header->has_exten = IP_TRUE; \ else if (iprohc_header->has_exten) \ { \ /* Free the old IP extension headers */ \ IPROHC_FREE_REF_LIST(iprohc_header); \ } \ \ /* Copy source and destination address */ \ ipcom_memcpy(&ip4_header->src, &pkt->data[pointer+2], 4); \ ipcom_memcpy(&ip4_header->dst, &pkt->data[pointer+6], 4); \ \ /* Move the pointer */ \ pointer += 10; \ } #else #define IPROHC_GET_IPV4_STATIC(iprohc_header, pointer, pkt) IP_NOOP #endif /* *=========================================================================== * IPROHC_GET_IPV6_STATIC *=========================================================================== * Get an IPv6 static part in Static chain from a IR packet * * 5.7.7.3 IPv6 header static part format * * --------------------------------- * | version = 6 |Flow Label (msb) | 1 octet * --------------------------------- * | Flow Label (lsb) | 2 octets * --------------------------------- * | Next Header | 1 octet * --------------------------------- * / Source Address / 16 octets * --------------------------------- * / Destination Address / 16 octets * --------------------------------- * */ #ifdef IPCOM_USE_INET6 #define IPROHC_GET_IPV6_STATIC(iprohc_header, pointer, pkt) \ { \ Ipcom_ip6_header *ip6_header = &(iprohc_header->header.ip6); \ Ip_u32 flow = 0, ver_class_flow; \ Ip_u16 flow_lsb; \ \ iprohc_header->packet_type = ROHC_PKT_IPV6; \ /* Form the flow label */ \ flow = (Ip_u32)(pkt->data[pointer] & 0x0F) << 16; \ flow_lsb = ip_ntohs((Ip_u16)pkt->data[pointer+1]); \ flow += flow_lsb; \ \ /* (version=6)+(class will be taken from dynamic part)+flow */ \ /* stored in network order */ \ ver_class_flow = (6<<28) + flow; \ ip6_header->ver_class_flow = ip_htonl(ver_class_flow); \ \ /* next header */ \ ip6_header->nxt = pkt->data[pointer+3]; \ \ if (IPROHC_PROC_EXT(ip6_header->nxt)) \ iprohc_header->has_exten = IP_TRUE; \ else if (iprohc_header->has_exten) \ { \ /* Free the old IP extension headers */ \ IPROHC_FREE_REF_LIST(iprohc_header); \ } \ \ /* copy source and destination addresses */ \ ipcom_memcpy(&ip6_header->src, &pkt->data[pointer+4], 16); \ ipcom_memcpy(&ip6_header->dst, &pkt->data[pointer+20], 16); \ \ /* move pointer */ \ pointer += 36; \ } #else #define IPROHC_GET_IPV6_STATIC(iprohc_header, pointer, pkt) IP_NOOP #endif /* *=========================================================================== * IPROHC_GET_IPV4_DYNAMIC *=========================================================================== * Get an IPv4 dynamic part in Dynamic chain from a IR/IR-DYN packet * * 5.7.7.4 IPv4 header dynamic part format * * --------------------------------- * | Type of Service | * --------------------------------- * | Time to Live | * --------------------------------- * / Identification / 2 octets * --------------------------------- * | DF|RND|NBO|SID| 0 | * --------------------------------- * / Generic extension Header list / (not supported) * --------------------------------- * */ #ifdef IPCOM_USE_INET #define IPROHC_GET_IPV4_DYNAMIC(iprohc_header, pointer, pkt) \ { \ Ipcom_ip_header *ip4_header = &(iprohc_header->header.ip4); \ \ ip4_header->tos = pkt->data[pointer]; \ ip4_header->ttl = pkt->data[pointer+1]; \ /* ID is in network order */ \ ipcom_memcpy(&(ip4_header->id), &(pkt->data[pointer+2]), 2); \ iprohc_header->rnd = (Ip_bool)((pkt->data[pointer+4] & 0x40) >> 6); \ iprohc_header->nbo = (Ip_bool)((pkt->data[pointer+4] & 0x20) >> 5); \ iprohc_header->sid = (Ip_bool)((pkt->data[pointer+4] & 0x10) >> 4); \ if (pkt->data[pointer+4] & 0x80) ip4_header->frag |= IPCOM_IPFRAG_DF; \ \ /* Move the pointer */ \ pointer += 5; \ if (iprohc_header->has_exten) \ IPROHC_UPD_LIST_ET0(iprohc_header, ip4_header->protocol, pointer, pkt); \ } #else #define IPROHC_GET_IPV4_DYNAMIC(iprohc_header, pointer, pkt) IP_NOOP #endif /* *=========================================================================== * IPROHC_GET_IPV6_DYNAMIC *=========================================================================== * Get an IPv6 dynamic part in Dynamic chain from a IR/IR-DYN packet * * 5.7.7.3 IPv6 header dynamic part format * * --------------------------------- * | Traffic Class | 1 octet * --------------------------------- * | Hop Limit | 1 octet * --------------------------------- * / Generic extension Header list / (not supported) * --------------------------------- * */ #ifdef IPCOM_USE_INET6 #define IPROHC_GET_IPV6_DYNAMIC(iprohc_header, pointer, pkt) \ { \ Ipcom_ip6_header *ip6_header; \ Ip_u32 ver_class_flow; \ \ ip6_header = (Ipcom_ip6_header *)&(iprohc_header->header.ip6); \ ver_class_flow = ip_ntohl(ip6_header->ver_class_flow); \ \ /* Add traffic class (8 bits) to ver_class_flow */ \ ver_class_flow += (Ip_u32)((pkt->data[pointer])<<20); \ ip6_header->ver_class_flow = ip_htonl(ver_class_flow); \ ip6_header->hlim = pkt->data[pointer+1]; \ \ /* Move pointer */ \ pointer += 2; \ if (iprohc_header->has_exten) \ IPROHC_UPD_LIST_ET0(iprohc_header, ip6_header->nxt, pointer, pkt); \ } #else #define IPROHC_GET_IPV6_DYNAMIC(iprohc_header, pointer, pkt) IP_NOOP #endif /* *=========================================================================== * IPROHC_GET_IP_STATIC *=========================================================================== * Get Static chain in a IR packet */ #define IPROHC_GET_IP_STATIC(ip_context, pointer, pkt) \ { \ Iprohc_ip_header *ip_header_v; \ Ip_u8 protocol; \ \ while (((pkt->data[pointer] >> 4) == 4) || \ ((pkt->data[pointer] >> 4) == 6)) \ { \ ip_header_v = (Iprohc_ip_header *)ipcom_malloc(sizeof(Iprohc_ip_header)); \ if (ip_header_v == IP_NULL) \ { \ IPCOM_LOG0(ERR,"IPROHC_GET_IP_STATIC, out of memory(header)"); \ goto errout; \ } \ \ /* Pre-init the memory */ \ ipcom_memset(ip_header_v, 0, sizeof(Iprohc_ip_header));\ ipcom_list_init(&ip_header_v->ref_head); \ \ /* Add the header to the context list */ \ ipcom_list_insert_last(&ip_context->ip_head, &ip_header_v->ip_list); \ ip_context->ip_num++; \ \ if ((pkt->data[pointer] >> 4) == 4) \ { \ protocol = pkt->data[pointer+1]; \ \ /* An IPv4 header */ \ IPROHC_GET_IPV4_STATIC(ip_header_v, pointer, pkt); \ } \ else \ { \ protocol = pkt->data[pointer+2]; \ \ /* An IPv6 header */ \ IPROHC_GET_IPV6_STATIC(ip_header_v, pointer, pkt); \ } \ \ if ((protocol != IP_IPPROTO_IPIP) && \ (protocol != IP_IPPROTO_IPV6)) \ break; \ } \ } /* *=========================================================================== * IPROHC_GET_IP_DYNAMIC *=========================================================================== * Get Dynamic chain in a IR/IP-DYN packet */ #define IPROHC_GET_IP_DYNAMIC(ip_context, pointer, pkt) \ { \ Iprohc_ip_header *ip_header_v, *p_ip_header; \ \ for (ip_header_v = IPCOM_LIST_FIRST(&ip_context->ip_head); ip_header_v; \ ip_header_v = p_ip_header) \ { \ p_ip_header = IPCOM_LIST_NEXT(&ip_header_v->ip_list); \ \ if (ip_header_v->packet_type == ROHC_PKT_IPV4) \ { \ /* Get an IPv4 dynamic part */ \ IPROHC_GET_IPV4_DYNAMIC(ip_header_v, pointer, pkt); \ } \ else \ { \ /* Get an IPv6 dynamic part */ \ IPROHC_GET_IPV6_DYNAMIC(ip_header_v, pointer, pkt); \ } \ } \ } /* *=========================================================================== * IPROHC_UPD_IP_STATIC *=========================================================================== * Update Static chains from a IR packet */ #define IPROHC_UPD_IP_STATIC(ip_context, pointer, pkt) \ { \ Iprohc_ip_header *ip_header, *p_ip_header; \ \ for (ip_header = IPCOM_LIST_FIRST(&ip_context->ip_head); ip_header; \ ip_header = p_ip_header) \ { \ p_ip_header = IPCOM_LIST_NEXT(&ip_header->ip_list); \ \ if (ip_header->packet_type == ROHC_PKT_IPV4) \ { \ /* Update an IPv4 static part */ \ IPROHC_GET_IPV4_STATIC(ip_header, pointer, pkt); \ } \ else \ { \ /* Update an IPv6 static part */ \ IPROHC_GET_IPV6_STATIC(ip_header, pointer, pkt); \ } \ } \ } /* *=========================================================================== * IPROHC_UPD_IP_DYNAMIC *=========================================================================== * Update Dynamic chains from a IR/IR-DYN packet */ #define IPROHC_UPD_IP_DYNAMIC(ip_context, pointer, pkt) \ IPROHC_GET_IP_DYNAMIC(ip_context, pointer, pkt) /* *=========================================================================== * IPROHC_UPD_IP_ADDTIONAL_DYNAMIC *=========================================================================== * Update additional Dynamic chains from a IP general compressed packet */ #define IPROHC_UPD_IP_ADDTIONAL_DYNAMIC(ip_context, pointer, pkt) \ { \ Iprohc_ip_header *ip_header, *p_ip_header; \ \ /* Skip the first two headers */ \ ip_header = IPCOM_LIST_FIRST(&ip_context->ip_head); \ if(ip_header != IP_NULL) \ ip_header = IPCOM_LIST_NEXT(&ip_header->ip_list); \ if(ip_header != IP_NULL) /* Start for loop from the third IP header */ \ for (ip_header = IPCOM_LIST_NEXT(&ip_header->ip_list); ip_header; \ ip_header = p_ip_header) \ { \ p_ip_header = IPCOM_LIST_NEXT(&ip_header->ip_list); \ \ if (ip_header->packet_type == ROHC_PKT_IPV4) \ { \ /* Get an IPv4 dynamic part */ \ IPROHC_GET_IPV4_DYNAMIC(ip_header, pointer, pkt); \ } \ else \ { \ /* Get an IPv6 dynamic part */ \ IPROHC_GET_IPV6_DYNAMIC(ip_header, pointer, pkt); \ } \ } \ } /* **************************************************************************** * Public TYPES **************************************************************************** */ /* **************************************************************************** * LOCAL TYPES **************************************************************************** */ /* **************************************************************************** * GLOBAL FUNCTIONS **************************************************************************** */ /* Received packet initial parsing functions */ IP_PUBLIC Ip_u8 iprohc_parse_pkt_type(Ipcom_pkt *pkt, Ip_u16 *feedback_num, Ip_u8 **feedbacks, Ipcom_netif *netif); /* Parse extension */ IP_PUBLIC Ip_err iprohc_parse_extension(void *out_header, void *in_header, Ip_u8 *sn, int *mode, int *in_bno, int *in_rnd, int *out_bno, int *out_rnd, Ipcom_pkt *pkt, int *pointer); #ifdef __cplusplus } #endif #endif /* #ifndef IPROHC_PARSER_H */ /* **************************************************************************** * END OF FILE **************************************************************************** */