2641 lines
82 KiB
C
2641 lines
82 KiB
C
/* 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 <ipcom_tags.h>
|
|
#include <ipcom_type.h>
|
|
#include <ipcom_list.h>
|
|
|
|
|
|
#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
|
|
****************************************************************************
|
|
*/
|
|
|