/* iprohc_udp_ip.c - ROHC UDP IP profile routines */ /* * 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 -------------------- 01s,08aug13,j_y Clean low impact code review defects 01r,30jul13,j_y Clean medium impact code review defects 01q,15may12,ggz Fix for defect WIND00350062 01e,20oct11,ggz Fix for defect WIND00312450 01d,12apr10,ggz Support 64bit 01c,27mar10,ggz Resolve coverity warnings 01b,15mar10,ggz Remove ip code from comp. context creation function 01a,01dec09,ggz Created. Incorporated IP profile source code */ /* **************************************************************************** * DESCRIPTION **************************************************************************** */ /* **************************************************************************** * CONFIGURATION **************************************************************************** */ #include "iprohc_config.h" /* **************************************************************************** * INCLUDE FILES **************************************************************************** */ #define IPCOM_USE_CLIB_PROTO /* ipcom */ #include #include #include #include #include #include #include #include #include #include /* iprohc */ #include "iprohc.h" #include "iprohc_udp_ip.h" #include "iprohc_format.h" #include "iprohc_parser.h" /* **************************************************************************** * DEFINES **************************************************************************** */ IP_EXTERN Iprohc_data iprohc; /* This is a compile flag, turning on it will build debug message into image */ #undef ROHC_DEBUG /* **************************************************************************** * LOCAL TYPES **************************************************************************** */ /* **************************************************************************** * LOCAL Data **************************************************************************** */ /* **************************************************************************** * LOCAL PROTOTYPES **************************************************************************** */ /* Compressor functions */ IP_STATIC Ip_err iprohc_udp_c_init(Iprohc_c_udp_context *udp_context); IP_STATIC Ip_err iprohc_fmt_udp_ip_ir(Iprohc_c_context *context, Ipcom_pkt *pkt); IP_STATIC Ip_err iprohc_fmt_udp_ip_irdyn(Iprohc_c_context *context, Ipcom_pkt *pkt); IP_STATIC Ip_err iprohc_fmt_udp_ip_general(Iprohc_c_context *context, Ipcom_pkt *pkt); IP_STATIC Ip_err iprohc_udp_c_get_header(Ipcom_pkt *pkt, udp_header *header); /* De-compressor functions */ IP_STATIC Ip_err iprohc_udp_d_init(Iprohc_d_udp_context *udp_context); IP_STATIC Ip_err iprohc_decomp_udp_ip_ir(Iprohc_d_context *context, Ipcom_pkt *pkt, Ip_u8 type_data); IP_STATIC Ip_err iprohc_decomp_udp_ip_irdyn(Iprohc_d_context *context, Ipcom_pkt *pkt, Ip_u8 type_data); IP_STATIC Ip_err iprohc_decomp_udp_ip_general(Iprohc_d_context *context, Ipcom_pkt *pkt, Ip_u8 pkt_type, Ip_u8 type_data); IP_STATIC Ip_err iprohc_d_copy_udp_context(Iprohc_d_udp_context **to_context, Iprohc_d_udp_context *from_context); IP_STATIC Ip_err iprohc_d_udp_ip_crc_validate(Iprohc_d_context *context, Iprohc_d_ip_context *backup_context, Iprohc_d_udp_context *backup_udp_context, Ipcom_pkt *pkt, Ip_u8 pkt_type, Ip_u8 crc, Ip_u8 crc_bits, int mode, Ip_bool udp_chksum); IP_STATIC Ip_err iprohc_del_udp_ip_context(void *context, Ip_bool is_comp); IP_STATIC Ip_err iprohc_del_udp_context(void *context, Ip_bool is_comp); /* **************************************************************************** * LOCAL FUNCTIONS **************************************************************************** */ /* *=========================================================================== * iprohc_del_udp_ip_context *=========================================================================== * Description: Delete a UDP_IP profile specific compression/decompression * context. * Parameters: * Returns: * */ IP_STATIC Ip_err iprohc_del_udp_ip_context(void *context, Ip_bool is_comp) { Ip_err retval = IPCOM_SUCCESS; void *ip_context, *udp_context; #ifdef ROHC_DEBUG ipcom_printf("Enter iprohc_del_udp_ip_context\n"); #endif if(is_comp == IP_TRUE) { ip_context = ((Iprohc_c_udp_ip_context *)context)->ip_context; udp_context = ((Iprohc_c_udp_ip_context *)context)->udp_context; } else { ip_context = ((Iprohc_d_udp_ip_context *)context)->ip_context; udp_context = ((Iprohc_d_udp_ip_context *)context)->udp_context; } /* Delete ip context */ if(ip_context) retval = iprohc_del_ip_context(ip_context, is_comp); /* Delete UDP context */ if(udp_context) (void) iprohc_del_udp_context(udp_context, is_comp); return retval; } /* *=========================================================================== * iprohc_d_copy_udp_context *=========================================================================== * Description: Make a copy of a UDP profile decompression context. * Parameters: * Returns: * */ IP_STATIC Ip_err iprohc_d_copy_udp_context(Iprohc_d_udp_context **to_context, Iprohc_d_udp_context *from_context) { Ip_err retval = IPCOM_SUCCESS; #ifdef ROHC_DEBUG ipcom_printf("Enter iprohc_d_copy_udp_context\n") ; #endif *to_context = (Iprohc_d_udp_context *) ipcom_malloc(sizeof(Iprohc_d_udp_context)); if (*to_context == IP_NULL) { retval = IPCOM_ERR_NO_MEMORY; IPCOM_LOG0(ERR,"iprohc_d_copy_udp_context, out of memory(to context)"); } else ipcom_memcpy(*to_context, from_context, sizeof(Iprohc_d_udp_context)); return retval; } /* *=========================================================================== * iprohc_d_udp_ip_crc_validate *=========================================================================== * Description: CRC validation of the re-constructed UDP_IP headers, decompressor * context state and mode transition, and send out feedbacks. * Parameters: * Returns: * */ IP_STATIC Ip_err iprohc_d_udp_ip_crc_validate(Iprohc_d_context *context, Iprohc_d_ip_context *backup_context, Iprohc_d_udp_context *backup_udp_context, Ipcom_pkt *pkt, Ip_u8 pkt_type, Ip_u8 crc, Ip_u8 crc_bits, int mode, Ip_bool udp_chksum) { Ip_err retval = IPCOM_SUCCESS; Iprohc_feedback *feedback = IP_NULL; Ip_u8 calc_crc = 0; Iprohc_d_udp_context *udp_context; udp_context = ((Iprohc_d_udp_ip_context *) context->profile_context)->udp_context; if (udp_chksum != IP_TRUE) { retval = IPCOM_ERR_BAD_PACKET; goto next; } if (crc_bits != 0) { /* CRC validation of the re-constructed packet */ if (crc_bits == 8) { /* 8-bit CRC calculation */ calc_crc = iprohc_crc8(&pkt->data[pkt->ipstart], udp_context->payload - pkt->ipstart); } else if (crc_bits == 7) { /* 7-bit CRC calculation */ calc_crc = iprohc_crc7(&pkt->data[pkt->ipstart], udp_context->payload - pkt->ipstart); } else if (crc_bits == 3) { /* 3-bit CRC calculation */ calc_crc = iprohc_crc3(&pkt->data[pkt->ipstart], udp_context->payload - pkt->ipstart); } /* Compare the calculated CRC with the CRC carried in the packet */ if (calc_crc != crc) retval = IPCOM_ERR_BAD_PACKET; } next: /* Process mode transition */ IPROHC_D_MODE_TRANS(context, mode); if (retval == IPCOM_SUCCESS) { /* The packet is successfully decompressed */ /* Increase the success counter */ context->num_decompressed ++; /* State transits to Full Context: RFC 3095, 5.3.2.1 */ context->state = ROHC_DECOMP_STATE_FULL; /* send ACK feedback for an IR/IR-DYN/type-2 packet */ if ((pkt_type == ROHC_PKT_IR) || (pkt_type == ROHC_PKT_IR_DYN) || (pkt_type == ROHC_PKT_TYPE_2)) { if (context->trans == ROHC_DECOMP_TRANS_DONE) /* Generate a FEEDBACK-1 feedback */ feedback = iprohc_create_feedback_1(context, backup_context->sn); else /* Generate a FEEDBACK-2 feedback */ feedback = iprohc_create_feedback_2(context, ROHC_FEEDBACK_ACK, backup_context->sn); } /* Free the backup ip context */ iprohc_del_ip_context((void *)backup_context, IP_FALSE); /* Free the backup udp context */ iprohc_del_udp_context((void *)backup_udp_context, IP_FALSE); if ((feedback != IP_NULL) && (context->trans == ROHC_DECOMP_TRANS_INITIATED)) { /* Feedback pkts that initiate the mode transition must */ /* carry CRC option */ iprohc_feedback_add_option(feedback, ROHC_FEEDBACK_OPT_CRC, 1, 0); } } else { /* The packet decompression is failed */ /* Free the updated ip context */ iprohc_del_ip_context(((Iprohc_d_udp_ip_context *) context->profile_context)->ip_context, IP_FALSE); /* Free the apdated udp context */ iprohc_del_udp_context(((Iprohc_d_udp_ip_context *) context->profile_context)->udp_context, IP_FALSE); /* Restore the backuped previous context */ ((Iprohc_d_udp_ip_context *) context->profile_context)->ip_context = (void *)backup_context; ((Iprohc_d_udp_ip_context *) context->profile_context)->udp_context = (void *)backup_udp_context; /* Increase the failed counter */ context->num_failed ++; IPROHC_D_F_STATE_TRANS(context, backup_context->sn); } return retval; } /* *=========================================================================== * iprohc_fmt_udp_ip_ir *=========================================================================== * Description: Format an UDP_IP profile IR packet. * * RFC 3095, 5.7.7.1, 5.11.1 Basic structure of the IR packet * * --------------------------- * | Add-CID octet | if for small CIDs and CID != 0 * --------------------------- * | 1 1 1 1 1 1 0 | D | * --------------------------- * | | * / 0-2 octets of CID info / 1-2 octets if for large CIDs * | | * --------------------------- * | Profile | 1 octet * --------------------------- * | CRC | 1 octet * --------------------------- * | | * | Static chain | variable length * | | * --------------------------- * | | * | Dynamic chain | present if D = 1, variable length * | | * --------------------------- * | Payload | variable length * | | * --------------------------- * * Parameters: * Returns: * */ IP_STATIC Ip_err iprohc_fmt_udp_ip_ir(Iprohc_c_context *context, Ipcom_pkt *pkt) { Ip_err retval = IPCOM_SUCCESS; Iprohc_c_ip_context *ip_context; Iprohc_c_udp_context *udp_context; int pointer; Ip_u16 data; Ip_bool has_dynamic = IP_FALSE; Ip_u8 num_h, calc_crc; #ifdef ROHC_DEBUG ipcom_printf("Enter iprohc_fmt_udp_ip_ir\n"); #endif ip_context = ((Iprohc_c_udp_ip_context *) context->profile_context)->ip_context; udp_context = ((Iprohc_c_udp_ip_context *) context->profile_context)->udp_context; /* Init pointer to point to payload data */ pointer = udp_context->payload; num_h = ip_context->ip_num; /* 8-bit CRC calculation before compress/re-format the packet */ calc_crc = iprohc_crc8(&pkt->data[pkt->ipstart], udp_context->payload - pkt->ipstart); /* Format SN, and save SN in WLSB structure */ pointer -= 2; data = ip_htons(ip_context->sn); ipcom_memcpy(&pkt->data[pointer], &data, 2); #ifdef IPROHC_WLSB_LSB iprohc_cmp_wlsb_add_val((cmp_wslb_cast *)&ip_context->sn_wlsb, data, data); #ifdef ROHC_DEBUG ipcom_printf("iprohc_fmt_udp_ip_ir, wslb sn %d\n", data); #endif /* ROHC_DEBUG */ #endif /* IPROHC_WLSB_LSB */ /* Format UDP dynamic chain */ IPROHC_FMT_UDP_DYNAMC(udp_context, pointer, has_dynamic, pkt); /* Format IP dynamic chain */ IPROHC_FMT_IP_DYNAMC(ip_context, pointer, pkt, has_dynamic, num_h); /* Format UDP static chain */ IPROHC_FMT_UDP_STATIC(udp_context, pointer, pkt); /* Format IP static chain */ IPROHC_FMT_IP_STATIC(ip_context, pointer, pkt); /* Format CRC */ pointer --; pkt->data[pointer] = calc_crc; /* Format profile ID */ pointer --; pkt->data[pointer] = ROHC_PROFILE_UDP_IP; /* Format large CID */ if (iprohc.large_cid) { Ip_u8 cid_size; Ip_u16 cid = context->cid; /* * Encode large CID according to RFC 3095, section 4.5.6 * RFC 3095, section 5.2.2: If the first bit is 0, the CID uses * one octet. If the first bit is 1, the CID uses two octets. */ if (context->cid < 128) /* 0 < cid < 128 (0x80) */ pointer --; else /* 127 (0x7F) < cid < 16384 (0x4000) */ pointer -= 2; IPROHC_ENCODE_LARGE_CID(pkt->data, pointer, cid, cid_size); } /* Format IR packet type: 1111110D, D=1 indicates dynamic chain exists */ pointer --; if (has_dynamic) pkt->data[pointer] = 0xFD; /* Format small CID */ if (!iprohc.large_cid) { pointer --; pkt->data[pointer] = 0xE0; pkt->data[pointer] = (Ip_u8)(pkt->data[pointer] | ((Ip_u8)context->cid & 0x0F)); } /* Move ipstart and start pointers in Ipcom_pkt */ pkt->ipstart = pkt->start = pointer; return retval; } /* *=========================================================================== * iprohc_fmt_udp_ip_irdyn *=========================================================================== * Description: Format an UDP_IP profile IR-DYN packet. * * RFC 3095, 5.7.7.2, 5.11.1 Basic structure of the IR-DYN packet * * --------------------------- * | Add-CID octet | if for small CIDs and CID != 0 * --------------------------- * | 1 1 1 1 1 0 0 0 | * --------------------------- * | | * / 0-2 octets of CID info / 1-2 octets if for large CIDs * | | * --------------------------- * | Profile | 1 octet * --------------------------- * | CRC | 1 octet * --------------------------- * | | * | Dynamic chain | variable length * | | * --------------------------- * | | * | Payload | variable length * | | * --------------------------- * * Parameters: * Returns: * */ IP_STATIC Ip_err iprohc_fmt_udp_ip_irdyn(Iprohc_c_context *context, Ipcom_pkt *pkt) { Ip_err retval = IPCOM_SUCCESS; Iprohc_c_ip_context *ip_context; Iprohc_c_udp_context *udp_context; int pointer; Ip_u16 data; Ip_bool has_dynamic = IP_FALSE; Ip_u8 num_h, calc_crc; #ifdef ROHC_DEBUG ipcom_printf("Enter iprohc_fmt_udp_ip_irdyn\n"); #endif ip_context = ((Iprohc_c_udp_ip_context *)context->profile_context)->ip_context; udp_context = ((Iprohc_c_udp_ip_context *)context->profile_context)->udp_context; /* Init pointer to point to payload data */ pointer = udp_context->payload; num_h = ip_context->ip_num; /* 8-bit CRC calculation before compress/re-format the packet */ calc_crc = iprohc_crc8(&pkt->data[pkt->ipstart], udp_context->payload - pkt->ipstart); /* Format SN, and save SN in WLSB structure */ pointer -= 2; data = ip_htons(ip_context->sn); ipcom_memcpy(&pkt->data[pointer], &data, 2); #ifdef IPROHC_WLSB_LSB iprohc_cmp_wlsb_add_val((cmp_wslb_cast *)&ip_context->sn_wlsb, data, data); #ifdef ROHC_DEBUG ipcom_printf("iprohc_fmt_udp_ip_irdyn, wslb sn %d\n", data); #endif /* ROHC_DEBUG */ #endif /* IPROHC_WLSB_LSB */ /* Format UDP dynamic chain */ IPROHC_FMT_UDP_DYNAMC(udp_context, pointer, has_dynamic, pkt); /* Format IP dynamic chain */ IPROHC_FMT_IP_DYNAMC(ip_context, pointer, pkt, has_dynamic, num_h); /* Format CRC */ pointer --; pkt->data[pointer] = calc_crc; /* Format profile ID */ pointer --; pkt->data[pointer] = ROHC_PROFILE_UDP_IP; /* Format large CID */ if (iprohc.large_cid) { Ip_u8 cid_size; Ip_u16 cid = context->cid; /* * Encode large CID according to RFC 3095, section 4.5.6 * RFC 3095, section 5.2.2: If the first bit is 0, the CID uses * one octet. If the first bit is 1, the CID uses two octets. */ if (context->cid < 128) /* 0 < cid < 128 (0x80) */ pointer --; else /* 127 (0x7F) < cid < 16384 (0x4000) */ pointer -= 2; IPROHC_ENCODE_LARGE_CID(pkt->data, pointer, cid, cid_size); } /* Format IR-DYN packet type: 11111000 */ pointer --; pkt->data[pointer] = 0xF8; /* Format small CID */ if (!iprohc.large_cid) { pointer --; pkt->data[pointer] = 0xE0; pkt->data[pointer] = (Ip_u8)(pkt->data[pointer] | ((Ip_u8)context->cid & 0x0F)); } /* Move ipstart and start pointers in Ipcom_pkt */ pkt->ipstart = pkt->start = pointer; return retval; } /* *=========================================================================== * iprohc_fmt_udp_ip_general *=========================================================================== * Description: Format an UDP_IP profile general compressed packet. * * RFC 3843, 3.6 General format for a compressed header * * ------------------------------ * | Add-CID octet | if for small CIDs and CID != 0 * ------------------------------ * | first octet of base header | (with type indication) * ------------------------------ * | | * / 0-2 octets of CID info / 1-2 octets if for large CIDs * | | * ------------------------------ * | remainder of base header | variable number of bits * ------------------------------ * : : * | Extension | extension, if X = 1 in base header * : : * ------------------------------ * : : * | IP-ID of outer IPv4 header | 2 octets, if value (RND2) = 1 * : : * ------------------------------ * / AH data for outer list / variable (not supported) * ------------------------------ * : : * | GRE checksum | 2 octets, if GRE flag C=1(not supported) * : : * ------------------------------ * : : * | IP-ID of inner IPv4 header | 2 octets, if value (RND) = 1 * : : * ------------------------------ * / AH data for inner list / variable (not supported) * ------------------------------ * : : * | GRE checksum | 2 octets, if GRE flag C=1(not supported) * : : * ------------------------------ * : : * | UDP checksum | 2 octets if context(UDP Checksum) != 0 * : : * ------------------------------ * * Parameters: * Returns: * */ IP_STATIC Ip_err iprohc_fmt_udp_ip_general(Iprohc_c_context *context, Ipcom_pkt *pkt) { Ip_err retval = IPCOM_SUCCESS; Iprohc_ip_header *ip_header1, *ip_header2; Iprohc_c_ip_context *ip_context; Iprohc_c_udp_context * udp_context; int pointer; void *header1 = IP_NULL, *header2 = IP_NULL; Ip_u8 base_header[2]; Ip_u8 crc = 0, size; Ip_u32 sn_e; Ip_bool has_dynamic = IP_FALSE; #ifdef IPROHC_WLSB_LSB Ip_u8 enc_val_ln; #endif #ifdef ROHC_DEBUG ipcom_printf("Enter iprohc_fmt_udp_ip_general\n"); #endif ip_context = ((Iprohc_c_udp_ip_context *) context->profile_context)->ip_context; udp_context = ((Iprohc_c_udp_ip_context *) context->profile_context)->udp_context; /* Init pointer to point to payload data */ pointer = udp_context->payload; sn_e = ip_htons(ip_context->sn); /* Calculate CRC before the packet is compressed/reformatted */ switch (context->pkt_type) { case ROHC_PKT_TYPE_0: if (context->mode == ROHC_MODE_R) { /* Calculate 7-bit CRC */ crc = iprohc_crc7(&pkt->data[pkt->ipstart], udp_context->payload - pkt->ipstart); } else { /* Calculate 3-bit CRC */ crc = iprohc_crc3(&pkt->data[pkt->ipstart], udp_context->payload - pkt->ipstart); } break; case ROHC_PKT_TYPE_1: if (context->mode != ROHC_MODE_R) { /* Calculate 3-bit CRC */ crc = iprohc_crc3(&pkt->data[pkt->ipstart], udp_context->payload - pkt->ipstart); } break; case ROHC_PKT_TYPE_2: /* Calculate 7-bit CRC */ crc = iprohc_crc7(&pkt->data[pkt->ipstart], udp_context->payload - pkt->ipstart); break; } #ifdef ROHC_DEBUG ipcom_printf("iprohc_fmt_udp_ip_general, pkt_type %s, mode %s\n", iprohc_pkt_type(context->pkt_type), iprohc_context_mode(context->mode)); #endif /* Init ROHC IP header1 (outer) and header2 (inner) */ ip_header1 = IPCOM_LIST_FIRST(&ip_context->ip_head); if(ip_header1 == IP_NULL) return IPCOM_ERR_INVALID_ARG; ip_header2 = IPCOM_LIST_NEXT(&ip_header1->ip_list); /* Init header1 */ if (ip_header1->packet_type == ROHC_PKT_IPV4) { #ifdef IPCOM_USE_INET header1 = (void *)&(ip_header1->header.ip4); #endif /* IPCOM_USE_INET */ } else if (ip_header1->packet_type == ROHC_PKT_IPV6) { #ifdef IPCOM_USE_INET6 header1 = (void *)&(ip_header1->header.ip6); #endif /* IPCOM_USE_INET6 */ } if(header1 == IP_NULL) return IPCOM_ERR_INVALID_ARG; /* Init header 2 */ if (ip_header2 && ip_header2->packet_type == ROHC_PKT_IPV4) { #ifdef IPCOM_USE_INET header2 = (void *)&(ip_header2->header.ip4); #endif /* IPCOM_USE_INET */ } else if (ip_header2 && ip_header2->packet_type == ROHC_PKT_IPV6) { #ifdef IPCOM_USE_INET6 header2 = (void *)&(ip_header2->header.ip6); #endif /* IPCOM_USE_INET6 */ } /* Add UDP checksum to the packet only if checksum is used */ if (udp_context->use_checksum == IP_TRUE) IPROHC_FMT_UDP_DYNAMC(udp_context, pointer, has_dynamic, pkt); /* Add dynamic chains for additional IP headers */ if (ip_context->ip_num > 2) { Ip_u8 num_h = (Ip_u8)(ip_context->ip_num - 2); IPROHC_FMT_IP_DYNAMC(ip_context, pointer, pkt, has_dynamic, num_h); } #ifdef IPCOM_USE_INET /* Add IP-ID of inner IPv4 header: ip_header2 */ if (ip_header2 && (ip_header2->packet_type == ROHC_PKT_IPV4) && ip_header2->rnd) { Ipcom_ip_header *ip4_header = &(ip_header2->header.ip4); pointer -= 2; ipcom_memcpy(&pkt->data[pointer], &ip4_header->id, 2); #ifdef ROHC_DEBUG ipcom_printf("iprohc_fmt_udp_ip_general, inner IP-ID: %x\n", ip4_header->id); #endif } #endif /* IPCOM_USE_INET */ #ifdef IPCOM_USE_INET /* Add IP-ID of outer IPv4 header: ip_header1 */ if (ip_header1 && (ip_header1->packet_type == ROHC_PKT_IPV4) && ip_header1->rnd) { Ipcom_ip_header *ip4_header = &(ip_header1->header.ip4); pointer -= 2; ipcom_memcpy(&pkt->data[pointer], &ip4_header->id, 2); #ifdef ROHC_DEBUG ipcom_printf("iprohc_fmt_udp_ip_general, outer IP-ID: %x\n", ip4_header->id); #endif } #endif /* IPCOM_USE_INET */ /* Add extension */ /* RFC 3095, section 5.7.5, extension formats */ /* Inner IP header (ip2) correspond to the inner IP header if there */ /* are two, and the single IP header otherwise. */ /* Outer IP header (ip1) is always zero unless the context contains */ /* two IP headers. */ if (context->ext_type != ROHC_EXT_NO_EXT) iprohc_fmt_extension(pkt, &pointer, context->ext_type, header2?header1:IP_NULL, header2?header2:header1, ip_context->sn, context->decline_mode_trans?ROHC_MODE_C:context->mode, (Ip_u8)(ip_header2?ip_header1->header_flags:0), (Ip_u8)(ip_header2?ip_header2->header_flags:ip_header1->header_flags)); #ifdef IPROHC_WLSB_LSB /* Encode SN to 4 bits */ if (iprohc_cmp_wlsb_encode_val((cmp_wslb_cast *)&ip_context->sn_wlsb, (Ip_u32)ip_htons(ip_context->sn), &sn_e, &enc_val_ln) != IP_TRUE) { IPCOM_LOG0(ERR,"iprohc_fmt_udp_ip_general, failed to encode SN"); IPROHC_ERROUT(IPCOM_ERR_FAILED); } #ifdef ROHC_DEBUG ipcom_printf("iprohc_fmt_udp_ip_general: encoded sn %u, context n_sn %u\n", sn_e, ip_htons(ip_context->sn)); #endif /* Save SN to WLSB structure */ iprohc_cmp_wlsb_add_val((cmp_wslb_cast *)&ip_context->sn_wlsb, ip_htons(ip_context->sn), ip_htons(ip_context->sn)); #endif /* IPROHC_WLSB_LSB */ /* Format base header */ size = iprohc_fmt_base_header(base_header, context, header1, (Ip_u8)sn_e, crc); /* Add the second octet of of base header */ if (size == 2) { pointer --; pkt->data[pointer] = base_header[1]; } /* Add large CID */ if (iprohc.large_cid) { Ip_u8 cid_size; Ip_u16 cid = context->cid; /* * Encode large CID according to RFC 3095, section 4.5.6 * RFC 3095, section 5.2.2: If the first bit is 0, the CID uses * one octet. If the first bit is 1, the CID uses two octets. */ if (context->cid < 128) /* 0 < cid < 128 (0x80) */ pointer --; else /* 127 (0x7F) < cid < 16384 (0x4000) */ pointer -= 2; IPROHC_ENCODE_LARGE_CID(pkt->data, pointer, cid, cid_size); } /* Add the first octet of base header */ pointer --; pkt->data[pointer] = base_header[0]; /* Format small CID */ if (!iprohc.large_cid) { pointer --; pkt->data[pointer] = 0xE0; pkt->data[pointer] = (Ip_u8)(pkt->data[pointer] | ((Ip_u8)context->cid & 0x0F)); } /* Move ipstart and start pointers in Ipcom_pkt */ pkt->ipstart = pkt->start = pointer; #ifdef IPROHC_WLSB_LSB errout: #endif /* IPROHC_WLSB_LSB */ #ifdef ROHC_DEBUG ipcom_printf("iprohc_fmt_udp_ip_general (end), retval %d\n", retval); /* iprohc_print_pkt(pkt); */ #endif return retval; } /* *=========================================================================== * iprohc_decomp_udp_ip_ir *=========================================================================== * Description: Decompress an UDP_IP profile IR packet. * * Passed in packet is an IP profile IR Body packet, in format: * RFC 3095, 5.7.7.1, 5.11.1 Basic structure of the IR packet * * --------------------------- * | Profile | 1 octet * --------------------------- * | CRC | 1 octet * --------------------------- * | | * | Static chain | variable length * | | * --------------------------- * | | * | Dynamic chain | present if D = 1, variable length * | | * --------------------------- * | | * | Payload | variable length * | | * --------------------------- * * Parameters: * Returns: * */ IP_STATIC Ip_err iprohc_decomp_udp_ip_ir(Iprohc_d_context *context, Ipcom_pkt *pkt, Ip_u8 type_data) { Ip_err retval = IPCOM_SUCCESS; Iprohc_d_ip_context *ip_context, *backup_context; Iprohc_d_udp_context *udp_context, *backup_udp_context; Ip_u8 crc; int pointer = pkt->ipstart, mode = -1; #ifdef ROHC_DEBUG ipcom_printf("Enter iprohc_decomp_udp_ip_ir\n"); #endif ip_context = ((Iprohc_d_udp_ip_context *) context->profile_context)->ip_context; udp_context = ((Iprohc_d_udp_ip_context *) context->profile_context)->udp_context; retval = iprohc_d_copy_ip_context(&backup_context, ip_context); if (retval != IPCOM_SUCCESS) { IPCOM_LOG0(ERR,"iprohc_decomp_udp_ip_ir, fail to make a copy of ip context"); return retval; } retval = iprohc_d_copy_udp_context(&backup_udp_context, udp_context); if (retval != IPCOM_SUCCESS) { /* Free the backup ip context */ iprohc_del_ip_context((void *)backup_context, IP_FALSE); IPCOM_LOG0(ERR,"iprohc_decomp_udp_ip_ir, fail to make a copy of udp context"); return retval; } if (!context->first_ir) { /* Update the context from the IR packet */ /* skip profile octet */ pointer++; /* Record CRC */ crc = pkt->data[pointer]; pointer++; /* Update the IP context from the static chain */ IPROHC_UPD_IP_STATIC(ip_context, pointer, pkt); /* Update the UDP context from the static chain */ IPROHC_UPD_UDP_STATIC(udp_context, pointer, pkt); /* if D bit is set, update the context from the Dynamic chain */ if (type_data & 0x01) { IPROHC_UPD_IP_DYNAMIC(ip_context, pointer, pkt); IPROHC_UPD_UDP_DYNAMIC(udp_context, pointer, pkt); } /* Record SN in ip profile specific context, save in LSB structure */ ip_context->sn = ip_ntohs(*((Ip_u16 *)&(pkt->data[pointer]))); pointer += 2; #ifdef IPROHC_WLSB_LSB iprohc_dmp_lsb_save_last_valid_ref(&ip_context->sn_lsb, ip_htons(ip_context->sn)); #ifdef ROHC_DEBUG ipcom_printf("iprohc_decomp_udp_ip_ir, (n)sn %d, lsb sn %d\n", ip_htons(ip_context->sn), *((Ip_u16 *)&(pkt->data[pointer]))); #endif /* Update ip_id offset from sn for every IPv4 header: ip_id - sn */ IPROHC_UPD_IPID_OFFSET(ip_context); #endif /* IPROHC_WLSB_LSB */ /* Record UDP payload */ udp_context->payload = pointer; } else { /* Flip the flag for next IR packet */ context->first_ir = IP_FALSE; crc = context->crc; } /* Move ipstart and start pointers to the UDP payload */ pkt->ipstart = pkt->start = udp_context->payload; /* Get UDP header length */ IPROHC_GET_UDP_LENGTH(udp_context, pkt); /* Re-construct the headers from the UDP context */ IPROHC_RECONSTRUCT_UDP(udp_context, pkt); /* Move the IP payload and start to the beginning of the UDP header */ ip_context->payload_offset = pkt->start = pkt->ipstart; \ /* Re-construct the headers from the context */ IPROHC_RECONSTRUCT_IP(ip_context, pkt); retval = iprohc_d_udp_ip_crc_validate(context, backup_context, backup_udp_context, pkt, ROHC_PKT_IR, crc, 8, mode, IP_TRUE); return retval; } /* *=========================================================================== * iprohc_decomp_udp_ip_irdyn *=========================================================================== * Description: Decompress an UDP_IP profile IR-DYN packet. * * Passed in packet is an IP profile IR-DYN Body packet, in format: * RFC 3095, 5.7.7.2, 5.11.1 Basic structure of the IR-DYN packet * * --------------------------- * | Profile | 1 octet * --------------------------- * | CRC | 1 octet * --------------------------- * | | * | Dynamic chain | variable length * | | * --------------------------- * | | * | Payload | variable length * | | * --------------------------- * * Parameters: * Returns: * */ IP_STATIC Ip_err iprohc_decomp_udp_ip_irdyn(Iprohc_d_context *context, Ipcom_pkt *pkt, Ip_u8 type_data) { Ip_err retval = IPCOM_SUCCESS; Iprohc_d_ip_context *ip_context, *backup_context; Iprohc_d_udp_context *udp_context, *backup_udp_context; Ip_u8 crc; int pointer = pkt->ipstart, mode = -1; IPCOM_UNUSED_ARG(type_data); #ifdef ROHC_DEBUG ipcom_printf("Enter iprohc_decomp_udp_ip_irdyn\n"); #endif ip_context = ((Iprohc_d_udp_ip_context *) context->profile_context)->ip_context; udp_context = ((Iprohc_d_udp_ip_context *) context->profile_context)->udp_context; retval = iprohc_d_copy_ip_context(&backup_context, ip_context); if (retval != IPCOM_SUCCESS) { IPCOM_LOG0(ERR,"iprohc_decomp_udp_ip_irdyn, fail to make a copy of ip context"); return retval; } retval = iprohc_d_copy_udp_context(&backup_udp_context, udp_context); if (retval != IPCOM_SUCCESS) { /* Free the backup ip context */ iprohc_del_ip_context((void *)backup_context, IP_FALSE); IPCOM_LOG0(ERR,"iprohc_decomp_udp_ip_irdyn, fail to make a copy of udp context"); return retval; } /* Update the context from the IR packet */ /* skip profile octet */ pointer++; /* Record CRC */ crc = pkt->data[pointer]; pointer++; /* Update the context from the Dynamic chain */ IPROHC_UPD_IP_DYNAMIC(ip_context, pointer, pkt); IPROHC_UPD_UDP_DYNAMIC(udp_context, pointer, pkt); /* Record SN in ip profile specific context, save SN in LSB structure */ ip_context->sn = ip_ntohs(*((Ip_u16 *)&(pkt->data[pointer]))); pointer += 2; #ifdef IPROHC_WLSB_LSB iprohc_dmp_lsb_save_last_valid_ref(&ip_context->sn_lsb, ip_htons(ip_context->sn)); #ifdef ROHC_DEBUG ipcom_printf("iprohc_decomp_udp_ip_irdyn, lsb sn %d\n", ip_htons(ip_context->sn)); #endif /* Update ip_id offset from sn for every IPv4 header: ip_id - sn */ IPROHC_UPD_IPID_OFFSET(ip_context); #endif /* IPROHC_WLSB_LSB */ /* Record the UDP payload. Move ipstart and start pointers to the UDP payload */ pkt->ipstart = pkt->start = udp_context->payload = pointer; /* Get UDP header length */ IPROHC_GET_UDP_LENGTH(udp_context, pkt); /* Re-construct the headers from the UDP context */ IPROHC_RECONSTRUCT_UDP(udp_context, pkt); /* Move start pointer to the UDP header. Record the IP payload.*/ ip_context->payload_offset = pkt->start = pkt->ipstart; \ /* Re-construct the headers from the context */ IPROHC_RECONSTRUCT_IP(ip_context, pkt); retval = iprohc_d_udp_ip_crc_validate(context, backup_context, backup_udp_context, pkt, ROHC_PKT_IR_DYN, crc, 8, mode, IP_TRUE); return retval; } /* *=========================================================================== * iprohc_decomp_udp_ip_general *=========================================================================== * Description: Decompress an UDP_IP profile general packet. * * Passed in packet is an IP profile type0/type1/type2 Body packet, in format: * RFC 3843, 3.6 General format for a compressed header * * ------------------------------ * | remainder of base header | variable number of bits * ------------------------------ * : : * | Extension | extension, if X = 1 in base header * : : * ------------------------------ * : : * | IP-ID of outer IPv4 header | 2 octets, if value (RND2) = 1 * : : * ------------------------------ * / AH data for outer list / variable (not supported) * ------------------------------ * : : * | GRE checksum | 2 octets, if GRE flag C=1(not supported) * : : * ------------------------------ * : : * | IP-ID of inner IPv4 header | 2 octets, if value (RND) = 1 * : : * ------------------------------ * / AH data for inner list / variable (not supported) * ------------------------------ * : : * | GRE checksum | 2 octets, if GRE flag C=1(not supported) * : : * ------------------------------ * : : * | UDP checksum | 2 octets if context(UDP Checksum) != 0 * : : * ------------------------------ * * Parameters: * Returns: * */ IP_STATIC Ip_err iprohc_decomp_udp_ip_general(Iprohc_d_context *context, Ipcom_pkt *pkt, Ip_u8 pkt_type, Ip_u8 type_data) { Ip_err retval = IPCOM_SUCCESS; Iprohc_d_ip_context *ip_context, *backup_context; Iprohc_d_udp_context *udp_context, *backup_udp_context; int pointer = pkt->ipstart; Ip_u8 sn, data, crc = 0, crc_bits = 0; int mode = -1; Ip_u32 sn_d = 0; int in_nbo = -1, in_rnd = -1, out_nbo = -1, out_rnd = -1; Iprohc_ip_header *in_header, *out_header; Ip_bool udp_chksum = IP_TRUE; #ifdef ROHC_DEBUG ipcom_printf("Enter iprohc_decomp_udp_ip_general, pkt type %s\n", iprohc_pkt_type(pkt_type)); #endif ip_context = ((Iprohc_d_udp_ip_context *) context->profile_context)->ip_context; udp_context = ((Iprohc_d_udp_ip_context *) context->profile_context)->udp_context; out_header = IPCOM_LIST_FIRST(&ip_context->ip_head); if(out_header == IP_NULL) return IPCOM_ERR_INVALID_ARG; in_header = IPCOM_LIST_NEXT(&out_header->ip_list); retval = iprohc_d_copy_ip_context(&backup_context, ip_context); if (retval != IPCOM_SUCCESS) { IPCOM_LOG0(ERR,"iprohc_decomp_udp_ip_general, fail to make a copy of ip context"); return retval; } retval = iprohc_d_copy_udp_context(&backup_udp_context, udp_context); if (retval != IPCOM_SUCCESS) { /* Free the backup ip context */ iprohc_del_ip_context((void *)backup_context, IP_FALSE); IPCOM_LOG0(ERR,"iprohc_decomp_udp_ip_general, fail to make a copy of udp context"); return retval; } switch (pkt_type) { case ROHC_PKT_TYPE_0: if (context->mode == ROHC_MODE_R) { /* It is in R-0-CRC format */ /* Get second octet of base header: SN(LSB) + CRC */ data = pkt->data[pointer]; /* Record CRC */ crc = (Ip_u8)(data & 0x7F); crc_bits = 7; /* Get sn (7 bits) */ sn_d = (Ip_u32)((type_data & 0x3F) << 1) + (Ip_u32)((data & 0x80) >> 7); sn = (Ip_u8)sn_d; #ifdef IPROHC_WLSB_LSB /* Decode and save SN */ iprohc_lsb_decode_and_save_ip_sn_ref(&sn_d, &ip_context->sn_lsb, (Ip_u32)sn, 7); #ifdef ROHC_DEBUG ipcom_printf("iprohc_decomp_udp_ip_general(type 0/R): header sn %d, sn_d %d\n", sn, sn_d); #endif #endif /* IPROHC_WLSB_LSB */ /* Move pointer */ pointer ++; } else { /* It is in UO-0 format */ /* Record CRC */ crc = (Ip_u8)(type_data & 0x07); crc_bits = 3; /* Get sn (4 bits) */ sn_d = (Ip_u32)(type_data & 0x78) >> 3; sn = (Ip_u8)sn_d; #ifdef IPROHC_WLSB_LSB /* Decode and save SN */ iprohc_lsb_decode_and_save_ip_sn_ref(&sn_d, &ip_context->sn_lsb, (Ip_u32)sn, 4); #ifdef ROHC_DEBUG ipcom_printf("iprohc_decomp_udp_ip_general(type 0/UO): header sn %d, sn_d %d\n", sn, sn_d); #endif #endif /* IPROHC_WLSB_LSB */ } break; case ROHC_PKT_TYPE_1: /* Get second octet of base header: X + CRC */ data = pkt->data[pointer]; pointer ++; if (context->mode == ROHC_MODE_R) { /* It is in R-1 format */ /* Get sn: 6 bits */ sn_d = type_data & 0x3F; sn = (Ip_u8)sn_d; #ifdef IPROHC_WLSB_LSB /* Decode SN */ iprohc_lsb_decode_and_save_ip_sn_ref(&sn_d, &ip_context->sn_lsb, (Ip_u32)sn, 6); #ifdef ROHC_DEBUG ipcom_printf("iprohc_decomp_udp_ip_general(type 1/R): header sn %d, sn_d %d\n", sn, sn_d); #endif #endif /* IPROHC_WLSB_LSB */ if (data & 0x80) { /* may update ip-id in the extension parsing funtion */ iprohc_parse_extension(in_header?&(out_header->header):IP_NULL, in_header?&(in_header->header):&(out_header->header), &sn, &mode, &in_nbo, &in_rnd, &out_nbo, &out_rnd, pkt, &pointer); } } else { /* It is in UO-1 format */ /* Record CRC */ crc = (Ip_u8)(data & 0x07); crc_bits = 3; /* Get sn: 5 bits */ sn_d = (data & 0xF8) >> 3; sn = (Ip_u8)sn_d; #ifdef IPROHC_WLSB_LSB /* Decode and save SN */ iprohc_lsb_decode_and_save_ip_sn_ref(&sn_d, &ip_context->sn_lsb, (Ip_u32)sn, 5); #ifdef ROHC_DEBUG ipcom_printf("iprohc_decomp_udp_ip_general(type 1/UO): header sn %d, sn_d %d\n", sn, sn_d); #endif #endif /* IPROHC_WLSB_LSB */ } break; case ROHC_PKT_TYPE_2: /* Get sn: 5 bits */ sn_d = (type_data & 0x1F); sn = (Ip_u8)sn_d; #ifdef IPROHC_WLSB_LSB /* Decode and save SN */ iprohc_lsb_decode_and_save_ip_sn_ref(&sn_d, &ip_context->sn_lsb, (Ip_u32)sn, 5); #ifdef ROHC_DEBUG ipcom_printf("iprohc_decomp_udp_ip_general(type 2): header sn %d, sn_d %d\n", sn, sn_d); #endif #endif /* IPROHC_WLSB_LSB */ /* Get second octet of base header: X + CRC */ data = pkt->data[pointer]; /* Record CRC and move pointer */ crc = (Ip_u8)(data & 0x7F); crc_bits = 7; pointer ++; if (data & 0x80) iprohc_parse_extension(in_header?&(out_header->header):IP_NULL, in_header?&(in_header->header):&(out_header->header), &sn, &mode, &in_nbo, &in_rnd, &out_nbo, &out_rnd, pkt, &pointer); break; } #ifdef IPCOM_USE_INET /* Update in/out BNO/RND */ if (in_nbo != -1) { if (in_header) in_header->nbo = in_nbo; else out_header->nbo = in_nbo; } if (in_rnd != -1) { if (in_header) in_header->rnd = in_rnd; else out_header->rnd = in_rnd; } if (out_nbo != -1) out_header->nbo = out_nbo; if (out_rnd != -1) out_header->rnd = out_rnd; #endif /* #ifdef IPCOM_USE_INET */ /* Update SN */ ip_context->sn = ip_ntohs(sn_d); #ifdef ROHC_DEBUG ipcom_printf("iprohc_decomp_udp_ip_general: context (n)sn %d\n", ip_htons(ip_context->sn)); #endif /* Check for IP-ID of outer IPv4 header */ if (out_header->packet_type == ROHC_PKT_IPV4) { #ifdef IPCOM_USE_INET if (out_header->rnd) { /* Get IP-ID of outer IPv4 header */ ipcom_memcpy(&(out_header->header.ip4.id), &(pkt->data[pointer]), 2); #ifdef ROHC_DEBUG ipcom_printf("iprohc_decomp_udp_ip_general: outer IP-ID(ramdon) %x\n", out_header->header.ip4.id); #endif pointer += 2; } else { /* Calcuate IP-ID from SN */ out_header->header.ip4.id = (Ip_u16)(out_header->offset + ip_htons(ip_context->sn)); } #ifdef ROHC_DEBUG ipcom_printf("iprohc_decomp_udp_ip_general: outer IP-ID %x\n", out_header->header.ip4.id); #endif #endif /* #ifdef IPCOM_USE_INET */ } if (in_header && in_header->packet_type == ROHC_PKT_IPV4) { #ifdef IPCOM_USE_INET if (in_header->rnd) { /* Get IP-ID of inner IPv4 header */ ipcom_memcpy(&(in_header->header.ip4.id), &(pkt->data[pointer]), 2); pointer += 2; } else { /* Calcuate IP-ID from SN */ in_header->header.ip4.id = (Ip_u16)(in_header->offset + ip_htons(ip_context->sn)); } #ifdef ROHC_DEBUG ipcom_printf("iprohc_decomp_udp_ip_general: inner IP-ID %x\n", in_header->header.ip4.id); #endif #endif /* #ifdef IPCOM_USE_INET */ } /* Parse the list of dynamic chains for additional IP headers */ if (ip_context->ip_num > 2) IPROHC_UPD_IP_ADDTIONAL_DYNAMIC(ip_context, pointer, pkt); /* Get the UDP dynamic chain and validate udp checksum usage in a genral packet. The checksum is not sent if it is not used */ IPROHC_UPD_UDP_DYNAMIC1(udp_context, pointer, pkt, udp_chksum); /* Record the UDP payload. Move ipstart and start pointers to the UDP payload */ pkt->ipstart = pkt->start = udp_context->payload = pointer; /* Calculate the UDP header length */ IPROHC_GET_UDP_LENGTH(udp_context, pkt); /* Re-construct the headers from the UDP context */ IPROHC_RECONSTRUCT_UDP(udp_context, pkt); /* Move start pointer to the UDP header. Record the IP payload.*/ ip_context->payload_offset = pkt->start = pkt->ipstart; \ /* Re-construct the headers from the context */ IPROHC_RECONSTRUCT_IP(ip_context, pkt); retval = iprohc_d_udp_ip_crc_validate(context, backup_context, backup_udp_context, pkt, pkt_type, crc, crc_bits, mode, udp_chksum); return retval; } /* *=========================================================================== * iprohc_udp_c_get_header *=========================================================================== * Description: Get UDP header from the packet on the compressor. * Parameters: * Returns: * */ IP_STATIC Ip_err iprohc_udp_c_get_header(Ipcom_pkt *pkt, udp_header *header) { Ip_err retval = IPCOM_SUCCESS; ipcom_memset(header, 0, sizeof(udp_header)); ipcom_memcpy(header, &pkt->data[pkt->tlstart], sizeof(udp_header)); #ifdef ROHC_DEBUG ipcom_printf("iprohc_udp_c_get_header, udp src port %u, dst port %u, pkt length %u, \ checksum %u, pkt tlstart %d\n", ipcom_ntohs(header->src_port), ipcom_ntohs(header->dst_port), ipcom_ntohs(header->length), ipcom_ntohs(header->checksum), pkt->tlstart); #endif return retval; } /* *=========================================================================== * iprohc_udp_c_init *=========================================================================== * Description: Initialize UDP compressor context. * Parameters: * Returns: * */ IP_STATIC Ip_err iprohc_udp_c_init(Iprohc_c_udp_context *udp_context) { Ip_err retval = IPCOM_SUCCESS; udp_context->use_checksum = IP_TRUE; /* Init UDP statistic information */ udp_context->udp_pkt_count = 0; return retval; } /* *=========================================================================== * iprohc_udp_d_init *=========================================================================== * Description: Initialize UDP decompressor context. * Parameters: * Returns: * */ IP_STATIC Ip_err iprohc_udp_d_init(Iprohc_d_udp_context *udp_context) { Ip_err retval = IPCOM_SUCCESS; udp_context->use_checksum = IP_TRUE; /* Init UDP statistic information */ udp_context->udp_pkt_count = 0; return retval; } /* *=========================================================================== * iprohc_del_udp_context *=========================================================================== * Description: Delete a udp profile specific compression/decompression * context. * Parameters: * Returns: * */ IP_STATIC Ip_err iprohc_del_udp_context(void *context, Ip_bool is_comp) { Ip_err retval = IPCOM_SUCCESS; IPCOM_UNUSED_ARG(is_comp); #ifdef ROHC_DEBUG ipcom_printf("Enter iprohc_del_udp_context\n"); #endif ipcom_free(context); context = IP_NULL; return retval; } /* **************************************************************************** * PUBLIC FUNCTIONS **************************************************************************** */ /* *=========================================================================== * iprohc_profile_udp_ip_register *=========================================================================== * Description: Register ROHC UDP_IP profile (0x0002) * Parameters: * Returns: * */ IP_PUBLIC Ip_err iprohc_profile_udp_ip_register(void) { Iprohc_profile *profile; #ifdef ROHC_DEBUG ipcom_printf("Calling iprohc_profile_udp_ip_register\n"); #endif IPROHC_LOCK(); if (iprohc.profiles[ROHC_PROFILE_UDP_IP].configured) { IPCOM_LOG0(ERR, "iprohc_profile_udp_ip_register, profile already configured\n"); IPROHC_UNLOCK(); return IPCOM_ERR_ALREADY_INSTALLED; } profile = &(iprohc.profiles[ROHC_PROFILE_UDP_IP]); /* Register the UDP_IP profile specific functions */ profile->p_deregister = iprohc_udp_ip_deregister; profile->c_find_context = iprohc_udp_ip_c_find_context; profile->c_create_context = iprohc_udp_ip_c_create_context; profile->c_del_context = iprohc_udp_ip_c_del_context; profile->c_print_context = iprohc_udp_ip_c_print_context; profile->c_process_feedback = iprohc_udp_ip_c_process_feedback; profile->c_compress = iprohc_udp_ip_c_compress; profile->d_find_context = iprohc_udp_ip_d_find_context; profile->d_create_context = iprohc_udp_ip_d_create_context; profile->d_del_context = iprohc_udp_ip_d_del_context; profile->d_print_context = iprohc_udp_ip_d_print_context; profile->d_decompress = iprohc_udp_ip_d_decompress; /* Increment the profile counter and set configured flag */ iprohc.profile_num++; profile->configured = IP_TRUE; IPROHC_UNLOCK(); #ifdef ROHC_DEBUG ipcom_printf("iprohc_profile_udp_ip_register, registered\n"); #endif return IPCOM_SUCCESS; } /* *=========================================================================== * iprohc_udp_ip_deregister *=========================================================================== * Description: De-register ROHC UDP_IP profile (0x0002) * Parameters: * Returns: * */ IP_PUBLIC Ip_err iprohc_udp_ip_deregister(void) { Iprohc_profile *profile; #ifdef ROHC_DEBUG ipcom_printf("Calling iprohc_udp_ip_deregister\n"); #endif IPROHC_LOCK(); if (iprohc.profiles[ROHC_PROFILE_UDP_IP].configured == IP_FALSE) { IPCOM_LOG0(ERR, "iprohc_udp_ip_deregister, profile not configured\n"); IPROHC_UNLOCK(); return IPCOM_ERR_NOT_INSTALLED; } profile = &(iprohc.profiles[ROHC_PROFILE_UDP_IP]); /* NULL all the IP profile specific functions */ profile->p_deregister = IP_NULL; profile->c_find_context = IP_NULL; profile->c_create_context = IP_NULL; profile->c_del_context = IP_NULL; profile->c_print_context = IP_NULL; profile->c_process_feedback = IP_NULL; profile->c_compress = IP_NULL; profile->d_find_context = IP_NULL; profile->d_create_context = IP_NULL; profile->d_del_context = IP_NULL; profile->d_print_context = IP_NULL; profile->d_decompress = IP_NULL; /* Decrement the profile counter and clear configured flag */ iprohc.profile_num--; profile->configured = IP_FALSE; IPROHC_UNLOCK(); #ifdef ROHC_DEBUG ipcom_printf("iprohc_udp_ip_deregister, deregistered\n"); #endif return IPCOM_SUCCESS; } /* *=========================================================================== * iprohc_udp_ip_c_find_context *=========================================================================== * Description: Find a compression context matching the packet. The * comparison is based on src/dst IP addresses in each IP * header and UDP ports. If found a compression context, it also updates * to-be-transmitted packet info in a compression context. * Updated fields include state, pkt_type, ext_type in the * compression context, add_dynamic_chain in IP profile * compression context, rnd, nbo, and header_flags in * each ROHC IP header and UDP context fields. * Parameters: * Returns: * */ IP_PUBLIC Ip_err iprohc_udp_ip_c_find_context(Iprohc_compressor *comp, Ipcom_pkt *pkt, Iprohc_c_context **context) { Iprohc_c_context *c_context; Iprohc_ip_header *ip_header, *n_ip_header = IP_NULL; int pointer = pkt->ipstart; Ip_err retval = IPCOM_SUCCESS; udp_header udp_header_; void* profile_context; #ifdef ROHC_DEBUG ipcom_printf("Enter iprohc_udp_ip_c_find_context\n"); #endif /* Get UDP heder from the packet */ (void)iprohc_udp_c_get_header(pkt, &udp_header_); IPROHC_COMP_LOCK(comp); for (c_context = IPCOM_LIST_FIRST(&comp->context_head); c_context != IP_NULL; c_context = IPCOM_LIST_NEXT(&c_context->context_list)) { Iprohc_c_ip_context *ip_context; Iprohc_c_udp_context *udp_context; int num_ip; if (c_context->profileid != ROHC_PROFILE_UDP_IP) continue; IPROHC_C_CONTEXT_LOCK(c_context); pointer = pkt->ipstart; ip_context = ((Iprohc_c_udp_ip_context *) c_context->profile_context)->ip_context; udp_context = ((Iprohc_c_udp_ip_context *) c_context->profile_context)->udp_context; if((((Iprohc_c_udp_ip_context *) c_context->profile_context)->udp_context->src_port != udp_header_.src_port) || (((Iprohc_c_udp_ip_context *) c_context->profile_context)->udp_context->dst_port != udp_header_.dst_port)) continue; /* Compare src and dst IP addresses in headers */ for (ip_header = IPCOM_LIST_FIRST(&ip_context->ip_head), num_ip = 1; ip_header && (pointer != -1); ip_header = n_ip_header, num_ip++) { n_ip_header = IPCOM_LIST_NEXT(&ip_header->ip_list); if (ip_header->packet_type != (pkt->data[pointer]>>4)) break; #ifdef IPCOM_USE_INET if (ip_header->packet_type == ROHC_PKT_IPV4) { Ipcom_ip_header *ip4; ip4 = (Ipcom_ip_header *)&pkt->data[pointer]; #ifdef ROHC_DEBUG { char buf[48]; (void)ipcom_inet_ntop(IP_AF_INET, &ip4->src.addr32, buf, sizeof(buf)); ipcom_printf("iprohc_udp_ip_c_find_context: IPv4 src addr %s\n", buf); (void)ipcom_inet_ntop(IP_AF_INET, &ip4->dst.addr32, buf, sizeof(buf)); ipcom_printf("iprohc_udp_ip_c_find_context: IPv4 dst addr %s\n", buf); } #endif /* Enforce IPv4 header fields according to RFC 3095, 5.7.7.4 */ /* IHL must be 5, MF flag must be 0, Fragment offset must be 0 */ /* Don't compress packet less than 64(??) bytes long on an */ /* ethernet interface. */ if (((ip4->vers_len & 0x0F) != 5) || IPCOM_ISFRAG(ip4->frag) || ((num_ip == 1) && (((Iprohc_interface *)(comp->interface))->netif->type == IP_IFT_ETHER) && (ip_ntohs(ip4->length) < 64))) { IPCOM_LOG0(ERR,"iprohc_udp_ip_c_find_context, IPv4 header fileds"); IPROHC_C_CONTEXT_UNLOCK(c_context); c_context = IP_NULL; IPROHC_LEAVE(IPCOM_ERR_IGNORED_PACKET); } /* Compare src and dst IPv4 address */ if ((ip4->src.addr32 != ip_header->header.ip4.src.addr32) || (ip4->dst.addr32 != ip_header->header.ip4.dst.addr32)) break; /* Check the protocl field */ if ((ip4->protocol == IP_IPPROTO_IPIP) || (ip4->protocol == IP_IPPROTO_IPV6)) { /* Next header is IPinIP or IPv6, move pinter */ pointer += 4 * (pkt->data[pointer] & 0x0F); } else /* The end of IP header, exit for loop */ pointer = -1; } #ifdef IPCOM_USE_INET6 else #endif #endif /* #ifdef IPCOM_USE_INET */ #ifdef IPCOM_USE_INET6 if (ip_header->packet_type == ROHC_PKT_IPV6) { Ipcom_ip6_header *ip6; ip6 = (Ipcom_ip6_header *)&pkt->data[pointer]; /* Don't compress a packet whose payload is less than 50(??) */ /* bytes long on an ethernet interface. */ if ((num_ip == 1) && (((Iprohc_interface *)(comp->interface))->netif->type == IP_IFT_ETHER) && (ip_ntohs(ip6->plen) < 50)) { IPCOM_LOG0(ERR,"iprohc_udp_ip_c_find_context, IPv6 header fileds"); IPROHC_C_CONTEXT_UNLOCK(c_context); c_context = IP_NULL; IPROHC_LEAVE(IPCOM_ERR_IGNORED_PACKET); } /* Compare src and dst IPv6 address */ if ((ipcom_memcmp(&ip6->src, &ip_header->header.ip6.src, sizeof(struct Ip_in6_addr)) != 0) || (ipcom_memcmp(&ip6->dst, &ip_header->header.ip6.dst, sizeof(struct Ip_in6_addr)) != 0)) break; /* Check the protocl field */ if (ip6->nxt == IP_IPPROTO_IPV6) { /* Next header is IPv6, move pinter */ pointer += IPROHC_IP6_HDR_SIZE; } else /* The end of IP header, exit for loop */ pointer = -1; } #endif /* #ifdef IPCOM_USE_INET6 */ } if ((n_ip_header == IP_NULL) && (pointer == -1)) /* address match until the end of header chain ... find the context */ { #ifdef ROHC_DEBUG ipcom_printf("iprohc_udp_ip_c_find_context, found the context\n"); /* iprohc_c_print_a_context(c_context); */ #endif /* ROHC_DEBUG */ /* Update the UDP context and decide UDP state */ IPROHC_UDP_UPDATE_CONTEXT(c_context, udp_context, udp_header_, pkt); /* Increase SN number */ ip_context->sn = ip_ntohs(ip_htons(ip_context->sn) + 1); /* Update Ip context */ if ((c_context->state == ROHC_COMP_STATE_IR) && (c_context->num_ir < IPROHC_MAX_IRS)) { /* Continue with IR packet type and no extension. */ /* Record new IP headers, and re-calculate the RND and */ /* NBO flags in Iprohc_ip_header */ iprohc_c_update_ip_hdrs(ip_context, pkt); #ifdef ROHC_DEBUG ipcom_printf("iprohc_udp_ip_c_find_context, update IP headers\n"); /* iprohc_c_print_a_context(c_context); */ #endif /* ROHC_DEBUG */ } else { /* update ip context info. */ profile_context = c_context->profile_context; c_context->profile_context = (void*) ip_context; iprohc_c_update_ip_context(c_context, pkt); c_context->profile_context = profile_context; #ifdef ROHC_DEBUG ipcom_printf("iprohc_udp_ip_c_find_context, update context info\n"); /* iprohc_c_print_a_context(c_context); */ #endif /* ROHC_DEBUG */ } IPROHC_C_CONTEXT_UNLOCK(c_context); break; } IPROHC_C_CONTEXT_UNLOCK(c_context); } leave: IPROHC_COMP_UNLOCK(comp); *context = c_context; return retval; } /* *=========================================================================== * iprohc_udp_ip_c_create_context *=========================================================================== * Description: Create a compression context for the packet. * The function will check on UDP and IP header fields * If headers don't conform to the rules, it won't create * a compression context and the packet will be returned * without compression. * Parameters: * Returns: * */ IP_PUBLIC Iprohc_c_context * iprohc_udp_ip_c_create_context(Iprohc_compressor *comp, Ipcom_pkt *pkt) { Iprohc_c_context *c_context = IP_NULL; Iprohc_c_ip_context *ip_context; Iprohc_c_udp_context *udp_context; Iprohc_c_udp_ip_context *udp_ip_context; udp_header udp_header_; #ifdef ROHC_DEBUG ipcom_printf("Enter iprohc_udp_ip_c_create_context\n"); #endif /* Create profile specific context structure */ udp_ip_context = ipcom_malloc(sizeof(Iprohc_c_udp_ip_context)); if (udp_ip_context == IP_NULL) { IPCOM_LOG0(ERR,"iprohc_udp_ip_c_create_context, out of memory(p context)"); return c_context = IP_NULL; } ipcom_memset(udp_ip_context, 0, sizeof(Iprohc_c_udp_ip_context)); /* Create udp profile specific context structure */ udp_context = ipcom_malloc(sizeof(Iprohc_c_udp_context)); if (udp_context == IP_NULL) { ipcom_free(udp_ip_context); IPCOM_LOG0(ERR,"iprohc_udp_ip_c_create_context, out of memory(p context)"); return c_context = IP_NULL; } ipcom_memset(udp_context, 0, sizeof(Iprohc_c_udp_context)); IPROHC_COMP_LOCK(comp); c_context = iprohc_ip_c_create_context(comp, pkt); if (c_context == IP_NULL) { ipcom_free(udp_ip_context); ipcom_free(udp_context); goto errout; } IPROHC_C_CONTEXT_LOCK(c_context); c_context->profileid = ROHC_PROFILE_UDP_IP; /* iprohc_ip_c_create_context creates ip_context. c_context->profile_context contains the pointer to the ip_context */ ip_context = (Iprohc_c_ip_context*) c_context->profile_context; c_context->profile_context = udp_ip_context; ((Iprohc_c_udp_ip_context *) c_context->profile_context)->udp_context = udp_context; ((Iprohc_c_udp_ip_context *) c_context->profile_context)->ip_context = ip_context; (void)iprohc_udp_c_get_header(pkt, &udp_header_); iprohc_udp_c_init(udp_context); IPROHC_UDP_INIT_CONTEXT(udp_context, udp_header_, pkt); /* This should never happen. This can be caused for example if IP code does not process all extension headers up to the UDP header */ if(ip_context->payload_offset != (udp_context->payload - 8)) { iprohc_del_udp_ip_context(c_context->profile_context, IP_TRUE); ipcom_free(c_context->profile_context); comp->context_num--; /* Recover CID */ comp->to_be_used_cid--; comp->cid_bit_map[c_context->cid >> 4] = (Ip_u16)(comp->cid_bit_map[c_context->cid >> 4] & ~(1 << (c_context->cid & 0x0f))); ipcom_list_remove(&c_context->context_list); IPROHC_C_CONTEXT_UNLOCK(c_context); iprohc_c_context_common_del(c_context); IPCOM_LOG0(ERR,"iprohc_udp_ip_c_create_context, payload mismatch"); goto errout; } IPROHC_C_CONTEXT_UNLOCK(c_context); goto leave; errout: c_context = IP_NULL; leave: IPROHC_COMP_UNLOCK(comp); return c_context; } /* *=========================================================================== * iprohc_udp_ip_c_del_context *=========================================================================== * Description: Delete a compression context. * Parameters: * Returns: * */ IP_PUBLIC Ip_err iprohc_udp_ip_c_del_context(Iprohc_c_context *context) { Ip_err retval = IPCOM_SUCCESS; #ifdef ROHC_DEBUG ipcom_printf("Enter iprohc_udp_ip_c_del_context\n"); #endif if (context == IP_NULL) return retval; IPROHC_C_CONTEXT_LOCK(context); /* Remove the context from the compressor */ ipcom_list_remove(&context->context_list); /* free profile specific context structure */ if (context->profile_context) { iprohc_del_udp_ip_context(context->profile_context, IP_TRUE); ipcom_free(context->profile_context); } IPROHC_C_CONTEXT_UNLOCK(context); /* free context structure */ iprohc_c_context_common_del(context); return retval; } /* *=========================================================================== * iprohc_udp_ip_c_print_context *=========================================================================== * Description: Debug: print a compression context. * Parameters: * Returns: * */ IP_PUBLIC void iprohc_udp_ip_c_print_context(Iprohc_c_context *context) { Iprohc_c_ip_context *ip_context; Iprohc_c_udp_context *udp_context; ip_context = ((Iprohc_c_udp_ip_context *) context->profile_context)->ip_context; udp_context = ((Iprohc_c_udp_ip_context *) context->profile_context)->udp_context; ipcom_printf(" sn (network order): %d, sn: %d\n", ip_htons(ip_context->sn), ip_context->sn); ipcom_printf(" add_dynamic_chain: %s\n", ip_context->add_dynamic_chain?"Yes":"No"); ipcom_printf(" ip_num: %d\n", ip_context->ip_num); ipcom_printf(" payload_offset: %d\n", udp_context->payload); ipcom_printf(" udp src_port: %u\n", ip_ntohs(udp_context->src_port)); ipcom_printf(" udp dst_port: %u\n", ip_ntohs(udp_context->dst_port)); ipcom_printf(" udp pkt length: %u\n", ip_ntohs(udp_context->length)); ipcom_printf(" udp checksum: %u\n", ip_ntohs(udp_context->checksum)); ipcom_printf(" udp checksum is used: %s\n", udp_context->use_checksum?"Yes":"No"); } /* *=========================================================================== * iprohc_udp_ip_c_process_feedback *=========================================================================== * Description: Process a received feedback data. * * The feedback data has the following structure: * * --------------------------- * : Add-CID octet : if for small CIDs and (CID != 0) * --------------------------- * : : * / large CID / 1 - 2 octects for large CIDs * : (4.5.6 encoding) : * --------------------------- * / feedback field / * * The feedback field can have either of the following two formats: * * FEEDBACK-1 * * ---------------------------- * | profile specific info | 1 octet * ---------------------------- * * FEEDBACK-2 * * ---------------------------- * |Acktype| | * --------- profile specific / at least 2 octets * / info | * ---------------------------- * * Parameters: * Returns: * */ IP_PUBLIC Ip_err iprohc_udp_ip_c_process_feedback(Iprohc_c_context *context, Ip_u8 *feedback, Ip_u8 size) { return iprohc_ip_c_process_feedback(context, feedback, size); } /* *=========================================================================== * iprohc_udp_ip_c_compress *=========================================================================== * Description: Compress a packet. * The passed-in parameter pkt is a normal uncompressed packet. * Parameters: * Returns: * */ IP_PUBLIC Ip_err iprohc_udp_ip_c_compress(Iprohc_c_context *context, Ipcom_pkt *pkt) { Ip_err retval = IPCOM_SUCCESS; Iprohc_c_ip_context *ip_context; #ifdef ROHC_DEBUG ipcom_printf("Enter iprohc_udp_ip_c_compress, context %x, pkt type %s\n", context, iprohc_pkt_type(context->pkt_type)); ipcom_printf("iprohc_udp_ip_c_compress, ext type %d, %s\n", context->ext_type, iprohc_ext_type(context->ext_type)); #endif IPROHC_C_CONTEXT_LOCK(context); ip_context = ((Iprohc_c_udp_ip_context *) context->profile_context)->ip_context; switch (context->pkt_type) { case ROHC_PKT_IR: #ifdef ROHC_DEBUG ipcom_printf("iprohc_udp_ip_c_compress, format an IR packet\n"); #endif retval = iprohc_fmt_udp_ip_ir(context, pkt); if (retval == IPCOM_SUCCESS) { /* Increase IR packet counter */ context->num_ir ++; /* Reset retx_ir timer and num_compressed counter */ context->num_compressed = 0; ipnet_timeout_cancel(context->retx_ir); ipnet_timeout_schedule(1000 * iprohc.f_max_time, iprohc_retx_ir_timeout, (void *)context, &context->retx_ir); } break; case ROHC_PKT_IR_DYN: #ifdef ROHC_DEBUG ipcom_printf("iprohc_udp_ip_c_compress, format an IR-DYN packet\n"); #endif retval = iprohc_fmt_udp_ip_irdyn(context, pkt); if (retval == IPCOM_SUCCESS) { /* Increase compressed packet counter, and reset IR counter */ context->num_compressed ++; context->num_ir = 0; } break; case ROHC_PKT_TYPE_0: case ROHC_PKT_TYPE_1: case ROHC_PKT_TYPE_2: #ifdef ROHC_DEBUG ipcom_printf("iprohc_udp_ip_c_compress, format packet type %s\n", iprohc_pkt_type(context->pkt_type)); #endif retval = iprohc_fmt_udp_ip_general(context, pkt); if (retval == IPCOM_SUCCESS) { /* Increase compressed packet counter, and reset IR counter */ context->num_compressed ++; context->num_ir = 0; } break; default: IPCOM_LOG0(ERR, "iprohc_udp_ip_c_compress: illegal packet type"); break; } /* Check the number of consecutive compressed packet counter */ if (context->num_compressed >= iprohc.f_max_period) { /* send an IR packet */ context->pkt_type = ROHC_PKT_IR; context->num_compressed = 0; } /* Reset pkt type, extension type, and add_dynamic_chain flag */ if (((context->pkt_type != ROHC_PKT_IR) && (context->trans != ROHC_COMP_TRANS_PENDING)) || ((context->pkt_type == ROHC_PKT_IR) && (context->trans != ROHC_COMP_TRANS_PENDING) && (context->state != ROHC_COMP_STATE_IR))) context->pkt_type = ROHC_PKT_TYPE_0; if (context->trans != ROHC_COMP_TRANS_PENDING) context->ext_type = ROHC_EXT_NO_EXT; ip_context->add_dynamic_chain = IP_FALSE; IPROHC_C_CONTEXT_UNLOCK(context); #ifdef DEBUG /* ipcom_printf("End of iprohc_udp_ip_c_compress\n"); iprohc_c_print_a_context(context); */ #endif return retval; } /* *=========================================================================== * iprohc_udp_ip_d_find_context *=========================================================================== * Description: Find a decompression context associated with the packet. * * Passed in packet has the following general format: * RFC 3095, 5.2 * * -------------------------- * : Add-CID octet : if (CID 1-15) and (small CIDs) * -------------------------- * | type indication | body | * -------------------------- * : : * / 0 - 2 octets of CID / 1 or 2 octets if (large CIDs) * : : * -------------------------- * / Body / variable length * -------------------------- * * Parameters: * Returns: * */ IP_PUBLIC Iprohc_d_context * iprohc_udp_ip_d_find_context(Iprohc_decompressor *decomp, Ipcom_pkt *pkt) { return iprohc_ip_d_find_context(decomp, pkt); } /* *=========================================================================== * iprohc_udp_ip_d_create_context *=========================================================================== * Description: Create a decompression context for the packet. * * Passed in packet is an IR packet, has the following format: * RFC 3095, 5.7.7.1, 5.11.1 * * --------------------------- * | Add-CID octet | if for small CIDs and CID != 0 * --------------------------- * | 1 1 1 1 1 1 0 | D | * --------------------------- * | | * / 0-2 octets of CID info / 1-2 octets if for large CIDs * | | * --------------------------- * | Profile | 1 octet * --------------------------- * | CRC | 1 octet * --------------------------- * | | * | Static chain | variable length * | | * --------------------------- * | | * | Dynamic chain | present if D = 1, variable length * | | * --------------------------- * | | * | Payload | variable length * | | * --------------------------- * * Parameters: * Returns: * */ IP_PUBLIC Iprohc_d_context * iprohc_udp_ip_d_create_context(Iprohc_decompressor *decomp, Ipcom_pkt *pkt) { Iprohc_d_context *d_context = IP_NULL; Iprohc_d_ip_context *ip_context; Iprohc_d_udp_context *udp_context; Ip_u16 cid = 0; int pointer; Ip_u8 type_data, crc; /* to get D bit */ Iprohc_ip_header *ip_header; #ifdef ROHC_DEBUG ipcom_printf("Enter iprohc_udp_ip_d_create_context\n"); #endif /* pointer will be moved to point Profile */ IPROHC_GET_CID(pkt, pointer, cid, type_data); /* skip profile octet */ pointer++; /* Record CRC from the packet */ crc = pkt->data[pointer]; pointer++; IPROHC_DECOMP_LOCK(decomp); d_context = iprohc_d_context_common_create(cid); if (d_context == IP_NULL) { IPCOM_LOG0(ERR,"iprohc_udp_ip_d_create_context, failed to create context"); goto errout; } IPROHC_D_CONTEXT_LOCK(d_context); /* Record decompressor and CRC */ d_context->decompressor = (struct Iprohc_decompressor *)decomp; d_context->profileid = ROHC_PROFILE_UDP_IP; d_context->crc = crc; /* Create profile specific context structure */ d_context->profile_context = ipcom_malloc(sizeof(Iprohc_d_udp_ip_context)); if (d_context->profile_context == IP_NULL) { IPCOM_LOG0(ERR,"iprohc_udp_ip_d_create_context, out of memory(p context)"); goto errout; } ipcom_memset(d_context->profile_context, 0, sizeof(Iprohc_d_udp_ip_context)); /* Create IP profile specific context structure */ ip_context = ipcom_malloc(sizeof(Iprohc_d_ip_context)); if (ip_context == IP_NULL) { IPCOM_LOG0(ERR,"iprohc_udp_ip_d_create_context, out of memory(p context)"); goto errout; } ipcom_memset(ip_context, 0, sizeof(Iprohc_d_ip_context)); ((Iprohc_d_udp_ip_context *) d_context->profile_context)->ip_context = ip_context; /* Init IP header list */ ipcom_list_init(&ip_context->ip_head); /* Create UDP profile specific context structure */ udp_context = ipcom_malloc(sizeof(Iprohc_d_udp_context)); if (udp_context == IP_NULL) { IPCOM_LOG0(ERR,"iprohc_udp_ip_d_create_context, out of memory(p context)"); goto errout; } ipcom_memset(udp_context, 0, sizeof(Iprohc_d_udp_context)); ((Iprohc_d_udp_ip_context *) d_context->profile_context)->udp_context = udp_context; /* Init udp context */ (void) iprohc_udp_d_init(udp_context); /* Parsing static chain to form IP headers */ IPROHC_GET_IP_STATIC(ip_context, pointer, pkt); /* Get UDP static chain */ IPROHC_GET_UDP_STATIC(udp_context, pointer, pkt) /* if D bit is set, parse dynamic chain */ if (type_data & 0x01) { IPROHC_GET_IP_DYNAMIC(ip_context, pointer, pkt); IPROHC_GET_UDP_DYNAMIC(udp_context, pointer, pkt); } /* Record stream type, source and destination address */ ip_header = IPCOM_LIST_FIRST(&(ip_context->ip_head)); if (ip_header == IP_NULL) { IPCOM_LOG0(ERR,"iprohc_udp_ip_d_create_context, NULL ip_header(p context)"); goto errout; } d_context->stream_type = ip_header->packet_type; #ifdef IPCOM_USE_INET if (ip_header->packet_type == ROHC_PKT_IPV4) { /* An IPv4 packet */ d_context->src.addr4 = ip_header->header.ip4.src; d_context->dst.addr4 = ip_header->header.ip4.dst; } #ifdef IPCOM_USE_INET6 else #endif #endif /* #ifdef IPCOM_USE_INET */ #ifdef IPCOM_USE_INET6 if (ip_header->packet_type == ROHC_PKT_IPV6) { /* An IPv6 packet */ d_context->src.addr6 = ip_header->header.ip6.src; d_context->dst.addr6 = ip_header->header.ip6.dst; } #endif /* #ifdef IPCOM_USE_INET6 */ /* Record SN in ip profile specific context, and init SN LSB structure */ ip_context->sn = ip_ntohs(*((Ip_u16 *)&(pkt->data[pointer]))); pointer += 2; /* Record UDP payload */ udp_context->payload = pointer; /* Get UDP header length */ IPROHC_GET_UDP_LENGTH(udp_context, pkt); #ifdef IPROHC_WLSB_LSB iprohc_init_dmp_lsb_struct(&ip_context->sn_lsb, IPROHC_LSB_INC, 0xffff); iprohc_dmp_lsb_save_last_valid_ref(&ip_context->sn_lsb, ip_htons(ip_context->sn)); #ifdef ROHC_DEBUG ipcom_printf("iprohc_udp_ip_d_create_context, lsb sn %d\n", ip_htons(ip_context->sn)); #endif /* ROHC_DEBUG */ /* Update ip_id offset from sn for every IPv4 header: ip_id - sn */ IPROHC_UPD_IPID_OFFSET(ip_context); #endif /* IPROHC_WLSB_LSB */ /* Mark the first IR to be true */ d_context->first_ir = IP_TRUE; /* Add the de-compression context to the de-compressor */ ipcom_list_insert_last(&decomp->context_head, &d_context->context_list); decomp->context_num++; IPROHC_D_CONTEXT_UNLOCK(d_context); goto leave; errout: /* free d_context structure */ if (d_context) { /* free profile specific context structure */ if (d_context->profile_context) { iprohc_del_udp_ip_context(d_context->profile_context, IP_FALSE); ipcom_free(d_context->profile_context); } IPROHC_D_CONTEXT_UNLOCK(d_context); iprohc_d_context_common_del(d_context); } d_context = IP_NULL; leave: IPROHC_DECOMP_UNLOCK(decomp); return d_context; } /* *=========================================================================== * iprohc_udp_ip_d_del_context *=========================================================================== * Description: Delete a decompression context. * Parameters: * Returns: * */ IP_PUBLIC Ip_err iprohc_udp_ip_d_del_context(Iprohc_d_context *context) { Ip_err retval = IPCOM_SUCCESS; #ifdef ROHC_DEBUG ipcom_printf("Enter iprohc_udp_ip_d_del_context\n"); #endif if (context == IP_NULL) return retval; IPROHC_D_CONTEXT_LOCK(context); /* Remove the context from the de-compressor */ ipcom_list_remove(&context->context_list); /* free profile specific context structure */ if (context->profile_context) { iprohc_del_udp_ip_context(context->profile_context, IP_FALSE); ipcom_free(context->profile_context); } IPROHC_D_CONTEXT_UNLOCK(context); /* free context structure */ iprohc_d_context_common_del(context); return retval; } /* *=========================================================================== * iprohc_udp_ip_d_print_context *=========================================================================== * Description: Debug: print a de-compression context. * Parameters: * Returns: * */ IP_PUBLIC void iprohc_udp_ip_d_print_context(Iprohc_d_context *context) { Iprohc_d_ip_context *ip_context; Iprohc_d_udp_context *udp_context; ip_context = ((Iprohc_d_udp_ip_context *) context->profile_context)->ip_context; udp_context = ((Iprohc_d_udp_ip_context *)context->profile_context)->udp_context; ipcom_printf(" sn (network order): %d, sn: %d\n", ip_htons(ip_context->sn), ip_context->sn); ipcom_printf(" ip_num: %d\n", ip_context->ip_num); ipcom_printf(" payload_offset: %d\n", udp_context->payload); ipcom_printf(" udp src_port: %u\n", ip_ntohs(udp_context->src_port)); ipcom_printf(" udp dst_port: %u\n", ip_ntohs(udp_context->dst_port)); ipcom_printf(" udp pkt length: %u\n", ip_ntohs(udp_context->length)); ipcom_printf(" udp checksum: %u\n", ip_ntohs(udp_context->checksum)); ipcom_printf(" udp checksum is used: %s\n", udp_context->use_checksum?"Yes":"No"); } /* *=========================================================================== * iprohc_udp_ip_d_decompress *=========================================================================== * Description: Decompress a packet. * * Passed in packet has the following general format: * RFC 3095, 5.2 * * -------------------------- * : Add-CID octet : if (CID 1-15) and (small CIDs) * -------------------------- * | type indication | body | * -------------------------- * : : * / 0 - 2 octets of CID / 1 or 2 octets if (large CIDs) * : : * -------------------------- * / Body / variable length * -------------------------- * * Parameters: * Returns: * */ IP_PUBLIC Ip_err iprohc_udp_ip_d_decompress(Iprohc_d_context *context, Ipcom_pkt *pkt) { Ip_err retval = IPCOM_SUCCESS; int pointer = pkt->ipstart; Ip_u8 pkt_type = 0, type_data; Iprohc_d_ip_context *ip_context; #ifdef ROHC_DEBUG ipcom_printf("iprohc_udp_ip_d_decompress\n"); #endif /* Record type data and move pointer to point to Body */ if ((pkt->data[pointer] >> ROHC_PKT_ADD_CID_SHIFT) == ROHC_PKT_ADD_CID) { /* small CID */ type_data = pkt->data[pointer+1]; pointer += 2; } else { /* large CID */ type_data = pkt->data[pointer]; /* * RFC 3095, section 5.2.2: If the first bit is 0, the CID uses * one octet. If the first bit is 1, the CID uses two octets. */ if ((pkt->data[pointer+1] & 0x80) == 0) pointer += 2; else pointer += 3; } /* Parse for packet type. */ /* ROHC segmentation type was handled in the packet intercept function. */ if (type_data == ROHC_PKT_IR_DYN) pkt_type = ROHC_PKT_IR_DYN; else if ((type_data >> ROHC_PKT_IR_SHIFT) == ROHC_PKT_IR) pkt_type = ROHC_PKT_IR; else if ((type_data >> ROHC_PKT_TYPE_0_SHIFT) == ROHC_PKT_TYPE_0) pkt_type = ROHC_PKT_TYPE_0; else if ((type_data >> ROHC_PKT_TYPE_1_SHIFT) == ROHC_PKT_TYPE_1) pkt_type = ROHC_PKT_TYPE_1; else if ((type_data >> ROHC_PKT_TYPE_2_SHIFT) == ROHC_PKT_TYPE_2) pkt_type = ROHC_PKT_TYPE_2; #ifdef ROHC_DEBUG ipcom_printf("iprohc_udp_ip_d_decompress, pkt_type %s\n", iprohc_pkt_type(pkt_type)); #endif /* Move the ipstart and start pointer to point to Body */ pkt->ipstart = pkt->start = pointer; IPROHC_D_CONTEXT_LOCK(context); ip_context = ((Iprohc_d_udp_ip_context *) context->profile_context)->ip_context; /* Check whether the decompression is allowed */ IPROHC_DECOMP_ALLOWED(context, pkt_type, ip_context->sn); /* Decompress the packet according to the packet type */ switch (pkt_type) { case ROHC_PKT_IR: retval = iprohc_decomp_udp_ip_ir(context, pkt, type_data); break; case ROHC_PKT_IR_DYN: retval = iprohc_decomp_udp_ip_irdyn(context, pkt, type_data); break; case ROHC_PKT_TYPE_0: case ROHC_PKT_TYPE_1: case ROHC_PKT_TYPE_2: retval = iprohc_decomp_udp_ip_general(context, pkt, pkt_type, type_data); break; default: retval = IPCOM_ERR_NOT_SUPPORTED; IPCOM_LOG0(ERR, "iprohc_udp_ip_d_decompress: illegal packet type"); break; } errout: IPROHC_D_CONTEXT_UNLOCK(context); return retval; } /* **************************************************************************** * END OF FILE **************************************************************************** */