/* iprohc_tcp_ip.h - ROHC TCP/IP profile head file */ /* * Copyright (c) 2013 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 -------------------- 01i,08aug13,j_y Clean low impact code review defects 01h,30jul13,j_y Clean medium impact code review defects 01d,31jan13,ggz Fixed defect WIND00402004 01c,16oct12,ggz Fix warnings. Defect WIND00382425 01b,01oct11,ggz Added capability to simulate various ipid change pattern 01a,01dec09,ggz Created */ #ifndef IPROHC_TCP_IP_H #define IPROHC_TCP_IP_H /* **************************************************************************** * INCLUDE FILES **************************************************************************** */ #include #include #include #include "iprohc_config.h" #include "iprohc_constant.h" #include "iprohc_ip.h" #include "iprohc_coding_util.h" #ifdef __cplusplus extern "C" { #endif /* **************************************************************************** * DEFINES **************************************************************************** */ #define IPROHC_ENABLE_REENTRANT #define GEN_LEN 9 #define ROHC_TCP_NUM_OF_IR_PKT 5 /* IR and IR-DYN packets */ #define ROHC_TCP_PKT_IR_CR 252 /* 11111100 */ /* TCP Item Table Mappings. * 6.3.4, RFC 4996 * +-----------------+---------------+------+ * | Option name | Table index | Kind | * +-----------------+---------------+------+ * | NOP | 0 | 1 | * | EOL | 1 | 0 | * | MSS | 2 | 2 | * | WINDOW SCALE | 3 | 3 | * | TIMESTAMP | 4 | 8 | * | SACK-PERMITTED | 5 | 4 | * | SACK | 6 | 5 | * | Generic options | 7-15 | | * +-----------------+---------------+------+ */ /* Item index maping table. Reserved options */ Ip_u8 item_index[9] = {1,0,2,3,5,6,255,255,4}; /* Generic options*/ Ip_u8 item_gen_index[GEN_LEN] = {7,8,9,10,11,12,13,14,15}; #define ECN_USED 0x80 /*10000000*/ /* #define ACK_STRIDE_IRREG 0x40 */ /*01000000*/ #define ACK_ZERO 0x20 /*00100000*/ #define URP_ZERO 0x10 /*00010000*/ #define LIST_PRESENT 0x8 /*00001000*/ /* General packet type masks */ #define ROHC_TCP_PKT_CO_M 0x1 #define ROHC_TCP_PKT_RND_1_M 0x2 #define ROHC_TCP_PKT_RND_2_M 0x4 #define ROHC_TCP_PKT_RND_3_M 0x7 #define ROHC_TCP_PKT_RND_4_M 0x4 #define ROHC_TCP_PKT_RND_5_M 0x5 #define ROHC_TCP_PKT_RND_6_M 0x4 #define ROHC_TCP_PKT_RND_7_M 0x2 #define ROHC_TCP_PKT_RND_8_M 0x3 #define ROHC_TCP_PKT_SEQ_1_M 0x4 #define ROHC_TCP_PKT_SEQ_2_M 0x3 #define ROHC_TCP_PKT_SEQ_3_M 0x4 #define ROHC_TCP_PKT_SEQ_4_M 0x7 #define ROHC_TCP_PKT_SEQ_5_M 0x4 #define ROHC_TCP_PKT_SEQ_6_M 0x3 #define ROHC_TCP_PKT_SEQ_7_M 0x4 #define ROHC_TCP_PKT_SEQ_8_M 0x4 /* * TCP control flags * tcp_ecn_flags [ 2 ]; * urg_flag [ 1 ]; * ack_flag [ 1 ]; * psh_flag [ 1 ]; * rsf_flags [ 3 ]; */ #define ROHC_TCP_ECN_FLAGS 0xC0 #define ROHC_TCP_URG_FLAG 0x20 #define ROHC_TCP_ACK_FLAG 0x10 #define ROHC_TCP_PSH_FLAG 0x08 #define ROHC_TCP_RSF_FLAGS 0x07 /* IP ID behavior */ #define IP_ID_BEHAVIOR_SEQUENTIAL 0 #define IP_ID_BEHAVIOR_SEQUENTIAL_SWAPPED 1 #define IP_ID_BEHAVIOR_RANDOM 2 #define IP_ID_BEHAVIOR_ZERO 3 /* TCP header flags * * urg_ptr_irreg; * window_irreg; * ack_stride_irreg; * ackn_not_present; * sn_not_present; */ #define URG_PTR_IRREG 0x01 #define WINDOW_IRREG 0x02 #define ACK_STRIDE_IRREG 0x04 #define ACK_NOT_PRESENT 0x08 #define SN_NOT_PRESENT 0x10 #define TCP_RES_FLAGS_IRREG 0x20 #define TCP_ECN_FLAGS_IRREG 0x40 /* IP flags * Outer IP header * outer_dscp_irreg; * outer_ip_ecn_flags_irreg; * ttl_irregular_chain_flag; */ #define OUTER_DSCP_IRREG 0x01 #define OUTER_IP_ECN_FLAGS_IRREG 0x02 #define TTL_IRREGULAR_CHAIN_FLAG 0x04 /* * Inner IP header * dscp_irreg; * ttl_hlim_irreg; * ecn_present; */ #define DF_IRREG 0x10 #define DSCP_IRREG 0x20 #define TTL_HLIM_IRREG 0x40 #define ECN_PRESENT 0x80 /* *=========================================================================== * IPROHC_TCP_INIT_CONTEXT *=========================================================================== * Set the TCP context */ #define IPROHC_TCP_INIT_CONTEXT(tcp_context, tcp_header, pkt) \ { \ int offset_; \ \ ipcom_memcpy(&tcp_context->src_port, &tcp_header.src_port, 20); \ \ /* Get and save mapped TCP options in the context */ \ IPROHC_TCP_INIT_OPT_LIST(tcp_context, pkt); \ \ tcp_context->c_flags = 0; \ if(tcp_context->ackn == 0) \ tcp_context->c_flags = tcp_context->c_flags | ACK_ZERO; \ if(tcp_context->uptr == 0) \ tcp_context->c_flags = tcp_context->c_flags | URP_ZERO; \ \ /* Set the TCP payload length */ \ offset_ = ((pkt->data[pkt->tlstart + 12]) >> 4) * 4; \ tcp_context->payload_ln = pkt->end - (pkt->tlstart + offset_); \ /* Set the TCP payload */ \ tcp_context->payload = pkt->tlstart + offset_; \ \ } /* *=========================================================================== * IPROHC_TCP_INIT_OPT_LIST *=========================================================================== * Populate TCP options item list * * Sets */ #define IPROHC_TCP_INIT_OPT_LIST(tcp_context, pkt) \ { \ tcp_item_list *item_list = IP_NULL; \ int item_ptr = 0, i; \ int opt_start, opt_end; \ Ip_u8 offset, item_kind = 0; \ Ip_u8 item_ln = 0; \ Ip_u8 opt_fl = 0; \ Ip_bool index_gen; \ \ offset = (Ip_u8)(tcp_context->offset_res >> 4); \ opt_start = pkt->tlstart + 20; \ opt_end = pkt->tlstart + (offset * 4); \ \ for(item_ptr = opt_start; item_ptr < opt_end;) \ { \ item_list = ipcom_malloc(sizeof(tcp_item_list)); \ if (item_list == IP_NULL) goto err2; \ ipcom_memset(item_list, 0, sizeof(tcp_item_list)); \ opt_fl = 0; \ \ item_kind = pkt->data[item_ptr]; \ \ if(item_kind == 0) /* EOL */ \ { \ /* EOL length is 1 byte. There can be padding after the EOL */ \ item_list->index = item_index[item_kind]; \ tcp_context->pad_ln = (Ip_u8)(opt_end - item_ptr - 1); \ item_list->item_ln = 1; \ item_ln = (Ip_u8)(tcp_context->pad_ln + 1); \ /* Dont save padding. tcp_context-pad_ln indicates the length \ of the p[adding */ \ item_list->item = ipcom_malloc(1); \ if (item_list->item == IP_NULL) goto err; \ item_list->item[0] = item_kind; \ opt_fl = 1; \ } \ else if(item_kind == 1) /* NOP */ \ { \ item_list->index = item_index[item_kind]; \ item_list->item_ln = item_ln = 1; \ item_list->item = ipcom_malloc(1); \ if (item_list->item == IP_NULL) goto err; \ item_list->item[0] = item_kind; \ /* ipcom_memcpy(item_list->item, &item_kind, 1);*/ \ opt_fl = 1; \ } \ else \ { \ if(((item_kind >= 2) && (item_kind <= 5)) || item_kind == 8) \ item_list->index = item_index[item_kind]; \ else \ { \ /* Allocate gneric index */ \ index_gen = IP_FALSE; \ for(i = 0; i < GEN_LEN; i++) \ { \ if(tcp_context->item_gen_uindex[i] == 0) \ { \ item_list->index = item_gen_index[i]; \ tcp_context->item_gen_uindex[i] = 1; /* Mark as USED */ \ index_gen = IP_TRUE; \ break; \ } \ } \ if (index_gen == IP_FALSE) \ { \ IPCOM_LOG0(ERR,"IPROHC_TCP_INIT_OPT_LIST, No generic index is available"); \ goto err; \ } \ } \ item_list->item_ln = item_ln = pkt->data[item_ptr + 1]; \ item_list->item = ipcom_malloc(item_ln); \ if(item_list->item == IP_NULL) goto err; \ ipcom_memcpy(item_list->item, &pkt->data[item_ptr], item_ln); \ opt_fl = 1; \ } \ \ if(item_list->index > tcp_context->max_indx) tcp_context->max_indx = item_list->index; \ ipcom_list_insert_last(&tcp_context->opt, &item_list->item_list); \ tcp_context->opt_num++; \ item_ptr = item_ptr + item_ln; \ \ } \ \ if((opt_fl == 0) && (opt_start != opt_end)) \ { \ err: if (item_list != IP_NULL) \ { \ if (item_list->item != IP_NULL) ipcom_free(item_list->item); \ ipcom_free(item_list); \ } \ err2: goto err1; \ } \ } /* *=========================================================================== * IPROHC_TCP_UPD_OPT_LIST *=========================================================================== * Get TCP option list from the packet */ #define IPROHC_TCP_UPD_OPT_LIST(tcp_context, pkt) \ { \ IPROHC_TCP_INIT_OPT_LIST(tcp_context, pkt) \ } /* *=========================================================================== * IPROHC_FMT_TCP_DYNAMIC *=========================================================================== * Fomat dynamic chain in a IR/IR-DYN packet * */ #define IPROHC_FMT_TCP_DYNAMC(tcp_context, pointer, pkt) \ { \ Ip_u8 ldata; \ Ip_u16 ldata1; \ \ IPROHC_FMT_LIST_TCP_OPT(tcp_context, pkt, pointer); \ \ if (tcp_context->tcp_flags & ACK_STRIDE_IRREG) \ { \ pointer -= 2; \ ldata1 = ipcom_htons(tcp_context->ackn_stride); \ ipcom_memcpy(&pkt->data[pointer], &ldata1, 2); \ } \ \ if (!(tcp_context->c_flags & URP_ZERO)) \ { \ pointer -= 2; \ ipcom_memcpy(&pkt->data[pointer], &tcp_context->uptr, 2); \ } \ \ /* Checksum */ \ pointer -= 2; \ ipcom_memcpy(&pkt->data[pointer], &tcp_context->chksum, 2); \ /* Window */ \ pointer -= 2; \ ipcom_memcpy(&pkt->data[pointer], &tcp_context->window, 2); \ /* Ack number */ \ if (!(tcp_context->c_flags & ACK_ZERO)) \ { \ pointer -= 4; \ ipcom_memcpy(&pkt->data[pointer], &tcp_context->ackn, 4); \ } \ /* Seq number */ \ pointer -= 4; \ ipcom_memcpy(&pkt->data[pointer], &tcp_context->sn, 4); \ /* MSN */ \ pointer -= 2; \ ldata1 = ipcom_htons(tcp_context->msn); \ ipcom_memcpy(&pkt->data[pointer], &ldata1, 2); \ pointer --; \ ipcom_memcpy(&pkt->data[pointer], &tcp_context->flags, 1); \ \ /* Reserverd field */ \ ldata = 0; \ ldata = (Ip_u8)(ldata | (tcp_context->offset_res & 0x0F)); \ /* Add c_flags, URP_ZERO, ACK_ZERO, ECN_USED */ \ ldata = (Ip_u8)(ldata | (tcp_context->c_flags & 0xF0)); \ /* Add ACK_STRIDE_FLAG */ \ if (tcp_context->tcp_flags & ACK_STRIDE_IRREG) \ ldata = ldata | 0x40; \ pointer --; \ ipcom_memcpy(&pkt->data[pointer], &ldata, 1); \ } /* *=========================================================================== * IPROHC_FMT_TCP_STATIC *=========================================================================== * Fomat dynamic chain in a IR/IR-DYN packet * */ #define IPROHC_FMT_TCP_STATIC(tcp_context, pointer, pkt) \ { \ pointer -= 2; \ ipcom_memcpy(&pkt->data[pointer], &tcp_context->dst_port, 2); \ pointer -= 2; \ ipcom_memcpy(&pkt->data[pointer], &tcp_context->src_port, 2); \ } /* *=========================================================================== * IPROHC_FMT_TCP_IP_STATIC *=========================================================================== * Fomat Static chain in a IR packet */ #define IPROHC_FMT_TCP_IP_STATIC(ip_context, pointer, pkt) \ { \ Iprohc_ip_header *ip_header, *p_ip_header; \ \ for (ip_header = IPCOM_LIST_LAST(&ip_context->ip_head); ip_header; \ ip_header = p_ip_header) \ { \ p_ip_header = IPCOM_LIST_PREV(&ip_header->ip_list); \ \ if (ip_header->has_exten) \ IPROHC_FMT_TCP_IP_EXT_STATIC(ip_header, pkt, pointer); \ \ if (ip_header->packet_type == ROHC_PKT_IPV4) \ { \ /* Move pointer back for one IPv4 static part */ \ pointer -= 10; \ \ /* Add an IPv4 static part to static chain */ \ IPROHC_FMT_TCP_IPV4_STATIC(ip_header, &pkt->data[pointer]); \ } \ else \ { \ /* Add an IPv6 static part to static chain */ \ IPROHC_FMT_TCP_IPV6_STATIC(ip_header, pkt, pointer); \ } \ } \ } /* *=========================================================================== * IPROHC_FMT_TCP_IPV4_STATIC *=========================================================================== * Add an IPv4 static part to Static chain in a IR packet * * IPv4 header static part format * * COMPRESSED ipv4_static { * version_flag =:= '0' [ 1 ]; * reserved =:= '0000000' [ 7 ]; * protocol =:= irregular(8) [ 8 ]; * src_addr =:= irregular(32) [ 32 ]; * dst_addr =:= irregular(32) [ 32 ]; * } * */ #ifdef IPCOM_USE_INET #define IPROHC_FMT_TCP_IPV4_STATIC(ip_header, data) \ { \ Ipcom_ip_header *ip4_header = &(ip_header->header.ip4); \ Ip_u8 *buff = (Ip_u8 *)data; \ \ ipcom_memcpy(&buff[6], &ip4_header->dst, 4); \ ipcom_memcpy(&buff[2], &ip4_header->src, 4); \ buff[1] = ip4_header->protocol; \ buff[0] = 0x00; \ } #else #define IPROHC_FMT_TCP_IPV4_STATIC(ip_header, data) IP_NOOP #endif /* *=========================================================================== * IPROHC_FMT_IPV6_STATIC *=========================================================================== * Add an IPv6 static part to Static chain in a IR packet * * IPv6 header static part format * * COMPRESSED ipv6_static { * version_flag =:= '1' [ 1 ]; * reserved =:= '00' [ 2 ]; * flow_label =:= fl_enc [ 5, 21 ]; * next_header =:= irregular(8) [ 8 ]; * src_addr =:= irregular(128) [ 128 ]; * dst_addr =:= irregular(128) [ 128 ]; * } * */ #ifdef IPCOM_USE_INET6 #define IPROHC_FMT_TCP_IPV6_STATIC(ip_header, pkt, pointer) \ { \ Ipcom_ip6_header *ip6_header = &(ip_header->header.ip6); \ Ip_u32 flow; \ Ip_u16 flow_lsb; \ Ip_u8 *buff; \ \ flow = IP_GET_NTOHL(&ip6_header->ver_class_flow) & 0xfffff; \ if (flow != 0) \ { \ pointer -= 36; \ } \ else \ { \ pointer -= 34; \ } \ \ buff = &pkt->data[pointer]; \ buff[0] = 0x80; \ if (flow != 0) \ { \ /* fl_enc */ \ buff[0] = buff[0] | 0x10; \ buff[0] = (Ip_u8)(buff[0] | ((flow >> 16) & 0x0f)); \ flow_lsb = (Ip_u16)(flow & 0xffff); \ flow_lsb = ipcom_htons(flow_lsb); \ ipcom_memcpy(&buff[1], &flow_lsb, 2); \ buff[3] = ip6_header->nxt; \ ipcom_memcpy(&buff[4], &ip6_header->src, 16); \ ipcom_memcpy(&buff[20], &ip6_header->dst, 16); \ } \ else \ { \ /* fl_enc */ \ buff[1] = ip6_header->nxt; \ ipcom_memcpy(&buff[2], &ip6_header->src, 16); \ ipcom_memcpy(&buff[18], &ip6_header->dst, 16); \ } \ } #else #define IPROHC_FMT_TCP_IPV6_STATIC(ip_header, pkt, pointer) IP_NOOP #endif /* *=========================================================================== * IPROHC_FMT_TCP_IP_EXT_STATIC *=========================================================================== * */ #define IPROHC_FMT_TCP_IP_EXT_STATIC(ip_header, pkt, pointer) \ { \ Iprohc_ref_list *ext, *n_ext; \ \ for (ext = IPCOM_LIST_LAST(&ip_header->ref_head); \ ext; \ ext = n_ext) \ { \ n_ext = IPCOM_LIST_PREV(&ext->ref_list); \ \ switch(ext->type) \ { \ case IP_IPPROTO_DSTOPTS: /* dest_opt, hop_op */ \ case IP_IPPROTO_HOPOPTS: \ pointer -= 2; \ ipcom_memcpy(&pkt->data[pointer], &ext->data[0], 2); \ break; \ case IP_IPPROTO_ROUTING: /* rout_op */ \ pointer = pointer - ext->length; \ ipcom_memcpy(&pkt->data[pointer], &ext->data[0], ext->length); \ break; \ case IP_IPPROTO_MOBILE: /* checksum is inferred */ \ if(ext->data[1] & 0x80) \ { \ pointer = pointer - 8; \ ipcom_memcpy(&pkt->data[pointer], &ext->data[4], 8); \ } \ else \ { \ pointer = pointer - 4; \ ipcom_memcpy(&pkt->data[pointer], &ext->data[4], 4); \ } \ /* Skip Checksum */ \ pointer -= 2; \ ipcom_memcpy(&pkt->data[pointer], &ext->data[0], 2); \ break; \ default: \ /* Not supported extension */ \ break; \ } \ } \ } /* *=========================================================================== * IPROHC_FMT_TCP_IP_DYNAMC *=========================================================================== * Format Dynamic chain in a IR/IR-DYN packet */ #define IPROHC_FMT_TCP_IP_DYNAMC(ip_context, pointer, pkt) \ { \ Iprohc_ip_header *ip_header, *p_ip_header; \ \ for (ip_header = IPCOM_LIST_LAST(&ip_context->ip_head); \ ip_header != IP_NULL; \ ip_header = p_ip_header) \ { \ p_ip_header = IPCOM_LIST_PREV(&ip_header->ip_list); \ \ if (ip_header->has_exten) \ IPROHC_FMT_TCP_IP_EXT_DYNAMIC(ip_header, pkt, pointer); \ \ if (ip_header->packet_type == ROHC_PKT_IPV4) \ { \ /* Add an IPv4 dynamic part to Dynamic chain */ \ IPROHC_FMT_TCP_IPV4_DYNAMIC(ip_header, pkt, pointer); \ } \ else \ { \ /* Move pointer back for one IPv6 dynamic part */ \ pointer = pointer - 2; \ \ /* Add an IPv6 dynamic part to Dynamic chain */ \ IPROHC_FMT_TCP_IPV6_DYNAMIC(ip_header, pkt, pointer); \ } \ } \ } /* *=========================================================================== * IPROHC_FMT_TCP_IPV4_DYNAMIC *=========================================================================== * Add an IPv4 dynamic part to Dynamic chain in a IR/IR-DYN packet * * COMPRESSED ipv4_dynamic { * reserved =:= '00000' [ 5 ]; * df =:= irregular(1) [ 1 ]; * ip_id_behavior =:= ip_id_behavior_choice(is_innermost) [ 2 ]; * dscp =:= irregular(6) [ 6 ]; * ip_ecn_flags =:= irregular(2) [ 2 ]; * ttl_hopl =:= irregular(8) [ 8 ]; * ip_id =:= * ip_id_enc_dyn(ip_id_behavior.UVALUE) [ 0, 16 ]; * } * */ #ifdef IPCOM_USE_INET #define IPROHC_FMT_TCP_IPV4_DYNAMIC(ip_header, pkt, pointer) \ { \ Ip_u8 ip_id_type = 100; \ Ipcom_ip_header *ip4_header = &(ip_header->header.ip4); \ \ if (ip_header->rnd) \ ip_id_type = IP_ID_BEHAVIOR_RANDOM; \ else if (ip_header->nbo) \ ip_id_type = IP_ID_BEHAVIOR_SEQUENTIAL; \ else if (ip_header->sid) \ { \ ip_id_type = IP_ID_BEHAVIOR_ZERO; \ goto m2; \ } \ else \ { \ /* Not supported IP ID type (swapped bytes). Use random type. */ \ ip_id_type = IP_ID_BEHAVIOR_RANDOM; \ } \ \ if(ip_id_type != IP_ID_BEHAVIOR_ZERO) \ { \ pointer = pointer - 2; \ ipcom_memcpy(&pkt->data[pointer], &(ip4_header->id), 2); \ } \ m2: \ pointer--; \ pkt->data[pointer] = ip4_header->ttl; \ pointer--; \ pkt->data[pointer] = ip4_header->tos; \ pointer--; \ pkt->data[pointer] = 0; \ if (ip4_header->frag & IPCOM_IPFRAG_DF) pkt->data[pointer] = 0x04; \ pkt->data[pointer] = (Ip_u8)(pkt->data[pointer] | (ip_id_type & 0x03)); \ } #else #define IPROHC_FMT_TCP_IPV4_DYNAMIC(ip_header, pkt, pointer) IP_NOOP #endif /* *=========================================================================== * IPROHC_FMT_TCP_IPV6_DYNAMIC *=========================================================================== * Add an IPv6 dynamic part to dynamic chain in a IR/IR-DYN packet * * COMPRESSED ipv6_dynamic { * dscp =:= irregular(6) [ 6 ]; * ip_ecn_flags =:= irregular(2) [ 2 ]; * ttl_hopl =:= irregular(8) [ 8 ]; * } */ #ifdef IPCOM_USE_INET6 #define IPROHC_FMT_TCP_IPV6_DYNAMIC(ip_header, pkt, pointer) \ { \ Ipcom_ip6_header *ip6_header; \ \ ip6_header = (Ipcom_ip6_header *)&(ip_header->header.ip6); \ /* Add dscp and ip_ecn_flags */ \ pkt->data[pointer] = (Ip_u8)((IP_GET_NTOHL(&ip6_header->ver_class_flow) >> 20) & 0xff); \ pkt->data[pointer + 1] = ip6_header->hlim; \ } #else #define IPROHC_FMT_TCP_IPV6_DYNAMIC(ip_header, pkt, pointer) IP_NOOP #endif /* *=========================================================================== * IPROHC_FMT_TCP_IP_EXT_DYNAMIC *=========================================================================== * */ #define IPROHC_FMT_TCP_IP_EXT_DYNAMIC(ip_header, pkt, pointer) \ { \ Iprohc_ref_list *ext_hdr, *n_ext_hdr; \ \ for (ext_hdr = IPCOM_LIST_LAST(&ip_header->ref_head); \ ext_hdr; \ ext_hdr = n_ext_hdr) \ { \ n_ext_hdr = IPCOM_LIST_PREV(&ext_hdr->ref_list); \ \ switch(ext_hdr->type) \ { \ /* Mine and IP_IPPROTO_ROUTING do not have dynamic content */ \ case IP_IPPROTO_DSTOPTS: /* dest_opt, hop_op */ \ case IP_IPPROTO_HOPOPTS: \ pointer = pointer - (ext_hdr->length - 2); \ ipcom_memcpy(&pkt->data[pointer], &ext_hdr->data[2], \ (Ip_size_t)(ext_hdr->length - 2)); \ break; \ default: \ break; \ } \ } \ } /* *=========================================================================== * IPROHC_GET_TCP_IP_STATIC *=========================================================================== * Get Static chain in a IR packet * * IPv4 header static part format * * COMPRESSED ipv4_static { * version_flag =:= '0' [ 1 ]; * reserved =:= '0000000' [ 7 ]; * protocol =:= irregular(8) [ 8 ]; * src_addr =:= irregular(32) [ 32 ]; * dst_addr =:= irregular(32) [ 32 ]; * } * */ #define IPROHC_GET_TCP_IP_STATIC(ip_context, pointer, pkt) \ { \ Iprohc_ip_header *ip_header_v; \ Ip_u8 protocol; \ \ while (((pkt->data[pointer] >> 7) == 0) || \ ((pkt->data[pointer] >> 7) == 1)) \ { \ ip_header_v = (Iprohc_ip_header *)ipcom_malloc(sizeof(Iprohc_ip_header)); \ if (ip_header_v == IP_NULL) \ { \ IPCOM_LOG0(ERR,"IPROHC_GET_TCP_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] >> 7) == 0) \ { \ protocol = pkt->data[pointer+1]; \ \ /* IPv4 header */ \ /* This macro should not change protocol val */ \ IPROHC_GET_TCP_IPV4_STATIC(ip_header_v, pointer, pkt, protocol); \ } \ else \ { \ /* fl_enc encoding */ \ if (pkt->data[pointer] & 0x10) \ { \ protocol = pkt->data[pointer+3]; \ } \ else \ { \ protocol = pkt->data[pointer+1]; \ } \ \ /* IPv4 header */ \ /* This macro should not change protocol val */ \ IPROHC_GET_TCP_IPV6_STATIC(ip_header_v, pointer, pkt, protocol); \ } \ \ if ((ip_header_v->has_exten == IP_TRUE) && (IPROHC_PROC_EXT(protocol))) \ IPROHC_GET_TCP_IP_EXT_STATIC(ip_header_v, pointer, pkt, protocol); \ \ if ((protocol != IP_IPPROTO_IPIP) && \ (protocol != IP_IPPROTO_IPV6)) \ break; \ } \ } /* *=========================================================================== * IPROHC_GET_TCP_IPV4_STATIC *=========================================================================== * Get an IPv4 static part in Static chain from a IR packet * * COMPRESSED ipv4_static { * version_flag =:= '0' [ 1 ]; * reserved =:= '0000000' [ 7 ]; * protocol =:= irregular(8) [ 8 ]; * src_addr =:= irregular(32) [ 32 ]; * dst_addr =:= irregular(32) [ 32 ]; * } * */ #ifdef IPCOM_USE_INET #define IPROHC_GET_TCP_IPV4_STATIC(iprohc_header, pointer, pkt, protocol) \ { \ 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); \ iprohc_header->has_exten = IP_FALSE; \ } \ \ /* 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 = pointer + 10; \ } #else #define IPROHC_GET_TCP_IPV4_STATIC(iprohc_header, pointer, pkt, protocol) IP_NOOP #endif /* *=========================================================================== * IPROHC_GET_TCP_IPV6_STATIC *=========================================================================== * Get an IPv6 static part in Static chain from a IR packet * * COMPRESSED ipv6_static { * version_flag =:= '1' [ 1 ]; * reserved =:= '00' [ 2 ]; * flow_label =:= fl_enc [ 5, 21 ]; * next_header =:= irregular(8) [ 8 ]; * src_addr =:= irregular(128) [ 128 ]; * dst_addr =:= irregular(128) [ 128 ]; * } * */ #ifdef IPCOM_USE_INET6 #define IPROHC_GET_TCP_IPV6_STATIC(iprohc_header, pointer, pkt, protocol) \ { \ Ipcom_ip6_header *ip6_header = &(iprohc_header->header.ip6); \ Ip_u32 flow = 0; \ Ip_u16 flow_lsb = 0; \ \ iprohc_header->packet_type = ROHC_PKT_IPV6; \ \ /* fl_enc encoding */ \ if (pkt->data[pointer] & 0x10) \ { \ /* Form the flow label */ \ ipcom_memcpy(&flow_lsb, &pkt->data[pointer + 1], 2); \ flow = (Ip_u32)ipcom_ntohs(flow_lsb); \ flow = flow | (Ip_u32)((pkt->data[pointer] & (Ip_u8)0xFF) << 16); \ pointer = pointer + 3; \ } \ else \ { \ pointer ++; \ } \ \ ip6_header->nxt = pkt->data[pointer]; \ pointer ++; \ flow = (6<<28) | flow; \ ip6_header->ver_class_flow = ip_htonl(flow); \ \ 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); \ iprohc_header->has_exten = IP_FALSE; \ } \ \ /* copy source and destination addresses */ \ ipcom_memcpy(&ip6_header->src, &pkt->data[pointer], 16); \ ipcom_memcpy(&ip6_header->dst, &pkt->data[pointer+16], 16); \ pointer = pointer + 32; \ } #else #define IPROHC_GET_TCP_IPV6_STATIC(iprohc_header, pointer, pkt, protocol) IP_NOOP #endif /* *=========================================================================== * IPROHC_GET_TCP_IP_EXT_STATIC *=========================================================================== * * */ #define IPROHC_GET_TCP_IP_EXT_STATIC(iprohc_header, pointer, pkt, protocol) \ { \ Iprohc_ip_header tmp_ip_header; \ Ip_u8 proto; \ Iprohc_ref_list *ref_list; \ Ip_bool err = IP_FALSE; \ Ip_u16 mine_c; \ \ proto = protocol; \ ipcom_memset(&tmp_ip_header, 0, sizeof(Iprohc_ip_header)); \ ipcom_list_init(&tmp_ip_header.ref_head); \ while (IPROHC_PROC_EXT(protocol)) \ { \ /* Record the reference list */ \ ref_list = (Iprohc_ref_list *)ipcom_malloc(sizeof(Iprohc_ref_list)); \ if (ref_list == IP_NULL) \ { \ IPCOM_LOG0(ERR, "IPROHC_UPD_TCP_IP_EXT_STATIC, out of memory(ref_list)"); \ err = IP_TRUE; \ goto l1; \ } \ \ ipcom_memset(ref_list, 0, sizeof(Iprohc_ref_list)); \ \ /* Add the ref list structure to ROHC IP header structure */ \ ipcom_list_insert_last(&tmp_ip_header.ref_head, &ref_list->ref_list); \ \ /* Record the IP extension header */ \ ref_list->type = protocol; \ protocol = pkt->data[pointer]; \ \ switch(ref_list->type) \ { \ /* Dest_opt, hop_op */ \ case IP_IPPROTO_DSTOPTS: \ case IP_IPPROTO_HOPOPTS: \ /* Copy 2 bytes. The rest will be added from dynamic cheain */ \ ref_list->length = pkt->data[pointer + 1]; \ ref_list->length = (Ip_u8)(8 * ( ref_list->length + 1)); \ if((ref_list->data = ipcom_malloc(ref_list->length)) == IP_NULL) \ { \ err = IP_TRUE; \ goto l1; \ } \ ipcom_memcpy(&ref_list->data[0], &pkt->data[pointer], 2); \ pointer = pointer + 2; \ break; \ /* Rout_op */ \ case IP_IPPROTO_ROUTING: \ ref_list->length = pkt->data[pointer + 1]; \ ref_list->length = (Ip_u8)(8 * ( ref_list->length + 1)); \ if((ref_list->data = ipcom_malloc(ref_list->length)) == IP_NULL) \ { \ err = IP_TRUE; \ goto l1; \ } \ ipcom_memcpy(&ref_list->data[0], &pkt->data[pointer], ref_list->length); \ pointer = pointer + ref_list->length; \ break; \ /* Mine, checksum is inferred */ \ case IP_IPPROTO_MOBILE: \ /* Minimal encapsulation header */ \ /* Skip Checksum */ \ if (pkt->data[pointer + 1] & 0x80) \ ref_list->length = 12; \ else \ ref_list->length = 8; \ \ if((ref_list->data = ipcom_malloc(ref_list->length)) == IP_NULL) \ { \ err = IP_TRUE; \ goto l1; \ } \ ipcom_memcpy(&ref_list->data[0], &pkt->data[pointer], 2); \ pointer = pointer + 2; \ /* Null checksum headers */ \ ref_list->data[2] = 0; \ ref_list->data[3] = 0; \ \ if (ref_list->data[1] & 0x80) \ { \ ipcom_memcpy(&ref_list->data[4], &pkt->data[pointer], 8); \ pointer = pointer + 8; \ } \ else \ { \ ipcom_memcpy(&ref_list->data[4], &pkt->data[pointer], 4); \ pointer = pointer + 4; \ } \ /* Calculate Mine checksum */ \ mine_c = ipcom_in_checksum(&ref_list->data[0], ref_list->length); \ /* mine_c = ipcom_htons(mine_c); */ \ ipcom_memcpy(&ref_list->data[2], &mine_c, 2); \ break; \ default: \ /* Not supported extension */ \ break; \ } \ \ tmp_ip_header.ref_num++; \ /* Total length of IP extension headers */ \ tmp_ip_header.ref_len = (Ip_u16)(tmp_ip_header.ref_len + ref_list->length); \ tmp_ip_header.has_exten = IP_TRUE; \ } \ l1: \ if(err == IP_FALSE) \ { \ /* 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 \ { \ IPROHC_FREE_REF_LIST((&tmp_ip_header)); \ IPCOM_LOG0(ERR, "IPROHC_GET_LIST_ET0, out of memory(ref->data)"); \ /* Free the new reference list */ \ } \ } /* *=========================================================================== * IPROHC_GET_TCP_IP_DYNAMIC *=========================================================================== * Get Dynamic chain in a IR/IP-DYN packet */ #define IPROHC_GET_TCP_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_TCP_IPV4_DYNAMIC(ip_header_v, pointer, pkt); \ } \ else \ { \ /* Get an IPv6 dynamic part */ \ IPROHC_GET_TCP_IPV6_DYNAMIC(ip_header_v, pointer, pkt); \ } \ } \ } /* *=========================================================================== * IPROHC_GET_TCP_IPV4_DYNAMIC *=========================================================================== * Get an IPv4 dynamic part in Dynamic chain from a IR/IR-DYN packet * * COMPRESSED ipv4_dynamic { * reserved =:= '00000' [ 5 ]; * df =:= irregular(1) [ 1 ]; * ip_id_behavior =:= ip_id_behavior_choice(is_innermost) [ 2 ]; * dscp =:= irregular(6) [ 6 ]; * ip_ecn_flags =:= irregular(2) [ 2 ]; * ttl_hopl =:= irregular(8) [ 8 ]; * ip_id =:= * ip_id_enc_dyn(ip_id_behavior.UVALUE) [ 0, 16 ]; * } * */ #ifdef IPCOM_USE_INET #define IPROHC_GET_TCP_IPV4_DYNAMIC(iprohc_header, pointer, pkt) \ { \ Ipcom_ip_header *ip4_header = &(iprohc_header->header.ip4); \ Ip_u8 ip_id_behavior; \ \ if (pkt->data[pointer] & 0x04) \ ip4_header->frag = (Ip_u16)(ip4_header->frag | IPCOM_IPFRAG_DF); \ else ip4_header->frag = (Ip_u16)(ip4_header->frag & (~IPCOM_IPFRAG_DF)); \ \ iprohc_header->rnd = IP_FALSE; \ iprohc_header->nbo = IP_FALSE; \ iprohc_header->sid = IP_FALSE; \ \ ip_id_behavior = (Ip_u8)(pkt->data[pointer] & 0x03); \ pointer ++; \ ip4_header->tos = pkt->data[pointer]; \ pointer ++; \ ip4_header->ttl = pkt->data[pointer]; \ pointer ++; \ \ if (ip_id_behavior == IP_ID_BEHAVIOR_SEQUENTIAL) \ iprohc_header->nbo = IP_TRUE; \ else if (ip_id_behavior == IP_ID_BEHAVIOR_RANDOM) \ iprohc_header->rnd = IP_TRUE; \ else if (ip_id_behavior == IP_ID_BEHAVIOR_ZERO) \ iprohc_header->sid = IP_TRUE; \ /* ip_id_behavior == IP_ID_BEHAVIOR_SEQUENTIAL_SWAPPED not supported */ \ \ /* ip_id_enc_dyn compression */ \ if(ip_id_behavior == IP_ID_BEHAVIOR_ZERO) \ ip4_header->id = 0; \ else \ { \ ipcom_memcpy(&(ip4_header->id), &(pkt->data[pointer]), 2); \ pointer = pointer + 2; \ } \ \ if (iprohc_header->has_exten) \ IPROHC_GET_TCP_IP_EXT_DYNAMIC(iprohc_header, ip4_header->protocol, \ pointer, pkt); \ } #else #define IPROHC_GET_TCP_IPV4_DYNAMIC(iprohc_header, pointer, pkt) IP_NOOP #endif /* *=========================================================================== * IPROHC_GET_TCP_IPV6_DYNAMIC *=========================================================================== * Get an IPv6 dynamic part in Dynamic chain from a IR/IR-DYN packet * * COMPRESSED ipv6_dynamic { * dscp =:= irregular(6) [ 6 ]; * ip_ecn_flags =:= irregular(2) [ 2 ]; * ttl_hopl =:= irregular(8) [ 8 ]; * } * */ #ifdef IPCOM_USE_INET6 #define IPROHC_GET_TCP_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 = ver_class_flow | (Ip_u32)((pkt->data[pointer])<<20); \ ip6_header->ver_class_flow = ip_htonl(ver_class_flow); \ pointer ++; \ ip6_header->hlim = pkt->data[pointer]; \ pointer ++; \ \ if (iprohc_header->has_exten) \ IPROHC_GET_TCP_IP_EXT_DYNAMIC(iprohc_header, ip6_header->nxt, pointer, pkt); \ } #else #define IPROHC_GET_TCP_IPV6_DYNAMIC(iprohc_header, pointer, pkt) IP_NOOP #endif /* *=========================================================================== * IPROHC_GET_TCP_IP_EXT_DYNAMIC *=========================================================================== * Update the compressed list encoding type 0 * */ #define IPROHC_GET_TCP_IP_EXT_DYNAMIC(iprohc_header, protocol, pointer, pkt) \ { \ Iprohc_ref_list *ext_hdr, *n_ext_hdr; \ Ip_u8 next_hdr_tmp = protocol; \ \ for (ext_hdr = IPCOM_LIST_FIRST(&iprohc_header->ref_head); \ ext_hdr; \ ext_hdr = n_ext_hdr) \ { \ n_ext_hdr = IPCOM_LIST_NEXT(&ext_hdr->ref_list); \ \ switch(next_hdr_tmp) \ { \ case IP_IPPROTO_DSTOPTS: /* dest_opt, hop_op */ \ case IP_IPPROTO_HOPOPTS: \ ipcom_memcpy(&ext_hdr->data[2], &pkt->data[pointer], (Ip_size_t)(ext_hdr->length - 2)); \ pointer = pointer + ext_hdr->length - 2; \ break; \ case IP_IPPROTO_ROUTING: /* No dynamic content */ \ case IP_IPPROTO_MOBILE: /* No dynamic content */ \ break; \ default: \ /* Not supported extension */ \ break; \ } \ next_hdr_tmp = ext_hdr->type; \ } \ } /* *=========================================================================== * IPROHC_UPD_TCP_IP_STATIC *=========================================================================== * Update Static chains from a IR packet */ #define IPROHC_UPD_TCP_IP_STATIC(ip_context, pointer, pkt) \ { \ Iprohc_ip_header *ip_header, *p_ip_header; \ Ip_u8 protocol; \ \ 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 */ \ protocol = pkt->data[pointer+1]; \ /* This macro should not change protocol val */ \ IPROHC_GET_TCP_IPV4_STATIC(ip_header, pointer, pkt, protocol); \ } \ else \ { \ /* Update an IPv6 static part */ \ /* fl_enc encoding */ \ if (pkt->data[pointer] & 0x10) \ { \ protocol = pkt->data[pointer+3]; \ } \ else \ { \ protocol = pkt->data[pointer+1]; \ } \ /* This macro should not change protocol val */ \ IPROHC_GET_TCP_IPV6_STATIC(ip_header, pointer, pkt, protocol); \ } \ if ((ip_header->has_exten == IP_TRUE) && (IPROHC_PROC_EXT(protocol))) \ IPROHC_GET_TCP_IP_EXT_STATIC(ip_header, pointer, pkt, protocol); \ } \ } /* *=========================================================================== * IPROHC_UPD_TCP_IP_DYNAMIC *=========================================================================== * Compressor. Set context attributes for scailed SN and ACK */ #define IPROHC_UPD_TCP_IP_DYNAMIC(ip_context, pointer, pkt) \ { \ IPROHC_GET_TCP_IP_DYNAMIC(ip_context, pointer, pkt); \ } /* *=========================================================================== * IPROHC_TCP_C_INIT_SCALING *=========================================================================== * Compressor. Set context attributes for scailed SN and ACK */ #define IPROHC_TCP_C_INIT_SCALING(tcp_context, pkt) \ { \ /* Scaling is not supported */ \ tcp_context->scailing_used = IP_FALSE; \ tcp_context->ackn_stride = 0; \ /*Clear ACK_STRIDE_IRREG flag */ \ tcp_context->tcp_flags = (Ip_u8)(tcp_context->tcp_flags & (~ACK_STRIDE_IRREG)); \ } /* *=========================================================================== * IPROHC_TCP_D_INIT_SCALING *=========================================================================== * Compressor. Set context attributes for scailed SN and ACK */ #define IPROHC_TCP_D_INIT_SCALING(tcp_context, pkt) \ { \ /* Scaling is not supported yet */ \ tcp_context->scailing_used = IP_FALSE; \ } /* *=========================================================================== * IPROHC_TCP_C_COPY_OPT_LIST *=========================================================================== * Copy the TCP options list */ #define IPROHC_TCP_C_COPY_OPT_LIST(tcp_context, from_tcp_context) \ { \ tcp_item_list *opt_item, *n_opt_item; \ \ ipcom_list_init(&tcp_context->opt); \ tcp_context->pad_ln = from_tcp_context->pad_ln; \ tcp_context->opt_num = from_tcp_context->opt_num; \ tcp_context->max_indx = from_tcp_context->max_indx; \ /* Copy gen indexes */ \ ipcom_memcpy(&tcp_context->item_gen_uindex, \ &from_tcp_context->item_gen_uindex, \ GEN_LEN); \ \ for (opt_item = IPCOM_LIST_FIRST(&from_tcp_context->opt); \ opt_item; \ opt_item = n_opt_item) \ { \ n_opt_item = IPCOM_LIST_NEXT(&opt_item->item_list); \ \ ipcom_list_remove(&opt_item->item_list); \ /* Add the item structure to tcp context */ \ ipcom_list_insert_last(&tcp_context->opt, &opt_item->item_list); \ } \ } /* *=========================================================================== * IPROHC_TCP_C_FREE_OPT_LIST *=========================================================================== * */ #define IPROHC_TCP_C_FREE_OPT_LIST(tcp_context) \ { \ tcp_item_list *opt_item, *n_opt_item; \ \ tcp_context->pad_ln = 0; \ tcp_context->opt_num = 0; \ tcp_context->max_indx = 0; \ ipcom_memset(&tcp_context->item_gen_uindex, 0, GEN_LEN); \ \ for (opt_item = IPCOM_LIST_FIRST(&tcp_context->opt); \ opt_item; \ opt_item = n_opt_item) \ { \ n_opt_item = IPCOM_LIST_NEXT(&opt_item->item_list); \ ipcom_list_remove(&opt_item->item_list); \ \ if (opt_item->item) ipcom_free(opt_item->item); \ \ ipcom_free(opt_item); \ } \ \ } /* *=========================================================================== * IPROHC_TCP_C_FREE_OPT_LIST *=========================================================================== * */ #define IPROHC_TCP_C_FREE_OPT_LIST1(tcp_opt_list) \ { \ tcp_item_list *opt_item, *n_opt_item; \ \ tcp_opt_list->pad_ln = 0; \ tcp_opt_list->opt_num = 0; \ tcp_opt_list->max_indx = 0; \ ipcom_memset(&tcp_opt_list->item_gen_uindex, 0, GEN_LEN); \ \ for (opt_item = IPCOM_LIST_FIRST(&tcp_opt_list->opt); \ opt_item; \ opt_item = n_opt_item) \ { \ n_opt_item = IPCOM_LIST_NEXT(&opt_item->item_list); \ ipcom_list_remove(&opt_item->item_list); \ \ if (opt_item->item) \ ipcom_free(opt_item->item); \ \ ipcom_free(opt_item); \ } \ } /* *=========================================================================== * IPROHC_TCP_D_FREE_OPT_LIST *=========================================================================== * */ #define IPROHC_TCP_D_FREE_OPT_LIST(tcp_context) \ { \ tcp_item_list *opt_item, *n_opt_item; \ \ tcp_context->pad_ln = 0; \ tcp_context->opt_num = 0; \ ipcom_memset(&tcp_context->item_gen_uindex, 0, GEN_LEN); \ \ for (opt_item = IPCOM_LIST_FIRST(&tcp_context->opt); \ opt_item; \ opt_item = n_opt_item) \ { \ n_opt_item = IPCOM_LIST_NEXT(&opt_item->item_list); \ ipcom_list_remove(&opt_item->item_list); \ \ if (opt_item->item) ipcom_free(opt_item->item); \ \ ipcom_free(opt_item); \ } \ } /* *=========================================================================== * IPROHC_TCP_D_FREE_OPT_LIST *=========================================================================== * */ #define IPROHC_TCP_D_FREE_OPT_LIST1(tmp_opt_list) \ { \ tcp_item_list *opt_item, *n_opt_item; \ \ tmp_opt_list.pad_ln = 0; \ tmp_opt_list.opt_num = 0; \ \ for (opt_item = IPCOM_LIST_FIRST(&tmp_opt_list.opt); \ opt_item; \ opt_item = n_opt_item) \ { \ n_opt_item = IPCOM_LIST_NEXT(&opt_item->item_list); \ ipcom_list_remove(&opt_item->item_list); \ \ if (opt_item->item) \ ipcom_free(opt_item->item); \ \ ipcom_free(opt_item); \ } \ } /* *=========================================================================== * IPROHC_TCP_D_COPY_OPT_LIST *=========================================================================== * */ #define IPROHC_TCP_D_COPY_OPT_LIST(tcp_context, from_opt_list) \ { \ tcp_item_list *opt_item, *n_opt_item; \ \ ipcom_list_init(&tcp_context->opt); \ tcp_context->pad_ln = from_opt_list.pad_ln; \ tcp_context->opt_num = from_opt_list.opt_num; \ \ ipcom_memcpy(&tcp_context->item_gen_uindex, \ &from_opt_list.item_gen_uindex, GEN_LEN); \ \ for (opt_item = IPCOM_LIST_FIRST(&from_opt_list.opt); \ opt_item; \ opt_item = n_opt_item) \ { \ n_opt_item = IPCOM_LIST_NEXT(&opt_item->item_list); \ /* Remove the item from the list */ \ ipcom_list_remove(&opt_item->item_list); \ /* Add the ref list structure to to_ref_head */ \ ipcom_list_insert_last(&tcp_context->opt, &opt_item->item_list); \ } \ } /* *=========================================================================== * IPROHC_GET_TCP_STATIC *=========================================================================== * GET static header header part in a IR packet */ #define IPROHC_GET_TCP_STATIC(tcp_context, pointer, pkt) \ { \ ipcom_memcpy(&tcp_context->src_port, &pkt->data[pointer], 2); \ pointer = pointer + 2; \ ipcom_memcpy(&tcp_context->dst_port, &pkt->data[pointer], 2); \ pointer = pointer + 2; \ } /* *=========================================================================== * IPROHC_GET_TCP_DYNAMIC *=========================================================================== * Get TCP dynamic chain in a IR/IP-DYN packet */ #define IPROHC_GET_TCP_DYNAMIC(tcp_context, pointer, pkt) \ { \ Ip_u16 data = 0; \ Ip_err ret_val = IPCOM_SUCCESS; \ tcp_opt_list tmp_opt_list; \ \ /* Get c_flags, URP_ZERO, ACK_ZERO, ECN_USED */ \ tcp_context->c_flags = (Ip_u8)(tcp_context->c_flags & (~0xF0)); \ tcp_context->c_flags = (Ip_u8)(tcp_context->c_flags | \ (pkt->data[pointer] & 0xF0)); \ /* Get ACK_STRIDE_FLAG */ \ tcp_context->tcp_flags = (Ip_u8)(tcp_context->tcp_flags & (~ACK_STRIDE_IRREG)); \ if (pkt->data[pointer] & 0x40) \ tcp_context->tcp_flags = tcp_context->tcp_flags | ACK_STRIDE_IRREG; \ \ tcp_context->offset_res = (Ip_u8)(tcp_context->offset_res & (~0x0F)); \ tcp_context->offset_res = (Ip_u8)(tcp_context->offset_res | \ (pkt->data[pointer] & 0x0F)); \ \ pointer++; \ ipcom_memcpy(&tcp_context->flags, &pkt->data[pointer], 1); \ pointer++; \ /* MSN */ \ ipcom_memcpy(&data, &pkt->data[pointer], 2); \ tcp_context->msn = ipcom_ntohs(data); \ pointer = pointer + 2; \ /* Seq number */ \ ipcom_memcpy(&tcp_context->sn, &pkt->data[pointer], 4); \ pointer = pointer + 4; \ /* Ack number */ \ if(!(tcp_context->c_flags & ACK_ZERO)) \ { \ ipcom_memcpy(&tcp_context->ackn, &pkt->data[pointer], 4); \ pointer = pointer + 4; \ } \ else tcp_context->ackn = 0; \ /* Window */ \ ipcom_memcpy(&tcp_context->window, &pkt->data[pointer], 2); \ pointer = pointer + 2; \ /* Checksum */ \ ipcom_memcpy(&tcp_context->chksum, &pkt->data[pointer], 2); \ pointer = pointer + 2; \ \ if(!(tcp_context->c_flags & URP_ZERO)) \ { \ ipcom_memcpy(&tcp_context->uptr, &pkt->data[pointer], 2); \ pointer += 2; \ } else tcp_context->uptr = 0; \ \ if(tcp_context->tcp_flags & ACK_STRIDE_IRREG) \ { \ ipcom_memcpy(&tcp_context->ackn_stride, &pkt->data[pointer], 2); \ pointer += 2; \ } /* else ack_stride is a static. Leave the previouse value in the context */ \ \ /* Save the older OPT list and recover if the exctraction of the new OPT failes */ \ ipcom_memset(&tmp_opt_list, 0, sizeof(tmp_opt_list)); \ ipcom_list_init(&tmp_opt_list.opt); \ IPROHC_GET_LIST_TCP_OPT(tmp_opt_list, pkt, pointer, ret_val); \ \ if (ret_val == IPCOM_SUCCESS) \ { \ IPROHC_TCP_D_FREE_OPT_LIST(tcp_context); \ IPROHC_TCP_D_COPY_OPT_LIST(tcp_context, tmp_opt_list); \ } \ else \ { \ IPROHC_TCP_D_FREE_OPT_LIST1(tmp_opt_list); \ goto errout; \ } \ } /* *=========================================================================== * IPROHC_GET_TCP_DYNAMIC *=========================================================================== * Get TCP dynamic chain in a IR/IP-DYN packet */ #define IPROHC_GET_TCP_DYNAMIC1(tcp_context, pointer, pkt) \ { \ Ip_u16 data = 0; \ Ip_err ret_val = IPCOM_SUCCESS; \ tcp_opt_list tmp_opt_list; \ \ tcp_context->offset_res = (Ip_u8)(tcp_context->offset_res & (~0x0F)); \ tcp_context->offset_res = (Ip_u8)(tcp_context->offset_res | \ (pkt->data[pointer] & 0x0F)); \ \ /* Get c_flags, URP_ZERO, ACK_ZERO, ECN_USED */ \ tcp_context->c_flags = (Ip_u8)(tcp_context->c_flags & (~0xF0)); \ tcp_context->c_flags = (Ip_u8)(tcp_context->c_flags | \ (pkt->data[pointer] & 0xF0)); \ \ /* Get ACK_STRIDE_FLAG */ \ tcp_context->tcp_flags = (Ip_u8)(tcp_context->tcp_flags & (~ACK_STRIDE_IRREG)); \ if (pkt->data[pointer] & 0x40) \ tcp_context->tcp_flags = (Ip_u8)(tcp_context->tcp_flags | ACK_STRIDE_IRREG); \ \ pointer++; \ ipcom_memcpy(&tcp_context->flags, &pkt->data[pointer], 1); \ pointer++; \ /* MSN */ \ ipcom_memcpy(&data, &pkt->data[pointer], 2); \ tcp_context->msn = ipcom_ntohs(data); \ pointer = pointer + 2; \ /* Seq number */ \ ipcom_memcpy(&tcp_context->sn, &pkt->data[pointer], 4); \ pointer = pointer + 4; \ /* Ack number */ \ if(!(tcp_context->c_flags & ACK_ZERO)) \ { \ ipcom_memcpy(&tcp_context->ackn, &pkt->data[pointer], 4); \ pointer = pointer + 4; \ } \ else tcp_context->ackn = 0; \ /* Window */ \ ipcom_memcpy(&tcp_context->window, &pkt->data[pointer], 2); \ pointer = pointer + 2; \ /* Checksum */ \ ipcom_memcpy(&tcp_context->chksum, &pkt->data[pointer], 2); \ pointer = pointer + 2; \ \ if(!(tcp_context->c_flags & URP_ZERO)) \ { \ ipcom_memcpy(&tcp_context->uptr, &pkt->data[pointer], 2); \ pointer += 2; \ } else tcp_context->uptr = 0; \ \ if(tcp_context->tcp_flags & ACK_STRIDE_IRREG) \ { \ ipcom_memcpy(&tcp_context->ackn_stride, &pkt->data[pointer], 2); \ pointer += 2; \ } /* else ack_stride is a static. Leave the previouse value in the context */ \ \ /* Save the older OPT list and recover if the exctraction of the new OPT failes */ \ ipcom_memset(&tmp_opt_list, 0, sizeof(tmp_opt_list)); \ ipcom_list_init(&tmp_opt_list.opt); \ IPROHC_GET_LIST_TCP_OPT(tmp_opt_list, pkt, pointer, ret_val); \ \ if (ret_val == IPCOM_SUCCESS) \ { \ IPROHC_TCP_D_FREE_OPT_LIST(tcp_context); \ IPROHC_TCP_D_COPY_OPT_LIST(tcp_context, tmp_opt_list); \ } \ else \ { \ IPROHC_TCP_D_FREE_OPT_LIST1(tmp_opt_list); \ } \ } /* *=========================================================================== * IPROHC_FMT_LIST_TCP_OPT *=========================================================================== * Format TCP options from option list in the context for dynamic chain. * * A compressed list of TCP options uses the following encoding: * * 0 1 2 3 4 5 6 7 * +---+---+---+---+---+---+---+---+ * | Reserved |PS | m | * +---+---+---+---+---+---+---+---+ * | XI_1, ..., XI_m | m octets, or m * 4 bits * / --- --- --- ---/ * | : Padding : if PS = 0 and m is odd * +---+---+---+---+---+---+---+---+ * | | * / item_1, ..., item_n / variable * | | * +---+---+---+---+---+---+---+---+ */ #define IPROHC_FMT_LIST_TCP_OPT(tcp_context, pkt, pointer) \ { \ tcp_item_list *ext, *n_ext; \ Ip_u8 opt, buf[41]; /* Max opt size */ \ int i; \ \ if (tcp_context->opt_num == 0) \ { \ /* No options. Format the header */ \ pointer--; \ pkt->data[pointer] = 0; \ goto leave; \ } \ \ ipcom_memset(buf, 0, 41); \ for (ext = IPCOM_LIST_LAST(&tcp_context->opt), i = 0; \ ext; \ ext = n_ext, i++) \ { \ n_ext = IPCOM_LIST_PREV(&ext->item_list); \ opt = ext->index; \ buf[i] = ext->index; \ \ /* Format ITEM chain */ \ if (opt == 1) /* EOL */ \ { \ pointer--; /* One byte for padding */ \ pkt->data[pointer] = tcp_context->pad_ln; \ /* pointer--; */ \ /* pkt->data[pointer] = ext->item[0]; */ \ } \ else if (opt == 0) /* NOP */ \ { \ pointer --; \ pkt->data[pointer] = ext->item[0]; \ } \ else \ { \ pointer = pointer - ext->item_ln; \ ipcom_memcpy(&pkt->data[pointer], ext->item, ext->item_ln); \ } \ } \ \ /* Add padding if needed */ \ if (((tcp_context->opt_num % 2) != 0) && (tcp_context->max_indx <= 7)) \ { \ pointer --; \ pkt->data[pointer] = (Ip_u8) (0x80 | (buf[0] << 4)); \ i = 1; \ } \ else i = 0; \ \ if (tcp_context->max_indx <= 7) \ { \ for (i = i; i < tcp_context->opt_num; i++) \ { \ pointer --; \ pkt->data[pointer] = (Ip_u8)(0x08 | buf[i]); \ i++; \ pkt->data[pointer] = (Ip_u8)(pkt->data[pointer] | 0x80 | (buf[i]<<4)); \ } \ } \ else \ { \ for (i = i; i < tcp_context->opt_num; i++) \ { \ /* Format XI chain */ \ pointer--; \ pkt->data[pointer] = (Ip_u8)(0x80 | buf[i]); \ } \ } \ /* Format the header */ \ pointer--; \ pkt->data[pointer] = (Ip_u8)(tcp_context->opt_num & 0x0F); /* Format m */ \ if (tcp_context->max_indx > 7) \ pkt->data[pointer] = pkt->data[pointer] | 0x10; /* ps m */ \ leave: \ pointer = pointer; \ } /* *=========================================================================== * IPROHC_GET_LIST_TCP_OPT *=========================================================================== * Get TCP options from compressed list in dynamic chain. * * A compressed list of TCP options uses the following encoding: * * * 0 1 2 3 4 5 6 7 * +---+---+---+---+---+---+---+---+ * | Reserved |PS | m | * +---+---+---+---+---+---+---+---+ * | XI_1, ..., XI_m | m octets, or m * 4 bits * / --- --- --- ---/ * | : Padding : if PS = 0 and m is odd * +---+---+---+---+---+---+---+---+ * | | * / item_1, ..., item_n / variable * | | * +---+---+---+---+---+---+---+---+ */ #define IPROHC_GET_LIST_TCP_OPT(tmp_opt_list, pkt, pointer, ret_val) \ { \ tcp_item_list *list_item; \ Ip_u8 ps, item_ln, item_indx, m; \ int i; \ Ip_u8 buf[16]; \ ret_val = IPCOM_SUCCESS; \ \ m = (Ip_u8)(pkt->data[pointer] & 0x0F); \ if (m == 0) \ { \ pointer++; \ goto leave1; \ } \ ps = (Ip_u8)(pkt->data[pointer] & 0x10); \ pointer++; \ \ if (ps) \ { \ for(i = 0; i < m; i++) \ { \ buf[i] = pkt->data[pointer]; \ pointer ++; \ } \ } \ else /* ps is 0, 4 bit items */ \ { \ for(i = 0; i < m; i++) \ { \ buf[i] = (Ip_u8)((pkt->data[pointer] & 0xF0) >> 4); \ i++; \ buf[i] = (Ip_u8)(pkt->data[pointer] & 0x0F); \ pointer ++; \ } \ } \ \ for (i = 0; i < m; i++) \ { \ list_item = ipcom_malloc(sizeof(tcp_item_list)); \ if (list_item == IP_NULL) \ { \ ipcom_free(list_item); \ IPCOM_LOG0(ERR, "IPROHC_GET_LIST_TCP_OPT, out of memory"); \ ret_val = IPCOM_ERR_NO_MEMORY; \ goto leave1; \ } \ ipcom_memset(list_item, 0, sizeof(tcp_item_list)); \ list_item->irreg_c = 1; \ \ if (ps) /* 8 bit index */ \ { \ item_indx = list_item->index = (Ip_u8)(buf[i] & 0x0F); \ if(buf[i] & 0x80) \ { \ if (item_indx == 0) /* NOP */ \ { \ item_ln = 1; \ list_item->item_ln = 1; \ } \ else if(item_indx == 1) /* EOL */ \ { \ tmp_opt_list.pad_ln = pkt->data[pointer]; \ item_ln = 1; \ list_item->item_ln = 1; \ } \ else \ { \ item_ln = list_item->item_ln = pkt->data[pointer + 1]; \ } \ } \ else item_ln = 0; /* No item pressent */ \ } \ else /* 4 bit index */ \ { \ item_indx = list_item->index = (Ip_u8)(buf[i] & 0x07); \ if(buf[i] & 0x8) \ { \ if (item_indx == 0) /* NOP */ \ { \ item_ln = 1; \ list_item->item_ln = 1; \ } \ else if(item_indx == 1) /* EOl */ \ { \ tmp_opt_list.pad_ln = (Ip_u8)(pkt->data[pointer]); \ item_ln = 1; \ list_item->item_ln = 1; \ } \ else \ { \ item_ln = list_item->item_ln = pkt->data[pointer + 1]; \ } \ } \ else item_ln = 0; \ } \ \ if (list_item->item_ln != 0) \ { \ list_item->item = ipcom_malloc(list_item->item_ln); \ if (list_item->item == IP_NULL) \ { \ ipcom_free(list_item->item); \ ipcom_free(list_item); \ IPCOM_LOG0(ERR, "IPROHC_GET_LIST_TCP_OPT, out of memory"); \ ret_val = IPCOM_ERR_NO_MEMORY; \ goto leave1; \ } \ ipcom_memset(list_item->item, 0, list_item->item_ln); \ \ if (item_indx == 0) /* NOP */ \ list_item->item[0] = 1; \ else if(item_indx == 1) /* EOl */ \ list_item->item[0] = 0; \ else \ ipcom_memcpy(list_item->item, &pkt->data[pointer], list_item->item_ln); \ } \ list_item->irreg_c = 0; /* 0 - list item, 1 irregular chain */ \ ipcom_list_insert_last(&tmp_opt_list.opt, &list_item->item_list); \ pointer = pointer + item_ln; \ } \ leave1: \ pointer = pointer; \ } /* *=========================================================================== * IPROHC_UPD_IPID_OFFSET *=========================================================================== * Loop through IP headers and update ip_id offset: ip_id - sn for each * IPv4 header. */ #ifdef IPCOM_USE_INET #define IPROHC_UPD_TCP_IPID_OFFSET(ip_context) \ { \ Iprohc_ip_header *ip_header_; \ \ /* Calcualte IP-ID offset for each IPv4 header : IP-ID - SN */ \ for (ip_header_ = IPCOM_LIST_FIRST(&ip_context->ip_head); \ ip_header_; \ ip_header_ = IPCOM_LIST_NEXT(&ip_header_->ip_list)) \ { \ if (ip_header_->packet_type == ROHC_PKT_IPV4) \ { \ /* An IPv4 packet */ \ ip_header_->offset = ipcom_ntohs(ip_header_->header.ip4.id) - \ ip_context->sn; \ } \ } \ } #else #define IPROHC_UPD_TCP_IPID_OFFSET(ip_context) IP_NOOP #endif /* #ifdef IPCOM_USE_INET */ /* *=========================================================================== * IPROHC_UPD_TCP_STATIC *=========================================================================== * Update TCP static header */ #define IPROHC_UPD_TCP_STATIC(tcp_context, pointer, pkt) \ { \ IPROHC_GET_TCP_STATIC(tcp_context, pointer, pkt) \ } /* *=========================================================================== * IPROHC_UPD_TCP_DYNAMIC *=========================================================================== * Update TCP dynamic header */ #define IPROHC_UPD_TCP_DYNAMIC(tcp_context, pointer, pkt) \ { \ IPROHC_GET_TCP_DYNAMIC1(tcp_context, pointer, pkt) \ } /* *=========================================================================== * IPROHC_RECONSTRUCT_TCP *=========================================================================== * Reconstruct the packet from TCP context */ #define IPROHC_RECONSTRUCT_TCP(tcp_context, pkt) \ { \ Ip_u8 item_ln, offset; \ int lpointer, i; \ tcp_item_list *opt_list, *n_opt_list; \ \ lpointer = pkt->ipstart; \ /* Reconstruct TCP options */ \ for (opt_list = IPCOM_LIST_LAST(&tcp_context->opt), i = 0; \ opt_list; \ opt_list = n_opt_list, i++) \ { \ n_opt_list = IPCOM_LIST_PREV(&opt_list->item_list); \ \ if (opt_list->index == 0) /* NOP */ \ item_ln = 1; \ else if(opt_list->index == 1) /* EOP */ \ { \ item_ln = 1; \ } \ else \ item_ln = opt_list->item_ln; \ \ lpointer = lpointer - item_ln; \ ipcom_memcpy(&pkt->data[lpointer], opt_list->item, item_ln); \ } \ \ /* Add pading if any */ \ if(tcp_context->pad_ln > 0) /* EOP */ \ { \ lpointer = lpointer - tcp_context->pad_ln; \ ipcom_memset(&pkt->data[lpointer], 0, tcp_context->pad_ln); \ } \ \ /* Reconstruct TCP header fields */ \ offset = (Ip_u8)((tcp_context->payload - lpointer + 20)/4); \ tcp_context->offset_res = (Ip_u8)(tcp_context->offset_res & 0x0F); \ tcp_context->offset_res = (Ip_u8)(tcp_context->offset_res | (offset << 4)); \ \ /* Urgent pointer */ \ lpointer -= 2; \ ipcom_memcpy(&pkt->data[lpointer], &tcp_context->uptr, 2); \ /* Checksum */ \ lpointer -= 2; \ ipcom_memcpy(&pkt->data[lpointer], &tcp_context->chksum, 2); \ /* Window */ \ lpointer -= 2; \ ipcom_memcpy(&pkt->data[lpointer], &tcp_context->window, 2); \ /* flags */ \ lpointer -= 1; \ ipcom_memcpy(&pkt->data[lpointer], &tcp_context->flags, 1); \ /* Data offset and reserved bits */ \ lpointer -= 1; \ ipcom_memcpy(&pkt->data[lpointer], &tcp_context->offset_res, 1); \ /* Ack number */ \ lpointer -= 4; \ ipcom_memcpy(&pkt->data[lpointer], &tcp_context->ackn, 4); \ /* Seq number */ \ lpointer -= 4; \ ipcom_memcpy(&pkt->data[lpointer], &tcp_context->sn, 4); \ /* Dst port */ \ lpointer -= 2; \ ipcom_memcpy(&pkt->data[lpointer], &tcp_context->dst_port, 2); \ /* Src port */ \ lpointer -= 2; \ ipcom_memcpy(&pkt->data[lpointer], &tcp_context->src_port, 2); \ \ pkt->ipstart = lpointer; \ } /* *=========================================================================== * IPROHC_ACK_FEEDBACK *=========================================================================== * Process ACK feedback. */ #define IPROHC_TCP_ACK_FEEDBACK(context) \ { \ if (context->state == ROHC_COMP_STATE_IR) \ context->state = ROHC_COMP_STATE_SO; \ \ /* Feedback channel is established */ \ if (context->mode == ROHC_MODE_U) \ context->mode = ROHC_MODE_O; \ } /* *=========================================================================== * IPROHC_TCP_PROCESS_FEEDBACK_OPT *=========================================================================== * Process feedback options. */ #define IPROHC_TCP_PROCESS_FEEDBACK_OPT(context, feedback, pointer, size) \ { \ Ip_u8 opt_type; \ \ while (pointer+1 <= size) \ { \ opt_type = (feedback[pointer] & 0xF0) >> 4; \ switch (opt_type) \ { \ case ROHC_FEEDBACK_OPT_REJ: \ /* Set up reject flag in context, not used */ \ context->reject = IP_TRUE; \ pointer ++; \ break; \ case ROHC_FEEDBACK_OPT_SN_NOT_VALID: \ /* Not using SN in feedback currently */ \ pointer ++; \ break; \ case ROHC_FEEDBACK_OPT_SN: \ /* Not using SN in feedback currently */ \ pointer = (Ip_u8)(pointer + 2); \ break; \ case ROHC_FEEDBACK_OPT_CONTEXT_MEMORY: \ /* Not used */ \ pointer ++; \ break; \ default: \ /* Unknown option skip it and continue parsing next options if any */ \ pointer = (Ip_u8)(pointer + (feedback[pointer] & 0xF) + 1); \ break; \ } \ } \ } /* *=========================================================================== * IPROHC_PROCESS_ACKTYPE *=========================================================================== * Process acktype field from feedback. */ #define IPROHC_TCP_PROCESS_ACKTYPE(context, acktype) \ { \ if (acktype == ROHC_FEEDBACK_ACK) \ { \ IPROHC_TCP_ACK_FEEDBACK(context); \ } \ else if (acktype == ROHC_FEEDBACK_NACK) \ { \ context->state = ROHC_COMP_STATE_IR; \ context->pkt_type = ROHC_PKT_IR_DYN; \ } \ else if (acktype == ROHC_FEEDBACK_STATIC_NACK) \ { \ context->state = ROHC_COMP_STATE_IR; \ context->pkt_type = ROHC_TCP_PKT_IR; \ context->num_ir = 0; \ } \ /* Feedback channel is established */ \ context->mode = ROHC_MODE_O; \ } /* *=========================================================================== * IPROHC_TCP_DECOMP_ALLOWED *=========================================================================== */ #define IPROHC_TCP_DECOMP_ALLOWED(context, pkt_type, msn) \ { \ Iprohc_feedback *feedback = IP_NULL; \ \ if (context->state == ROHC_DECOMP_STATE_NO) \ { \ if (pkt_type != ROHC_TCP_PKT_IR) \ { \ /* Send STATIC-NACK feedback */ \ feedback = iprohc_tcp_create_feedback_2(context, \ ROHC_FEEDBACK_STATIC_NACK, msn); \ } \ } \ else if (context->state == ROHC_DECOMP_STATE_STATIC) \ { \ if ((pkt_type != ROHC_TCP_PKT_IR) && \ (pkt_type != ROHC_PKT_IR_DYN) && \ /* General pkts with 7 bit CRC */ \ (pkt_type != ROHC_TCP_PKT_CO) && \ (pkt_type != ROHC_TCP_PKT_RND_8) && \ (pkt_type != ROHC_TCP_PKT_SEQ_8)) \ { \ /* Send NACK feedback */ \ feedback = iprohc_tcp_create_feedback_2(context, \ ROHC_FEEDBACK_NACK, msn); \ } \ } \ \ if (feedback != IP_NULL) \ { \ IPROHC_ERROUT(IPCOM_ERR_PERMISSION_DENIED); \ } \ } /* *=========================================================================== * IPROHC_TCP_D_MODE_TRANS *=========================================================================== * Process transition at decompressor */ #define IPROHC_TCP_D_MODE_TRANS(d_context, mode) \ { \ if (d_context->mode == ROHC_MODE_U) \ { \ /* U-mode-->O-mode */ \ d_context->mode = ROHC_MODE_O; \ d_context->trans = ROHC_DECOMP_TRANS_DONE; \ } \ } /* *=========================================================================== * IPROHC_TCP_D_F_STATE_TRANS *=========================================================================== * Process state transition at decompressor when a decompression fails */ #define IPROHC_TCP_D_F_STATE_TRANS(d_context, msn, pkt_type) \ { \ Ip_u8 ratio; \ \ /* Calculate the failure ratio */ \ ratio = (Ip_u8)((d_context->num_decompressed * 100) % d_context->num_failed); \ \ if (d_context->state == ROHC_DECOMP_STATE_NO) \ { \ /* Send NACK */ \ (void)iprohc_tcp_create_feedback_2(d_context, \ ROHC_FEEDBACK_STATIC_NACK, msn); \ } \ else if (d_context->state == ROHC_DECOMP_STATE_FULL) \ { \ if (ratio > IPROHC_D_FULL_RATIO) \ { \ d_context->state = ROHC_DECOMP_STATE_STATIC; \ \ /* Send NACK */ \ (void)iprohc_tcp_create_feedback_2(d_context, \ ROHC_FEEDBACK_NACK, msn); \ } \ } \ else if (d_context->state == ROHC_DECOMP_STATE_STATIC) \ { \ if (ratio > IPROHC_D_STATIC_RATIO) \ { \ if((pkt_type == ROHC_TCP_PKT_IR) || \ (pkt_type == ROHC_PKT_IR_DYN)) \ { \ d_context->state = ROHC_DECOMP_STATE_NO; \ /* Send NACK */ \ (void)iprohc_tcp_create_feedback_2(d_context, \ ROHC_FEEDBACK_STATIC_NACK, msn); \ } \ else \ /* Send NACK */ \ (void)iprohc_tcp_create_feedback_2(d_context, \ ROHC_FEEDBACK_NACK, msn); \ } \ } \ } /* *=========================================================================== * IPROHC_TCP_C_ECN_USED *=========================================================================== * Determine if ECN is used */ #define IPROHC_TCP_C_ECN_USED(tcp_context, ip_context) \ { \ Ip_u32 flow; \ \ flow = 0; \ if (ip_context->ip_num == 1) \ { \ base_ip_header = IPCOM_LIST_FIRST(&ip_context->ip_head); \ } \ else /* More then one header */ \ { \ outer_ip_header = IPCOM_LIST_FIRST(&ip_context->ip_head); \ if(outer_ip_header != IP_NULL) \ base_ip_header = IPCOM_LIST_NEXT(&outer_ip_header->ip_list); \ } \ \ /* Determine the ECN_USED flag */ \ if (base_ip_header != IP_NULL /*!(tcp_context->c_flags & ECN_USED)*/) \ { \ IPROHC_TCP_C_ECN_USED_IPV4(tcp_context, base_ip_header); \ IPROHC_TCP_C_ECN_USED_IPV6(tcp_context, base_ip_header); \ } \ } #ifdef IPCOM_USE_INET #define IPROHC_TCP_C_ECN_USED_IPV4(tcp_context, base_ip_header) \ if (base_ip_header->packet_type == ROHC_PKT_IPV4) \ { \ /* Is ECN used? */ \ if (base_ip_header->header.ip4.tos & (Ip_u8)0x03) \ tcp_context->c_flags = (Ip_u8)(tcp_context->c_flags | ECN_USED); \ else \ tcp_context->c_flags = (Ip_u8)(tcp_context->c_flags & (~ECN_USED)); \ } #else #define IPROHC_TCP_C_ECN_USED_IPV4(tcp_context, base_ip_header) IP_NOOP #endif #ifdef IPCOM_USE_INET6 #define IPROHC_TCP_C_ECN_USED_IPV6(tcp_context, base_ip_header) \ if (base_ip_header->packet_type == ROHC_PKT_IPV6) \ { \ flow = ipcom_ntohl(base_ip_header->header.ip6.ver_class_flow); \ flow = flow >> 20; \ if(flow & 0x03) \ tcp_context->c_flags = (Ip_u8)(tcp_context->c_flags | ECN_USED); \ else \ tcp_context->c_flags = (Ip_u8)(tcp_context->c_flags & (~ECN_USED)); \ } #else #define IPROHC_TCP_C_ECN_USED_IPV6(tcp_context, base_ip_header) IP_NOOP #endif /* * **************************************************************************** * Public TYPES **************************************************************************** */ /* **************************************************************************** * LOCAL TYPES **************************************************************************** */ typedef struct tcp_header_struct { /* Source port */ Ip_u16 src_port; /* Destination port */ Ip_u16 dst_port; /* Sequence number */ Ip_u32 sn; /* Acknowledgment number */ Ip_u32 ackn; /* Used to save data_offset, reserved bits */ Ip_u8 offset_res; /* ECN and other flags */ Ip_u8 flags; /* Used to save */ /* Window */ Ip_u16 window; /* Checksum */ Ip_u16 chksum; /* Urgent pointer */ Ip_u16 uptr; } tcp_header; /* *=========================================================================== * tcp_item_list *=========================================================================== * This is the TCP reference list structure */ typedef struct tcp_item_list_struct { Ipcom_list item_list; Ip_u8 index; Ip_u8 item_ln; Ip_u8 irreg_c; /* 1 - Compressed in irregular chain */ Ip_u8 *item; }tcp_item_list; typedef struct tcp_opt_list_struct { /* TCP options as index/item list */ Ip_u8 item_gen_uindex[GEN_LEN]; Ip_u8 offset_res; Ip_u8 pad_ln; /* Padding length */ Ip_u8 opt_num; Ip_u8 max_indx; Ipcom_list opt; /* tcp_item_list */ }tcp_opt_list; /* *=========================================================================== * Iprohc_c_tcp_context_struct *=========================================================================== * ROHC compression TCP profile specific context structure * All TCP header fields are in network order */ typedef struct Iprohc_c_tcp_context_struct { /* All TCP header fields are in network order */ /* Source port */ Ip_u16 src_port; /* Destination port */ Ip_u16 dst_port; /* Sequence number */ Ip_u32 sn; /* Acknowledgment number */ Ip_u32 ackn; /* Used to save data_offset, reserved bits */ Ip_u8 offset_res; /* ECN and othe flags */ Ip_u8 flags; /* Window */ Ip_u16 window; /* Checksum */ Ip_u16 chksum; /* Urgent pointer */ Ip_u16 uptr; int payload; /* Pointer to TCP payload */ int payload_ln; /* Payload Length */ /* Previouse sequence number in host order */ Ip_u32 sn_prev; /* Previouse acknowledgment number in host order */ Ip_u32 ackn_prev; /* Controll fileds ecn and msn. Can be updated if 7 bit CRC is used */ /* * Controll fileds. Can be updated if 7 bit CRC is used. * 1 - the val is used. O - the val is not used. * ecn_used; * ack_zero; * urp_zero; * ack_stride_flag; */ Ip_u8 c_flags; Ip_bool scailing_used; Ip_u32 sec_num_scaled; Ip_u32 ack_num_scaled; Ip_u16 ackn_stride; Ip_u16 msn; /* In host order */ /* IP flags * Outer IP header * outer_dscp_irreg; * outer_ip_ecn_flags_irreg; * ttl_irregular_chain_flag; * Inner IP header * dscp_irreg; * ttl_hlim_irreg; * ecn_present; */ Ip_u8 ip_flags; /* TCP header flags * * urg_ptr_irreg; * window_irreg; * ack_stride_irreg; * ackn_not_present; * sn_not_present; * tcp_res_flags_irreg; * tcp_ecn_flags_irreg; */ Ip_u8 tcp_flags; /* TCP options index/item list */ Ip_bool list_present; Ipcom_list list; /* tcp_item_list */ /* Values: 0 - option is not used. 1 - option is used */ Ip_u8 item_gen_uindex[GEN_LEN]; Ip_u8 pad_ln; /* Padding length */ Ip_u8 opt_num; Ip_u8 max_indx; #ifdef IPROHC_USE_TEST #ifdef IPROHC_TCP_IP_SIMULATED_IPID Ip_u16 simulated_ip_id; #endif #endif Ipcom_list opt; /* tcp_item_list */ } Iprohc_c_tcp_context; /* *=========================================================================== * Iprohc_d_tcp_context_struct *=========================================================================== * ROHC decompression TCP profile specific context structure * All TCP header fields are in network order */ typedef struct Iprohc_d_tcp_context_struct { /* Source port */ Ip_u16 src_port; /* Destination port */ Ip_u16 dst_port; /* Sequence number */ Ip_u32 sn; /* Acknowledgment number */ Ip_u32 ackn; /* Used to save data_offset, reserved bits */ Ip_u8 offset_res; /* ECN and othe flags */ Ip_u8 flags; /* Window */ Ip_u16 window; /* Checksum */ Ip_u16 chksum; /* Urgent pointer */ Ip_u16 uptr; int payload; /* Pointer to TCP payload */ int payload_ln; /* Payload Length */ /* * Controll fileds. Can be updated if 7 bit CRC is used. * 1 - the val is used. O - the val is not used. * ecn_used; * ack_zero; * urp_zero; * ack_stride_flag; */ Ip_u8 c_flags; Ip_u8 tcp_flags; Ip_bool scailing_used; Ip_u32 sec_num_scaled; Ip_u32 ack_num_scaled; Ip_u16 ackn_stride; Ip_u16 msn; /* In host order */ /* Values: 0 - option is not used. 1 - option is used */ Ip_u8 item_gen_uindex[GEN_LEN]; /* TCP options as index/item list */ Ip_u8 pad_ln; /* Padding length */ Ip_u8 opt_num; Ipcom_list opt; /* tcp_item_list */ } Iprohc_d_tcp_context; /* *=========================================================================== * Iprohc_c_tcp_ip_context_struct *=========================================================================== * ROHC compression TCP_IP profile specific context structure */ typedef struct Iprohc_c_tcp_ip_context_struct { /* IPvX specific context */ Iprohc_c_ip_context *ip_context; /* TCP sepecific context */ Iprohc_c_tcp_context *tcp_context; } Iprohc_c_tcp_ip_context; /* *=========================================================================== * Iprohc_d_tcp_ip_context_struct *=========================================================================== * ROHC decompression TCP_IP profile specific context structure */ typedef struct Iprohc_d_tcp_ip_context_struct { /* IPvX specific context */ Iprohc_d_ip_context *ip_context; /* TCP sepecific context */ Iprohc_d_tcp_context *tcp_context; } Iprohc_d_tcp_ip_context; /* **************************************************************************** * GLOBAL FUNCTIONS **************************************************************************** */ /* Profile registration/deregistration functions */ IP_PUBLIC Ip_err iprohc_profile_tcp_ip_register(void); IP_PUBLIC Ip_err iprohc_tcp_ip_deregister(void); /* Profile specific compression functions */ IP_PUBLIC Ip_err iprohc_tcp_ip_c_find_context(Iprohc_compressor *comp, Ipcom_pkt *pkt, Iprohc_c_context **c_context); IP_PUBLIC Iprohc_c_context * iprohc_tcp_ip_c_create_context(Iprohc_compressor *comp, Ipcom_pkt *pkt); IP_PUBLIC Ip_err iprohc_tcp_ip_c_del_context(Iprohc_c_context *context); IP_PUBLIC Ip_err iprohc_tcp_ip_c_process_feedback(Iprohc_c_context *context, Ip_u8 *feedback, Ip_u8 size); IP_PUBLIC Ip_err iprohc_tcp_ip_c_compress(Iprohc_c_context *context, Ipcom_pkt *pkt); IP_PUBLIC void iprohc_tcp_ip_c_print_context(Iprohc_c_context *context); /* Profile specific decompression functions */ IP_PUBLIC Iprohc_d_context * iprohc_tcp_ip_d_find_context(Iprohc_decompressor *decomp, Ipcom_pkt *pkt); IP_PUBLIC Iprohc_d_context * iprohc_tcp_ip_d_create_context(Iprohc_decompressor *decomp, Ipcom_pkt *pkt); IP_PUBLIC Ip_err iprohc_tcp_ip_d_del_context(Iprohc_d_context *context); IP_PUBLIC void iprohc_tcp_ip_d_print_context(Iprohc_d_context *context); IP_PUBLIC Ip_err iprohc_tcp_ip_d_decompress(Iprohc_d_context *context, Ipcom_pkt *pkt); IP_PUBLIC Ip_err iprohc_c_update_tcp_ip_context(Iprohc_c_context *context, Ipcom_pkt *pkt, Ip_u8 *pkt_type); #ifdef __cplusplus } #endif #endif /* #ifndef IPROHC_UDP_IP_H */ /* **************************************************************************** * END OF FILE **************************************************************************** */