/* iprohc_util.c - ROHC utility 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 -------------------- 01r,06aug13,j_y Clean low impact code review defects 01q,21nov12,ggz Defect WIND00387435. Validate comp/decomp ptrs before usage 01p,20oct11,ggz Support multiple profiles per channel. WIND00312948 01o,20oct11,ggz Fix for defect WIND00312450 01n,08dec10,ggz Add 64 bit support 01m,08apr10,ggz Resolve a compiler warning 01l,27mar10,ggz Resolve coverity warnings 01k,18mar10,ggz Remove comments in comp. profile selection function 01j,22feb10,ggz Add ESP/IP,UDP/IP profiles 01i,10jan10,ggz Add functions to determine transport layer protocol and UDP packet length. 01h,05jan10,ggz Modifications to support ESP_IP UDP_IP profiles 01g,20nov09,ggz Add iprohc_d_choose_profile function 01f,05feb09,tlu Remove interface number restriction in shell cmds 01e,11aug08,tlu Add to print source address in feedback print function 01d,15jun18,ggz Add uncompressed pkt type to iprohc_pkt_type() function 01c,15may08,tlu Add debug utilities 01b,25apr08,tlu Add CRC caculation functions 01a,25feb08,tlu Created. */ /* **************************************************************************** * 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_ip.h" /* **************************************************************************** * DEFINES **************************************************************************** */ IP_EXTERN Iprohc_data iprohc; /* This is a compile flag, turning on it will build debug message into image */ #undef ROHC_DEBUG #undef IPROHC_UDP_SEND_UNCOMPRESSED /* **************************************************************************** * LOCAL TYPES **************************************************************************** */ /* **************************************************************************** * LOCAL Data **************************************************************************** */ IP_STATIC Ip_u8 crc3_tab[] = { 0x00, 0x06, 0x01, 0x07, 0x02, 0x04, 0x03, 0x05, 0x04, 0x02, 0x05, 0x03, 0x06, 0x00, 0x07, 0x01, 0x05, 0x03, 0x04, 0x02, 0x07, 0x01, 0x06, 0x00, 0x01, 0x07, 0x00, 0x06, 0x03, 0x05, 0x02, 0x04, 0x07, 0x01, 0x06, 0x00, 0x05, 0x03, 0x04, 0x02, 0x03, 0x05, 0x02, 0x04, 0x01, 0x07, 0x00, 0x06, 0x02, 0x04, 0x03, 0x05, 0x00, 0x06, 0x01, 0x07, 0x06, 0x00, 0x07, 0x01, 0x04, 0x02, 0x05, 0x03, 0x03, 0x05, 0x02, 0x04, 0x01, 0x07, 0x00, 0x06, 0x07, 0x01, 0x06, 0x00, 0x05, 0x03, 0x04, 0x02, 0x06, 0x00, 0x07, 0x01, 0x04, 0x02, 0x05, 0x03, 0x02, 0x04, 0x03, 0x05, 0x00, 0x06, 0x01, 0x07, 0x04, 0x02, 0x05, 0x03, 0x06, 0x00, 0x07, 0x01, 0x00, 0x06, 0x01, 0x07, 0x02, 0x04, 0x03, 0x05, 0x01, 0x07, 0x00, 0x06, 0x03, 0x05, 0x02, 0x04, 0x05, 0x03, 0x04, 0x02, 0x07, 0x01, 0x06, 0x00, 0x06, 0x00, 0x07, 0x01, 0x04, 0x02, 0x05, 0x03, 0x02, 0x04, 0x03, 0x05, 0x00, 0x06, 0x01, 0x07, 0x03, 0x05, 0x02, 0x04, 0x01, 0x07, 0x00, 0x06, 0x07, 0x01, 0x06, 0x00, 0x05, 0x03, 0x04, 0x02, 0x01, 0x07, 0x00, 0x06, 0x03, 0x05, 0x02, 0x04, 0x05, 0x03, 0x04, 0x02, 0x07, 0x01, 0x06, 0x00, 0x04, 0x02, 0x05, 0x03, 0x06, 0x00, 0x07, 0x01, 0x00, 0x06, 0x01, 0x07, 0x02, 0x04, 0x03, 0x05, 0x05, 0x03, 0x04, 0x02, 0x07, 0x01, 0x06, 0x00, 0x01, 0x07, 0x00, 0x06, 0x03, 0x05, 0x02, 0x04, 0x00, 0x06, 0x01, 0x07, 0x02, 0x04, 0x03, 0x05, 0x04, 0x02, 0x05, 0x03, 0x06, 0x00, 0x07, 0x01, 0x02, 0x04, 0x03, 0x05, 0x00, 0x06, 0x01, 0x07, 0x06, 0x00, 0x07, 0x01, 0x04, 0x02, 0x05, 0x03, 0x07, 0x01, 0x06, 0x00, 0x05, 0x03, 0x04, 0x02, 0x03, 0x05, 0x02, 0x04, 0x01, 0x07, 0x00, 0x06 }; IP_STATIC Ip_u8 crc7_tab[] = { 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77, 0x19, 0x10, 0x0b, 0x02, 0x3d, 0x34, 0x2f, 0x26, 0x51, 0x58, 0x43, 0x4a, 0x75, 0x7c, 0x67, 0x6e, 0x32, 0x3b, 0x20, 0x29, 0x16, 0x1f, 0x04, 0x0d, 0x7a, 0x73, 0x68, 0x61, 0x5e, 0x57, 0x4c, 0x45, 0x2b, 0x22, 0x39, 0x30, 0x0f, 0x06, 0x1d, 0x14, 0x63, 0x6a, 0x71, 0x78, 0x47, 0x4e, 0x55, 0x5c, 0x64, 0x6d, 0x76, 0x7f, 0x40, 0x49, 0x52, 0x5b, 0x2c, 0x25, 0x3e, 0x37, 0x08, 0x01, 0x1a, 0x13, 0x7d, 0x74, 0x6f, 0x66, 0x59, 0x50, 0x4b, 0x42, 0x35, 0x3c, 0x27, 0x2e, 0x11, 0x18, 0x03, 0x0a, 0x56, 0x5f, 0x44, 0x4d, 0x72, 0x7b, 0x60, 0x69, 0x1e, 0x17, 0x0c, 0x05, 0x3a, 0x33, 0x28, 0x21, 0x4f, 0x46, 0x5d, 0x54, 0x6b, 0x62, 0x79, 0x70, 0x07, 0x0e, 0x15, 0x1c, 0x23, 0x2a, 0x31, 0x38, 0x41, 0x48, 0x53, 0x5a, 0x65, 0x6c, 0x77, 0x7e, 0x09, 0x00, 0x1b, 0x12, 0x2d, 0x24, 0x3f, 0x36, 0x58, 0x51, 0x4a, 0x43, 0x7c, 0x75, 0x6e, 0x67, 0x10, 0x19, 0x02, 0x0b, 0x34, 0x3d, 0x26, 0x2f, 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c, 0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04, 0x6a, 0x63, 0x78, 0x71, 0x4e, 0x47, 0x5c, 0x55, 0x22, 0x2b, 0x30, 0x39, 0x06, 0x0f, 0x14, 0x1d, 0x25, 0x2c, 0x37, 0x3e, 0x01, 0x08, 0x13, 0x1a, 0x6d, 0x64, 0x7f, 0x76, 0x49, 0x40, 0x5b, 0x52, 0x3c, 0x35, 0x2e, 0x27, 0x18, 0x11, 0x0a, 0x03, 0x74, 0x7d, 0x66, 0x6f, 0x50, 0x59, 0x42, 0x4b, 0x17, 0x1e, 0x05, 0x0c, 0x33, 0x3a, 0x21, 0x28, 0x5f, 0x56, 0x4d, 0x44, 0x7b, 0x72, 0x69, 0x60, 0x0e, 0x07, 0x1c, 0x15, 0x2a, 0x23, 0x38, 0x31, 0x46, 0x4f, 0x54, 0x5d, 0x62, 0x6b, 0x70, 0x79 }; IP_STATIC Ip_u8 crc8_tab[] = { 0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15, 0x38, 0x3f, 0x36, 0x31, 0x24, 0x23, 0x2a, 0x2d, 0x70, 0x77, 0x7e, 0x79, 0x6c, 0x6b, 0x62, 0x65, 0x48, 0x4f, 0x46, 0x41, 0x54, 0x53, 0x5a, 0x5d, 0xe0, 0xe7, 0xee, 0xe9, 0xfc, 0xfb, 0xf2, 0xf5, 0xd8, 0xdf, 0xd6, 0xd1, 0xc4, 0xc3, 0xca, 0xcd, 0x90, 0x97, 0x9e, 0x99, 0x8c, 0x8b, 0x82, 0x85, 0xa8, 0xaf, 0xa6, 0xa1, 0xb4, 0xb3, 0xba, 0xbd, 0xc7, 0xc0, 0xc9, 0xce, 0xdb, 0xdc, 0xd5, 0xd2, 0xff, 0xf8, 0xf1, 0xf6, 0xe3, 0xe4, 0xed, 0xea, 0xb7, 0xb0, 0xb9, 0xbe, 0xab, 0xac, 0xa5, 0xa2, 0x8f, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9d, 0x9a, 0x27, 0x20, 0x29, 0x2e, 0x3b, 0x3c, 0x35, 0x32, 0x1f, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0d, 0x0a, 0x57, 0x50, 0x59, 0x5e, 0x4b, 0x4c, 0x45, 0x42, 0x6f, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7d, 0x7a, 0x89, 0x8e, 0x87, 0x80, 0x95, 0x92, 0x9b, 0x9c, 0xb1, 0xb6, 0xbf, 0xb8, 0xad, 0xaa, 0xa3, 0xa4, 0xf9, 0xfe, 0xf7, 0xf0, 0xe5, 0xe2, 0xeb, 0xec, 0xc1, 0xc6, 0xcf, 0xc8, 0xdd, 0xda, 0xd3, 0xd4, 0x69, 0x6e, 0x67, 0x60, 0x75, 0x72, 0x7b, 0x7c, 0x51, 0x56, 0x5f, 0x58, 0x4d, 0x4a, 0x43, 0x44, 0x19, 0x1e, 0x17, 0x10, 0x05, 0x02, 0x0b, 0x0c, 0x21, 0x26, 0x2f, 0x28, 0x3d, 0x3a, 0x33, 0x34, 0x4e, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5c, 0x5b, 0x76, 0x71, 0x78, 0x7f, 0x6a, 0x6d, 0x64, 0x63, 0x3e, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2c, 0x2b, 0x06, 0x01, 0x08, 0x0f, 0x1a, 0x1d, 0x14, 0x13, 0xae, 0xa9, 0xa0, 0xa7, 0xb2, 0xb5, 0xbc, 0xbb, 0x96, 0x91, 0x98, 0x9f, 0x8a, 0x8d, 0x84, 0x83, 0xde, 0xd9, 0xd0, 0xd7, 0xc2, 0xc5, 0xcc, 0xcb, 0xe6, 0xe1, 0xe8, 0xef, 0xfa, 0xfd, 0xf4, 0xf3 }; /* **************************************************************************** * LOCAL PROTOTYPES **************************************************************************** */ /* Profile specific utility functions */ #ifdef IPROHC_UDP_SEND_UNCOMPRESSED IP_STATIC int iprohc_udp_get_payload_length(Ipcom_pkt *pkt); #endif IP_STATIC Ip_err iprohc_c_get_protocol(Ipcom_pkt *pkt, Ip_u8* proto, int* hdr_ptr); /* **************************************************************************** * LOCAL FUNCTIONS **************************************************************************** */ /* **************************************************************************** * PUBLIC FUNCTIONS **************************************************************************** */ /* *=========================================================================== * iprohc_find_interface *=========================================================================== * Description: Find a ROHC monitoring interface * Parameters: * Returns: * */ IP_PUBLIC Iprohc_interface * iprohc_find_interface(char *ifname) { Iprohc_interface *interface, *ninterface; if (iprohc.opened == IP_FALSE) { IPCOM_LOG0(INFO, "iprohc_find_interface, ROHC not opened yet\n"); return IP_NULL; } IPROHC_LOCK(); for (interface = IPCOM_LIST_FIRST(&iprohc.if_head); interface != IP_NULL; interface = ninterface) { char if_name[IPROHC_IF_NAME_MAX]; IPROHC_IF_LOCK(interface); ninterface = IPCOM_LIST_NEXT(&interface->interface_list); if (interface->have_unitNum) ipcom_sprintf(if_name, "%s%d", interface->name, interface->unitNum); else ipcom_sprintf(if_name, "%s", interface->name); IPROHC_IF_UNLOCK(interface); /* Find a peer entry with same address. */ if (ipcom_strcmp(if_name, ifname) == 0) { IPROHC_UNLOCK(); return interface; } } IPROHC_UNLOCK(); IPCOM_LOG0(DEBUG, "iprohc_find_interface: failed to find the interface"); return IP_NULL; } /* *=========================================================================== * iprohc_add_interface *=========================================================================== * Description: Add a ROHC monitoring interface * Parameters: * Returns: * */ IP_PUBLIC Ip_err iprohc_add_interface(char *name, Ip_bool have_num, Ip_u8 num) { Iprohc_interface *interface; char ifname[IPROHC_IF_NAME_MAX]; if (iprohc.opened == IP_FALSE) { IPCOM_LOG0(INFO, "iprohc_add_interface, ROHC not opened yet\n"); return IPCOM_ERR_NOT_OPENED; } if (have_num) ipcom_sprintf(ifname, "%s%d", name, num); else ipcom_sprintf(ifname, "%s", name); interface = iprohc_find_interface(ifname); if (interface != IP_NULL) { IPCOM_LOG0(INFO, "iprohc_add_interface, interface exists already\n"); return IPCOM_SUCCESS; } interface = (Iprohc_interface *)ipcom_malloc(sizeof(Iprohc_interface)); if (interface == IP_NULL) { IPCOM_LOG1(ERR, "iprohc_add_interface: out of memory (%ld bytes)", sizeof(Iprohc_interface)); return IPCOM_ERR_NO_MEMORY; } /* preinit the memory pointed by interface */ ipcom_memset(interface, 0, sizeof(Iprohc_interface)); ipcom_strncpy(interface->name, name,IPROHC_IF_NAME_MAX); interface->name[IPROHC_IF_NAME_MAX-1] = '\0'; interface->have_unitNum = have_num; interface->unitNum = num; /* Add the interface to the ROHC global data structure */ IPROHC_LOCK(); ipcom_list_insert_last(&iprohc.if_head, &interface->interface_list); iprohc.if_num++; IPROHC_UNLOCK(); /* create semaphore */ #ifdef IPROHC_ENABLE_REENTRANT (void)ipcom_mutex_create(&interface->code_mutex); #endif return IPCOM_SUCCESS; } /* *=========================================================================== * iprohc_del_interface *=========================================================================== * Description: Remove a ROHC monitoring interface * Parameters: * Returns: * */ IP_PUBLIC Ip_err iprohc_del_interface(char *name, Ip_bool have_num, Ip_u8 num) { Iprohc_interface *interface; char ifname[IPROHC_IF_NAME_MAX]; int i; if (iprohc.opened == IP_FALSE) { IPCOM_LOG0(INFO, "iprohc_del_interface, ROHC not opened yet\n"); return IPCOM_ERR_NOT_OPENED; } if (have_num) ipcom_sprintf(ifname, "%s%d", name, num); else ipcom_sprintf(ifname, "%s", name); interface = iprohc_find_interface(ifname); if (interface == IP_NULL) { IPCOM_LOG0(INFO, "iprohc_del_interface, interface not in monitoring list\n"); return IPCOM_SUCCESS; } /* Remove the interface from the ROHC global data structure and list */ IPROHC_LOCK(); ip_assert(iprohc.if_num > 0); iprohc.if_num--; IPROHC_UNLOCK(); IPROHC_IF_LOCK(interface); ipcom_list_remove(&interface->interface_list); /* delete all profiles configured for the interface */ for (i = 0; i < IPROHC_MAX_PROFILE_IDS; i++) if (interface->profiles[i]) (void)iprohc_if_del_profile(interface,(Ip_u8)i); /* delete the compressor associated with the interface */ iprohc_del_compressor(interface->compressor); /* delete the decompressor associated with the interface */ iprohc_del_decompressor(interface->decompressor); IPROHC_IF_UNLOCK(interface); #ifdef IPROHC_ENABLE_REENTRANT (void)ipcom_mutex_delete(&interface->code_mutex); #endif /* free the memory pointed by interface */ ipcom_free(interface); return IPCOM_SUCCESS; } /* *=========================================================================== * iprohc_remove_interfaces *=========================================================================== * Description: Remove all ROHC monitoring interfaces * Parameters: * Returns: * */ IP_PUBLIC Ip_err iprohc_remove_interfaces() { Iprohc_interface *interface, *ninterface; int i; if (iprohc.opened == IP_FALSE) { IPCOM_LOG0(INFO, "iprohc_remove_interfaces, ROHC not opened yet\n"); return IPCOM_ERR_NOT_OPENED; } IPROHC_LOCK(); for (interface = IPCOM_LIST_FIRST(&iprohc.if_head); interface != IP_NULL; interface = ninterface) { ninterface = IPCOM_LIST_NEXT(&interface->interface_list); /* Remove the interface from the ROHC global data structure and list */ ip_assert(iprohc.if_num > 0); iprohc.if_num--; ipcom_list_remove(&interface->interface_list); /* delete all profiles configured for the interface */ for (i = 0; i < IPROHC_MAX_PROFILE_IDS; i++) if (interface->profiles[i]) (void)iprohc_if_del_profile(interface, (Ip_u8)i); /* delete the compressor associated with the interface */ iprohc_del_compressor(interface->compressor); /* delete the decompressor associated with the interface */ iprohc_del_decompressor(interface->decompressor); #ifdef IPROHC_ENABLE_REENTRANT (void)ipcom_mutex_delete(&interface->code_mutex); #endif /* free the memory pointed by interface */ ipcom_free(interface); } IPROHC_UNLOCK(); return IPCOM_SUCCESS; } /* *=========================================================================== * iprohc_profile *=========================================================================== * Description: print out a ROHC profile. * Parameters: * Returns: * */ IP_PUBLIC char * iprohc_profile(Ip_u8 profile_id) { switch(profile_id) { case ROHC_PROFILE_UNCOMPRESSED: ipcom_strcpy(iprohc.buf, "uncompressed profile"); break; case ROHC_PROFILE_RTP_UDP_IP: ipcom_strcpy(iprohc.buf, "RTP/UDP/IP profile"); break; case ROHC_PROFILE_UDP_IP: ipcom_strcpy(iprohc.buf, "UDP/IP profile"); break; case ROHC_PROFILE_ESP_IP: ipcom_strcpy(iprohc.buf, "ESP/IP profile"); break; case ROHC_PROFILE_IP: ipcom_strcpy(iprohc.buf, "IP profile"); break; case ROHC_PROFILE_LLA_IP_UDP_RTP: ipcom_strcpy(iprohc.buf, "LLA IP/UDP/RTP profile"); break; case ROHC_PROFILE_TCP_IP: ipcom_strcpy(iprohc.buf, "TCP/IP profile"); break; default: ipcom_strcpy(iprohc.buf, "Unknown profile"); break; } return iprohc.buf; } /* *=========================================================================== * iprohc_find_profile *=========================================================================== * Description: Find whether a particular ROHC profile is configured. * Parameters: * Returns: * */ IP_PUBLIC Ip_err iprohc_find_profile(Ip_u8 profileid) { Ip_err retval = IPCOM_SUCCESS; #ifdef ROHC_DEBUG ipcom_printf("Calling iprohc_find_profile, profileid %d\n", profileid); #endif /* Validate the profile ID */ if (!IPROHC_VALID_PROFILE_ID(profileid)) { IPCOM_LOG0(ERR, "iprohc_find_profile, not a valid profile ID\n"); return IPCOM_ERR_INVALID_ARG; } IPROHC_LOCK(); if (iprohc.profiles[profileid].configured) { IPCOM_LOG1(INFO, "iprohc_find_profile, profile %d is configured\n", profileid); } else retval = IPCOM_ERR_NOT_FOUND; IPROHC_UNLOCK(); #ifdef ROHC_DEBUG ipcom_printf("iprohc_find_profile, profile %d\n is not configured\n", profileid); #endif return retval; } /* *=========================================================================== * iprohc_del_profile *=========================================================================== * Description: Remove a ROHC profile * Parameters: * Returns: * */ IP_PUBLIC Ip_err iprohc_del_profile(Ip_u8 profileid) { /* Validate the profile ID */ if (!IPROHC_VALID_PROFILE_ID(profileid)) { IPCOM_LOG0(ERR, "iprohc_del_profile, not a valid profile ID\n"); return IPCOM_ERR_INVALID_ARG; } /* De-register the profile */ if (iprohc.profiles[profileid].p_deregister != IP_NULL) iprohc.profiles[profileid].p_deregister(); return IPCOM_SUCCESS; } /* *=========================================================================== * iprohc_choose_profile *=========================================================================== * Description: Decide on a ROHC profile to compress a packet with. * Parameters: * Returns: * */ IP_PUBLIC Ip_s8 iprohc_choose_profile(Iprohc_interface *interface, Ipcom_pkt *pkt) { Ip_s8 profileid = -1; Ip_u8 proto; int hdr_ptr; #ifdef ROHC_DEBUG if (interface->have_unitNum) { ipcom_printf("Calling iprohc_choose_profile, interface %s%d\n", interface->name, interface->unitNum); } else { ipcom_printf("Calling iprohc_choose_profile, interface %s\n", interface->name); } #endif IPROHC_IF_LOCK(interface); if (iprohc_c_get_protocol(pkt, &proto, &hdr_ptr) == IPCOM_ERR_FAILED) goto leave; if ((proto == 6) && interface->profiles[ROHC_PROFILE_TCP_IP]) { profileid = ROHC_PROFILE_TCP_IP; /* Use pkt->tlstart to save the pointer to ESP header for ESP profile. This is safe */ pkt->tlstart = hdr_ptr; } else if ((proto == 17) && (interface->profiles[ROHC_PROFILE_UDP_IP])) { /* pkt->tlstart is not always set for the transport layer protocol by networking stack. Reset it. */ pkt->tlstart = hdr_ptr; /* In RTP/UDP packet less than 12 octets should be compressed with uncompressed profile */ #ifdef IPROHC_UDP_SEND_UNCOMPRESSED if (iprohc_udp_get_payload_length(pkt) <= 12) goto leave; else #endif profileid = ROHC_PROFILE_UDP_IP; } else if ((proto == 50) && (interface->profiles[ROHC_PROFILE_ESP_IP])) { profileid = ROHC_PROFILE_ESP_IP; /* Use pkt->tlstart to save the pointer to ESP header for ESP profile. This is safe */ pkt->tlstart = hdr_ptr; } else if (interface->profiles[ROHC_PROFILE_IP]) { profileid = ROHC_PROFILE_IP; } else if (interface->profiles[ROHC_PROFILE_UNCOMPRESSED]) { profileid = ROHC_PROFILE_UNCOMPRESSED; } leave: IPROHC_IF_UNLOCK(interface); return profileid; } /* *=========================================================================== * iprohc_choose_profile *=========================================================================== * Description: Decide on a ROHC profile to compress a packet with. * Parameters: * Returns: * */ IP_PUBLIC Ip_s8 iprohc_d_choose_profile(Iprohc_interface *interface, Ipcom_pkt *pkt) { Ip_s8 profileid = -1; int pointer = pkt->ipstart; Ip_u16 cid; Ip_u8 type_data; Iprohc_d_context *context, *ncontext; #ifdef ROHC_DEBUG if (interface->have_unitNum) { ipcom_printf("Calling iprohc_d_choose_profile, interface %s%d\n", interface->name, interface->unitNum); } else { ipcom_printf("Calling iprohc_d_choose_profile, interface %s\n", interface->name); } #endif IPROHC_IF_LOCK(interface); if (interface->decompressor == IP_NULL) goto l1; /* Get packet type, CID and profile ID */ IPROHC_GET_CID(pkt, pointer, cid, type_data) if (((type_data >> ROHC_PKT_IR_SHIFT) == ROHC_PKT_IR) || ( type_data == ROHC_PKT_IR_DYN)) { profileid = (Ip_s8)pkt->data[pointer]; if (interface->profiles[profileid] == IP_FALSE) profileid = -1; goto l1; } /* Lookup CID match in decompressor */ for (context = IPCOM_LIST_FIRST(&(interface->decompressor->context_head)); context != IP_NULL; context = ncontext) { ncontext = IPCOM_LIST_NEXT(&context->context_list); if (cid == context->cid) { profileid = (Ip_s8)context->profileid; if (interface->profiles[profileid] == IP_FALSE) { IPCOM_LOG0(ERR, "iprohc_d_choose_profile, mismatch of context and interface profiles ID\n"); ; profileid = -1; } goto l1; } } l1: IPROHC_IF_UNLOCK(interface); #ifdef ROHC_DEBUG ipcom_printf("Calling iprohc_d_choose_profile, interface %d\n", profileid); #endif return profileid; } /* *=========================================================================== * iprohc_if_find_profile *=========================================================================== * Description: Find whether a profile is configured on an interface * Parameters: * Returns: * */ IP_PUBLIC Ip_err iprohc_if_find_profile(Iprohc_interface *interface, Ip_u8 profileid) { Ip_err retval = IPCOM_SUCCESS; #ifdef ROHC_DEBUG if (interface->have_unitNum) { ipcom_printf("Enter iprohc_if_find_profile, interface %s%d, profileid %d\n", interface->name, interface->unitNum, profileid); } else { ipcom_printf("Enter iprohc_if_find_profile, interface %s, profileid %d\n", interface->name, profileid); } #endif /* Validate the profile ID */ if (!IPROHC_VALID_PROFILE_ID(profileid)) { IPCOM_LOG0(ERR, "iprohc_if_find_profile, not a valid profile ID\n"); return IPCOM_ERR_INVALID_ARG; } IPROHC_IF_LOCK(interface); if (interface->profiles[profileid]) { if (interface->have_unitNum) { IPCOM_LOG3(INFO, "iprohc_if_find_profile, profile %d is configured on interface %s%d\n", profileid, interface->name, interface->unitNum); } else { IPCOM_LOG2(INFO, "iprohc_if_find_profile, profile %d is configured on interface %s\n", profileid, interface->name); } IPROHC_IF_UNLOCK(interface); return retval; } IPROHC_IF_UNLOCK(interface); #ifdef ROHC_DEBUG ipcom_printf("iprohc_if_find_profile, profile %d\n is not configured\n", profileid); #endif return IPCOM_ERR_NOT_FOUND; } /* *=========================================================================== * iprohc_if_add_profile *=========================================================================== * Description: Add a ROHC profile to an interface * Parameters: * Returns: * */ IP_PUBLIC Ip_err iprohc_if_add_profile(Iprohc_interface *interface, Ip_u8 profileid) { #ifdef ROHC_DEBUG if (interface->have_unitNum) { ipcom_printf("Enter iprohc_if_add_profile, interface %s%d, profileid %d\n", interface->name, interface->unitNum, profileid); } else { ipcom_printf("Enter iprohc_if_add_profile, interface %s, profileid %d\n", interface->name, profileid); } #endif /* Check whether the profile is configured */ if (iprohc_find_profile(profileid) != IPCOM_SUCCESS) { IPCOM_LOG1(ERR, "iprohc_if_add_profile, not a configured profile %d\n", profileid); return IPCOM_ERR_INVALID_ARG; } IPROHC_IF_LOCK(interface); if (interface->profiles[profileid]) { IPCOM_LOG0(ERR, "iprohc_if_add_profile, profile already added\n"); IPROHC_IF_UNLOCK(interface); return IPCOM_SUCCESS; } interface->profile_num++; interface->profiles[profileid] = IP_TRUE; /* Initialize feedback lists for the profile */ ipcom_list_init(&interface->feedback_head[profileid]); /* Allocate a compressor structure for the profile */ if (interface->compressor == IP_NULL) interface->compressor = iprohc_alloc_compressor((struct Iprohc_interface *)interface); /* Allocate a decompressor structure for the profile */ if (interface->decompressor == IP_NULL) interface->decompressor = iprohc_alloc_decompressor((struct Iprohc_interface *)interface); IPROHC_IF_UNLOCK(interface); #ifdef ROHC_DEBUG ipcom_printf("iprohc_if_add_profile, added profile %d\n", profileid); #endif return IPCOM_SUCCESS; } /* *=========================================================================== * iprohc_if_del_profile *=========================================================================== * Description: Remove a ROHC profile from an interface * Parameters: * Returns: * */ IP_PUBLIC Ip_err iprohc_if_del_profile(Iprohc_interface *interface, Ip_u8 profileid) { Iprohc_feedback *feedback, *nfeedback; #ifdef ROHC_DEBUG if (interface->have_unitNum) { ipcom_printf("Enter iprohc_if_del_profile, interface %s%d, profileid %d\n", interface->name, interface->unitNum, profileid); } else { ipcom_printf("Enter iprohc_if_del_profile, interface %s, profileid %d\n", interface->name, profileid); } #endif /* Check whether the profile is configured */ if (iprohc_find_profile(profileid) != IPCOM_SUCCESS) { IPCOM_LOG1(ERR, "iprohc_if_del_profile, not a configured profile %d\n", profileid); return IPCOM_ERR_INVALID_ARG; } IPROHC_IF_LOCK(interface); if (!(interface->profiles[profileid])) { IPCOM_LOG0(ERR, "iprohc_if_del_profile, profile not configured\n"); IPROHC_IF_UNLOCK(interface); return IPCOM_SUCCESS; } interface->profile_num--; interface->profiles[profileid] = IP_FALSE; /* free all feedbacks associated with the profile */ for (feedback = IPCOM_LIST_FIRST(&interface->feedback_head[profileid]); feedback != IP_NULL; feedback = nfeedback) { nfeedback = IPCOM_LIST_NEXT(&feedback->feedback_list); interface->feedback_num[profileid]--; ipcom_list_remove(&feedback->feedback_list); ipcom_free(feedback); } iprohc_c_del_profile_contexts(interface->compressor, profileid); iprohc_d_del_profile_contexts(interface->decompressor, profileid); IPROHC_IF_UNLOCK(interface); #ifdef ROHC_DEBUG ipcom_printf("iprohc_if_del_profile, removed profile %d\n", profileid); #endif return IPCOM_SUCCESS; } /* *=========================================================================== * iprohc_update_rnd_nbo *=========================================================================== * Description: Update RND and NBO flags from old and new ip_id * Parameters: * Returns: * */ IP_PUBLIC void iprohc_update_rnd_nbo(Ip_u16 old_ipid, Ip_u16 ipid, Ip_bool *rnd, Ip_bool *nbo, Ip_bool *sid) { Ip_u16 tmp_old_ipid, tmp_ipid; #ifdef ROHC_DEBUG ipcom_printf("Enter iprohc_update_rnd_nbo, old_ipid %x, %d, ipid %x, %d\n", old_ipid, old_ipid, ipid, ipid); #endif tmp_old_ipid = ip_ntohs(old_ipid); tmp_ipid = ip_ntohs(ipid); /* Check for static IP ID */ if (old_ipid == ipid) *sid = IP_TRUE; else *sid = IP_FALSE; /* Check whether the to-be-transmitted IP-ID increments by 1 */ if ((tmp_ipid - tmp_old_ipid == 1) || ((tmp_old_ipid == 0xFFFF) && (tmp_ipid == 0))) { *nbo = IP_TRUE; *rnd = IP_FALSE; return; } /* Swap byte order of old_ipid and ipid */ tmp_old_ipid = (Ip_u16)(((old_ipid>>8) & 0x00FF) | ((old_ipid<<8) & 0xFF00)); tmp_ipid = (Ip_u16)(((ipid>>8) & 0x00FF) | ((ipid<<8) & 0xFF00)); tmp_old_ipid = ip_ntohs(tmp_old_ipid); tmp_ipid = ip_ntohs(tmp_ipid); /* Check whether after swapping bytes, IP-ID increments by 1 */ if (tmp_ipid - tmp_old_ipid == 1) { *nbo = IP_FALSE; *rnd = IP_FALSE; return; } /* IP-ID is a pseudo-random number. */ /* Don't worry about NBO in this case, keep the value as was. */ *rnd = IP_TRUE; } /* *=========================================================================== * iprohc_crc3 *=========================================================================== * Description: Calculate the 3-bit CRC value from a byte array * The CRC polynomial to be used for the 3-bit CRC is: * c(x) = 1 + x + x^3 * * Parameters: * Returns: 3-bit CRC value * */ IP_PUBLIC Ip_u8 iprohc_crc3(Ip_u8 *data, int len) { Ip_u8 crc3val = 0x7; Ip_u8 i; for (i = 0; i < len; i++) crc3val = crc3_tab[data[i]^(crc3val & 0x07)]; return crc3val; } /* *=========================================================================== * iprohc_crc7 *=========================================================================== * Description: Calculate the 7-bit CRC value from a byte array * The CRC polynomial to be used for the 7-bit CRC is: * c(x) = 1 + x + x^2 + x^3 + x^6 + x^7 * * Parameters: * Returns: 7-bit CRC value * */ IP_PUBLIC Ip_u8 iprohc_crc7(Ip_u8 *data, int len) { Ip_u8 crc7val = 0; Ip_u8 i; for (i = 0; i < len; i++) crc7val = crc7_tab[(crc7val << 1) ^ data[i]]; return crc7val; } /* *=========================================================================== * iprohc_crc8 *=========================================================================== * Description: Calculate the 8-bit CRC value from a byte array * The CRC polynomial to be used for the 8-bit CRC is: * c(x) = 1 + x + x^2 + x^8 * * Parameters: * Returns: 8-bit CRC value * */ IP_PUBLIC Ip_u8 iprohc_crc8(Ip_u8 *data, int len) { Ip_u8 crc8val = 0; Ip_u8 i; for (i = 0; i < len; i++) crc8val = crc8_tab[(crc8val ^ data[i]) & 0xff]; return crc8val; } /* *=========================================================================== * iprohc_print_pkt *=========================================================================== * Description: Debugging utility to print a packet * Parameters: * Returns: * */ IP_PUBLIC void iprohc_print_pkt(Ipcom_pkt *pkt) { int i; ipcom_printf("A packet: %x, start %d, ipstart %d, end %d, length %d\n", pkt, pkt->start, pkt->ipstart, pkt->end, pkt->end - pkt->ipstart); for (i = pkt->ipstart; i < pkt->end; i++) ipcom_printf("%x ", pkt->data[i]); ipcom_printf("\n"); } /* *=========================================================================== * iprohc_print_feedback *=========================================================================== * Description: Debugging utility to print a feedback structure * Parameters: * Returns: * */ IP_PUBLIC void iprohc_print_feedback(Iprohc_feedback *feedback) { int i; char buf[48], srcbuf[48]; ipcom_printf("A feedback: %x\n", feedback); ipcom_printf(" packet type: %s\n", (feedback->packet_type==ROHC_PKT_IPV4)?"IPv4":"IPv6"); #ifdef IPCOM_USE_INET if (feedback->packet_type == ROHC_PKT_IPV4) { /* An IPv4 packet */ (void)ipcom_inet_ntop(IP_AF_INET, &feedback->dst.addr4.addr32, buf, sizeof(buf)); (void)ipcom_inet_ntop(IP_AF_INET, &feedback->src.addr4.addr32, srcbuf, sizeof(srcbuf)); } #ifdef IPCOM_USE_INET6 else #endif #endif /* #ifdef IPCOM_USE_INET */ #ifdef IPCOM_USE_INET6 { (void)ipcom_inet_ntop(IP_AF_INET6, &feedback->dst.addr6, buf, sizeof(buf)); (void)ipcom_inet_ntop(IP_AF_INET6, &feedback->src.addr6, srcbuf, sizeof(srcbuf)); } #endif /* #ifdef IPCOM_USE_INET6 */ ipcom_printf(" src address: %s\n", srcbuf); ipcom_printf(" dst address: %s\n", buf); ipcom_printf(" size: %d\n", feedback->size); ipcom_printf(" data: "); for (i = 0; i < feedback->size; i++) ipcom_printf("%x ", feedback->data[i]); ipcom_printf("\n"); } /* *=========================================================================== * iprohc_pkt_type *=========================================================================== * Description: Debugging utility to print a packet * Parameters: * Returns: * */ IP_PUBLIC char * iprohc_pkt_type(Ip_u8 pkt_type) { switch (pkt_type) { case ROHC_PKT_NORMAL: ipcom_strcpy(iprohc.buf, "Normal IP v4/v6 Packet"); break; case ROHC_PKT_COMPRESSED: ipcom_strcpy(iprohc.buf, "Compressed Packet"); break; case ROHC_PKT_COMP_UNCOMPRESSED: ipcom_strcpy(iprohc.buf, "Uncompressed Packet"); break; case ROHC_PKT_FEEDBACK: ipcom_strcpy(iprohc.buf, "Feedback Packet"); break; case ROHC_PKT_IR_DYN: ipcom_strcpy(iprohc.buf, "IR-DYN Packet"); break; case ROHC_PKT_IR: ipcom_strcpy(iprohc.buf, "IR Packet"); break; case ROHC_PKT_SEGMENT: ipcom_strcpy(iprohc.buf, "Segment Packet"); break; case ROHC_PKT_TYPE_0: ipcom_strcpy(iprohc.buf, "Compressed Type 0 Packet"); break; case ROHC_PKT_TYPE_1: ipcom_strcpy(iprohc.buf, "Compressed Type 1 Packet"); break; case ROHC_PKT_TYPE_2: ipcom_strcpy(iprohc.buf, "Compressed Type 2 Packet"); break; case ROHC_TCP_PKT_IR: ipcom_strcpy(iprohc.buf, "IR(TCP) Packet"); break; case ROHC_TCP_PKT_CO: ipcom_strcpy(iprohc.buf, "ROHC_TCP_PKT_CO Packet"); break; case ROHC_TCP_PKT_RND_1: ipcom_strcpy(iprohc.buf, "ROHC_TCP_PKT_RND_1 Packet"); break; /* case ROHC_TCP_PKT_RND_3: ipcom_strcpy(iprohc.buf, "ROHC_TCP_PKT_RND_3 Packet"); break; */ case ROHC_TCP_PKT_RND_5: ipcom_strcpy(iprohc.buf, "ROHC_TCP_PKT_RND_5 Packet"); break; case ROHC_TCP_PKT_RND_7: ipcom_strcpy(iprohc.buf, "ROHC_TCP_PKT_RND_7 Packet"); break; case ROHC_TCP_PKT_SEQ_1: ipcom_strcpy(iprohc.buf, "ROHC_TCP_PKT_SEQ_1 Packet"); break; case ROHC_TCP_PKT_SEQ_3: ipcom_strcpy(iprohc.buf, "ROHC_TCP_PKT_SEQ_3 Packet"); break; case ROHC_TCP_PKT_SEQ_5: ipcom_strcpy(iprohc.buf, "ROHC_TCP_PKT_SEQ_5 Packet"); break; case ROHC_TCP_PKT_SEQ_7: ipcom_strcpy(iprohc.buf, "ROHC_TCP_PKT_SEQ_7 Packet"); break; default: ipcom_strcpy(iprohc.buf, "Illegal Packet"); break; } return iprohc.buf; } /* *=========================================================================== * iprohc_context_mode *=========================================================================== * Description: Debugging utility to print a context mode * Parameters: * Returns: * */ IP_PUBLIC char * iprohc_context_mode(Iprohc_mode mode) { switch (mode) { case ROHC_MODE_C: ipcom_strcpy(iprohc.buf, "C-mode"); break; case ROHC_MODE_U: ipcom_strcpy(iprohc.buf, "U-mode"); break; case ROHC_MODE_O: ipcom_strcpy(iprohc.buf, "O-mode"); break; case ROHC_MODE_R: ipcom_strcpy(iprohc.buf, "R-mode"); break; default: ipcom_strcpy(iprohc.buf, "Illegal"); break; } return iprohc.buf; } /* *=========================================================================== * iprohc_ext_type *=========================================================================== * Description: Debugging utility to print a packet extension type * Parameters: * Returns: * */ IP_PUBLIC char * iprohc_ext_type(Iprohc_extension extension) { switch (extension) { case ROHC_EXT_NO_EXT: ipcom_strcpy(iprohc.buf, "No extension"); break; case ROHC_EXT_0: ipcom_strcpy(iprohc.buf, "Extension 0"); break; case ROHC_EXT_1: ipcom_strcpy(iprohc.buf, "Extension 1"); break; case ROHC_EXT_2: ipcom_strcpy(iprohc.buf, "Extension 2"); break; case ROHC_EXT_3: ipcom_strcpy(iprohc.buf, "Extension 3"); break; default: ipcom_strcpy(iprohc.buf, "Illegal"); break; } return iprohc.buf; } #ifndef IP_PORT_VXWORKS /* for Linux recursive semaphore */ /* *=========================================================================== * iprohc_if_lck *=========================================================================== * Description: This function provides a recursive semaphore lock to an ROHC * monitoring interface. * Parameters: * Returns: * */ IP_PUBLIC void iprohc_if_lck(Iprohc_interface *interface) { Ip_pid_t cpid = ipcom_getpid(); #ifdef ROHC_DEBUG ipcom_printf("Calling iprohc_if_lck: pid %d, counter %d, cpid %d\n", interface->pid, interface->s_counter, cpid); #endif if (interface->pid == 0) { /* No one has semaphore, take it */ interface->pid = cpid; interface->s_counter = 1; ipcom_mutex_lock(interface->code_mutex); } else if (interface->pid != cpid) /* block a different process/task */ ipcom_mutex_lock(interface->code_mutex); else /* the semaphore is taken by the same process, increase the counter */ interface->s_counter ++; #ifdef ROHC_DEBUG ipcom_printf("iprohc_if_lck: pid %d, counter %d, cpid %d\n", interface->pid, interface->s_counter, cpid); #endif } /* *=========================================================================== * iprohc_if_unlck *=========================================================================== * Description: This function provides a recursive semaphore unlock to an * ROHC monitoring interface. * Parameters: * Returns: * */ IP_PUBLIC void iprohc_if_unlck(Iprohc_interface *interface) { Ip_pid_t cpid = ipcom_getpid(); #ifdef ROHC_DEBUG ipcom_printf("Calling iprohc_if_unlck: pid %d, counter %d, cpid %d\n", interface->pid, interface->s_counter, cpid); #endif if (interface->pid != cpid) { IPCOM_LOG0(ERR, "iprohc_if_unlck: released by a different process "); return; } /* decrease the counter */ interface->s_counter --; if (interface->s_counter == 0) { /* clear the semaphore PID */ interface->pid = 0; /* release the semaphore */ ipcom_mutex_unlock(interface->code_mutex); } #ifdef ROHC_DEBUG ipcom_printf("iprohc_if_unlck: pid %d, counter %d, cpid %d\n", interface->pid, interface->s_counter, cpid); #endif } #endif /* !IP_PORT_VXWORKS */ #ifdef IPROHC_UDP_SEND_UNCOMPRESSED /* *=========================================================================== * iprohc_udp_get_payload_length *=========================================================================== * Description: Get UDP packet length * Parameters: * Returns: * */ IP_STATIC int iprohc_udp_get_payload_length(Ipcom_pkt *pkt) { Ip_u16 data, length = 0; ipcom_memcpy((Ip_u8 *) &data, (Ip_u8 *) &pkt->data[pkt->tlstart + 4], 2); length = ipcom_ntohs(data); #ifdef ROHC_DEBUG ipcom_printf("iprohc_udp_get_payload_length: pkt->tlstart %d, udp pkt length %d\n", pkt->tlstart, length); #endif return (int)length; } #endif /* *=========================================================================== * iprohc_c_get_protocol *=========================================================================== * Description: Get the transport layer protocol * Parameters: * Returns: * */ IP_STATIC Ip_err iprohc_c_get_protocol(Ipcom_pkt *pkt, Ip_u8* proto, int* hdr_ptr) { Ip_err retval = IPCOM_SUCCESS; int pointer = pkt->ipstart; Ip_u8 length = 0; *hdr_ptr = -1; while (pointer != -1) { #ifdef IPCOM_USE_INET if ((pkt->data[pointer] >> 4) == 4) { /* An IPv4 packet */ Ipcom_ip_header *ip4 = (Ipcom_ip_header *)&pkt->data[pointer]; /* Check the protocl field */ if ((ip4->protocol == IP_IPPROTO_IPIP) || (ip4->protocol == IP_IPPROTO_IPV6)) { /* Next header is IPinIP or IPv6, move pointer */ pointer += 4 * (pkt->data[pointer] & 0x0F); *proto = ip4->protocol; } else if (IPROHC_PROC_EXT(ip4->protocol)) { /* Move pointer to point to the extension header */ pointer += 4*(pkt->data[pointer]&0x0F); *proto = ip4->protocol; do { if (IPROHC_IP6_EXT(*proto)) /* * IPv6 ext header, Hdr-ext-len (second octet of the ext header) * is the length of the extension header in 8-octet units, not * including the first 8 octets. */ length = (Ip_u8)(8 * (pkt->data[pointer+1] + 1)); else { /* minimal encapsulation header */ if (pkt->data[pointer+1] & 0x80) length = 12; else length = 8; } /* Get type of the next header and move the pointer to next ext header */ *proto = pkt->data[pointer]; pointer += length; }while (IPROHC_PROC_EXT(*proto)); *hdr_ptr = pointer; pointer = -1; } else { /* The end of IP header, exit from while loop */ *hdr_ptr = pointer + 4*(pkt->data[pointer]&0x0F); *proto = ip4->protocol; pointer = -1; } } #ifdef IPCOM_USE_INET6 else #endif #endif /* #ifdef IPCOM_USE_INET */ #ifdef IPCOM_USE_INET6 if ((pkt->data[pointer] >> 4) == 6) { /* An IPv6 packet */ Ipcom_ip6_header *ip6 = (Ipcom_ip6_header *)&pkt->data[pointer]; /* Check the protocl field */ if (ip6->nxt == IP_IPPROTO_IPV6) { /* Next header is IPv6, move pointer */ pointer += IPROHC_IP6_HDR_SIZE; *proto = ip6->nxt; } else if IPROHC_PROC_EXT(ip6->nxt) { /* Move pointer to point to the extension header */ pointer += IPROHC_IP6_HDR_SIZE; /* Creat reference list for IP extension headers */ *proto = ip6->nxt; do { if (IPROHC_IP6_EXT(*proto)) /* * IPv6 ext header, Hdr-ext-len (second octet of the ext header) * is the length of the extension header in 8-octet units, not * including the first 8 octets. */ length = (Ip_u8)(8 * (pkt->data[pointer+1] + 1)); else { /* minimal encapsulation header */ if (pkt->data[pointer+1] & 0x80) length = 12; else length = 8; } /* Get type of the next header and move the pointer to next ext header */ *proto = pkt->data[pointer]; pointer += length; }while (IPROHC_PROC_EXT(*proto)); *hdr_ptr = pointer; pointer = -1; } else { *hdr_ptr = pointer + IPROHC_IP6_HDR_SIZE; *proto = ip6->nxt; /* The end of IP header, exit from while loop */ pointer = -1; } } #endif /* #ifdef IPCOM_USE_INET6 */ } #ifdef ROHC_DEBUG ipcom_printf("iprohc_c_get_protocol: protocol %d, hdr_ptr %d, pkt->tlstart %d, pointer %d\n", *proto, *hdr_ptr, pkt->tlstart, pointer); #endif if (*hdr_ptr == -1) retval = IPCOM_ERR_FAILED; return retval; } /* **************************************************************************** * END OF FILE **************************************************************************** */