/* iprohc_comp.c - ROHC compressor utility routines */ /* * Copyright (c) 2008-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 01n,21nov12,ggz Defect WIND00387435. Validate comp/decomp ptrs before usage 01m,01oct12,ggz Use cid = 1 instead of random val. Defect WIND00380294 01l,20oct11,ggz Fix for defect WIND00312450 01k,11feb11,ggz Fix for defect WIND00254208 01j,10feb11,ggz Resolve a lock issue for non vxworks port. Defet WIND00254463 01i,13apr10,ggz Resolve 64bit compiler warnings 01h,24feb09,tlu Replace ipcom_tmo by ipnet_timeout to port to LKM 01g,15jul08,tlu Add for CID bit map allocation 01f,03jul08,tlu Modify to call ipcom_random only to init CID and release context lock when finding a context 01e,15jun08,ggz Added normal state to iprohc_comp_state for uncompressed profile 01d,23jun08,tlu Modify to init CID with a random number 01c,12may08,tlu Add more debugging functions 01b,30apr08,tlu Add debug function to print compression context 01a,07mar08,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" /* **************************************************************************** * 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 **************************************************************************** */ IP_STATIC Iprohc_c_context * iprohc_c_find_context_by_cid(Iprohc_compressor *comp, Ip_u16 cid, Ip_u8 src_addr_type, void *src_addr); /* **************************************************************************** * LOCAL FUNCTIONS **************************************************************************** */ /* *=========================================================================== * iprohc_c_find_context_by_cid *=========================================================================== * Description: Find a compression context according to CID and source * address of the feedback pkt. * Parameters: * Returns: * */ IP_STATIC Iprohc_c_context * iprohc_c_find_context_by_cid(Iprohc_compressor *comp, Ip_u16 cid, Ip_u8 src_addr_type, void *src_addr) { Iprohc_c_context *context, *ncontext; #ifdef IPCOM_USE_INET Ipa_union *addr4 = IP_NULL; #endif #ifdef IPCOM_USE_INET6 struct Ip_in6_addr *addr6 = IP_NULL; #endif #ifdef ROHC_DEBUG ipcom_printf("Enter iprohc_c_find_context_by_cid\n"); #endif if (src_addr) { #ifdef IPCOM_USE_INET if (src_addr_type == ROHC_PKT_IPV4) addr4 = (Ipa_union *)src_addr; #ifdef IPCOM_USE_INET6 else #endif /* IPCOM_USE_INET6 */ #endif #ifdef IPCOM_USE_INET6 if (src_addr_type == ROHC_PKT_IPV6) addr6 = (struct Ip_in6_addr *)src_addr; #endif } IPROHC_COMP_LOCK(comp); for (context = IPCOM_LIST_FIRST(&comp->context_head); context != IP_NULL; context = ncontext) { ncontext = IPCOM_LIST_NEXT(&context->context_list); IPROHC_C_CONTEXT_LOCK(context); /* Check the CID */ if (context->cid == cid) { /* Check the address if supplied*/ #ifdef IPCOM_USE_INET if (addr4 && (context->stream_type == ROHC_PKT_IPV4) && (addr4->addr32 == context->dst.addr4.addr32)) goto findit; #ifdef IPCOM_USE_INET6 else #endif /* #ifdef IPCOM_USE_INET6 */ #endif /* #ifdef IPCOM_USE_INET */ #ifdef IPCOM_USE_INET6 if (addr6 && (context->stream_type == ROHC_PKT_IPV6) && (ipcom_memcmp(addr6, &context->dst.addr6, sizeof(struct Ip_in6_addr)) == 0)) goto findit; #endif /* #ifdef IPCOM_USE_INET6 */ else goto next_c; /* Find the context, return it */ findit: IPROHC_C_CONTEXT_UNLOCK(context); IPROHC_COMP_UNLOCK(comp); return context; } next_c: IPROHC_C_CONTEXT_UNLOCK(context); } IPROHC_COMP_UNLOCK(comp); /* Didn't find the context, return IP_NULL */ return IP_NULL; } /* **************************************************************************** * PUBLIC FUNCTIONS **************************************************************************** */ /* *=========================================================================== * iprohc_alloc_compressor *=========================================================================== * Description: Allocate a ROHC compressor structure * Parameters: * Returns: * */ IP_PUBLIC Iprohc_compressor * iprohc_alloc_compressor(struct Iprohc_interface *interface) { Iprohc_compressor *comp; Ip_u32 ra = ipcom_random() & 0x7; Ip_u16 cid_map_size; /* Allocate and pre-init compressor structure */ comp = (Iprohc_compressor *)ipcom_malloc(sizeof(Iprohc_compressor)); if(comp == IP_NULL) return IP_NULL; ipcom_memset(comp, 0, sizeof(Iprohc_compressor)); /* Allocate CID bit map */ cid_map_size = (Ip_u16)((iprohc.max_cid+1)/16); if ((iprohc.max_cid+1) % 16) cid_map_size = (Ip_u16)(cid_map_size + 1); comp->bit_map_size = cid_map_size; comp->cid_bit_map = ipcom_malloc(2 * cid_map_size); if(comp->cid_bit_map == IP_NULL) { ipcom_free(comp); return IP_NULL; } ipcom_memset(comp->cid_bit_map, 0, (2*cid_map_size)); /* Mark CID 0 as used in the bit map */ comp->cid_bit_map[0] |= 1; comp->interface = interface; /* init the next to-be-used CID to a random not 0 value (won't use 0 * as CID) to avoid confusing of the ADD-CID octet with the PADDING * octet */ comp->to_be_used_cid = (Ip_u16)(ra?ra:1); /* init list */ ipcom_list_init(&(comp->context_head)); #ifdef IPROHC_ENABLE_REENTRANT (void)ipcom_mutex_create(&comp->code_mutex); #endif return comp; } /* *=========================================================================== * iprohc_del_compressor *=========================================================================== * Description: Free a ROHC compressor structure * Parameters: * Returns: * */ IP_PUBLIC Ip_err iprohc_del_compressor(Iprohc_compressor *compressor) { Ip_err retval = IPCOM_SUCCESS; Iprohc_c_context *context, *ncontext; /* just return IPCOM_SUCCESS for a NULL compressor */ if (compressor == IP_NULL) return retval; IPROHC_COMP_LOCK(compressor); /* free cid_bit_map */ ipcom_free(compressor->cid_bit_map); for (context = IPCOM_LIST_FIRST(&compressor->context_head); context != IP_NULL; context = ncontext) { ncontext = IPCOM_LIST_NEXT(&context->context_list); compressor->context_num--; /* free the context */ iprohc.profiles[context->profileid].c_del_context(context); } IPROHC_COMP_UNLOCK(compressor); #ifdef IPROHC_ENABLE_REENTRANT (void)ipcom_mutex_delete(&compressor->code_mutex); #endif /* free the compressor */ ipcom_free(compressor); return retval; } /* *=========================================================================== * iprohc_c_del_profile_contexts *=========================================================================== * Description: Free contexts associated with a profile * Parameters: * Returns: * */ IP_PUBLIC Ip_err iprohc_c_del_profile_contexts(Iprohc_compressor *compressor, Ip_u8 profileid) { Ip_err retval = IPCOM_SUCCESS; Iprohc_c_context *context, *ncontext; Ip_u16 i, j, m = 0; /* just return IPCOM_SUCCESS for a NULL compressor */ if (compressor == IP_NULL) return retval; IPROHC_COMP_LOCK(compressor); for (context = IPCOM_LIST_FIRST(&compressor->context_head); context != IP_NULL; context = ncontext) { ncontext = IPCOM_LIST_NEXT(&context->context_list); if (context->profileid != profileid) continue; compressor->context_num--; /* find the next cid to be allocated */ i = (Ip_u16)((int)context->cid / 16); j = (Ip_u16)((int)context->cid % 16); m = (Ip_u16)(1 << j); m = (Ip_u16)~m; /* Reset CID used flag */ compressor->cid_bit_map[i] = compressor->cid_bit_map[i] & m; /* free the context */ iprohc.profiles[context->profileid].c_del_context(context); } IPROHC_COMP_UNLOCK(compressor); return retval; } /* *=========================================================================== * iprohc_comp_mod_cid *=========================================================================== * Description: Allocate a ROHC compressor structure * Parameters: * Returns: * */ IP_PUBLIC Ip_err iprohc_comp_mod_cid(struct Iprohc_interface *interface, Ip_u8 profileid, Ip_u16 cid) { Iprohc_compressor *comp; #ifdef ROHC_DEBUG if (((Iprohc_interface *)interface)->have_unitNum) { ipcom_printf("Enter iprohc_comp_mod_cid, interface %s%d, profileid %d, cid %d\n", ((Iprohc_interface *)interface)->name, ((Iprohc_interface *)interface)->unitNum, profileid, cid); } else { ipcom_printf("Enter iprohc_comp_mod_cid, interface %s, profileid %d, cid %d\n", ((Iprohc_interface *)interface)->name, profileid, cid); } #endif /* Check whether the profile is configured */ if (iprohc_find_profile(profileid) != IPCOM_SUCCESS) { IPCOM_LOG1(ERR, "iprohc_comp_mod_cid, not a configured profile %d\n", profileid); return IPCOM_ERR_INVALID_ARG; } /* Validate CID value */ if ((cid < 1) || (cid > iprohc.max_cid)) { IPCOM_LOG2(ERR, "iprohc_comp_mod_cid, %d not in valid cid range [1, %d]\n", cid, iprohc.max_cid); return IPCOM_ERR_INVALID_ARG; } comp = ((Iprohc_interface *)interface)->compressor; IPROHC_COMP_LOCK(comp); /* init the next to-be-used CID to a random not 0 value (won't use 0 * as CID) to avoid confusing of the ADD-CID octet with the PADDING * octet */ comp->to_be_used_cid = cid; IPROHC_COMP_UNLOCK(comp); #ifdef ROHC_DEBUG ipcom_printf("iprohc_comp_mod_cid, modified next to be used cid\n"); #endif return IPCOM_SUCCESS; } /* *=========================================================================== * iprohc_c_context_common_create *=========================================================================== * Description: Allocate a ROHC compression context common structure * Parameters: * Returns: * */ IP_PUBLIC Iprohc_c_context * iprohc_c_context_common_create(Ip_u16 cid) { Iprohc_c_context *c_context; /* Allocate and pre-init compression context structure */ c_context = (Iprohc_c_context *)ipcom_malloc(sizeof(Iprohc_c_context)); if (c_context == IP_NULL) { IPCOM_LOG0(ERR,"iprohc_c_context_common_create, out of memory"); return IP_NULL; } ipcom_memset(c_context, 0, sizeof(Iprohc_c_context)); /* Initialize the context fields */ c_context->cid = cid; c_context->state = ROHC_COMP_STATE_IR; c_context->mode = ROHC_MODE_U; c_context->pkt_type = ROHC_PKT_IR; #ifdef IPROHC_ENABLE_REENTRANT (void)ipcom_mutex_create(&c_context->code_mutex); #endif return c_context; } /* *=========================================================================== * iprohc_c_context_common_del *=========================================================================== * Description: Free a ROHC compression context common structure * Parameters: * Returns: * */ IP_PUBLIC Ip_err iprohc_c_context_common_del(Iprohc_c_context *c_context) { /* Cancel the timer. */ ipnet_timeout_cancel(c_context->retx_ir); #ifdef IPROHC_ENABLE_REENTRANT (void)ipcom_mutex_delete(&c_context->code_mutex); #endif ipcom_free(c_context); return IPCOM_SUCCESS; } /* *=========================================================================== * iprohc_c_process_feedback *=========================================================================== * Description: Process the received feedback elements from the decompressor * * Feedback consists of one or more concatenated feedback elements, * where each feedback element has the following format: * * --------------------------- * | 1 1 1 1 0 | Code | feedback type octet * --------------------------- * : Size : if Code = 0 * --------------------------- * / feedback data / variable length * --------------------------- * * 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 / * --------------------------- * * Parameters: * Returns: * */ IP_PUBLIC Ip_err iprohc_c_process_feedback(Iprohc_compressor *compressor, Ip_u8 src_addr_type, void *src_addr, Ip_u16 feedback_num, Ip_u8 *feedbacks) { Ip_err retval = IPCOM_SUCCESS; Ip_u8 pointer = 0, fb_p = 0; Ip_u8 size, data_size; Ip_u16 cid = 0, i; Iprohc_c_context *context; #ifdef ROHC_DEBUG ipcom_printf("Enter iprohc_c_process_feedback, feedback_num %d, feedback %x\n", feedback_num, feedbacks); #endif if (compressor == IP_NULL) goto leave; for (i = 0; i < feedback_num; i++) { #ifdef ROHC_DEBUG ipcom_printf("iprohc_c_process_feedback(for), i %d, pointer %d, feedbacks[pointer] %x\n", i, pointer, feedbacks[pointer]); #endif if ((feedbacks[pointer]>>ROHC_PKT_FEEDBACK_SHIFT) != ROHC_PKT_FEEDBACK) { /* Pass in a non feedback element */ IPCOM_LOG0(ERR, "iprohc_c_process_feedback, not a feedback element\n"); IPROHC_LEAVE(IPCOM_ERR_INVALID_ARG); } /* Get the size */ if ((feedbacks[pointer] & 0x07) == 0) { /* move the pointer */ pointer++; data_size = size = feedbacks[pointer]; /* Count Size octet */ size ++; } else data_size = size = (Ip_u8)(feedbacks[pointer] & 0x07); #ifdef ROHC_DEBUG ipcom_printf("iprohc_c_process_feedback, data_size %d, size %d\n", data_size, size); #endif /* Move the pointer */ pointer++; /* get the CID */ if (iprohc.large_cid) { /* * Decode cid according to RFC 3095, 4.5.6. * RFC 3095, section 5.2.2: If the first bit is 0, the CID uses * one octet. If the first bit is 1, the CID uses two octet. */ if ((feedbacks[pointer] & 0x80) == 0) cid = feedbacks[pointer]; else { ipcom_memcpy(&cid, &(feedbacks[pointer]), 2); cid = ip_ntohs(cid); cid = (Ip_u16)(cid & 0x7fff); } } else if ((feedbacks[pointer]>>ROHC_PKT_ADD_CID_SHIFT) == ROHC_PKT_ADD_CID) { /* Small CID */ cid = (Ip_u16)(feedbacks[pointer] & 0x0F); } else cid = 0; #ifdef ROHC_DEBUG ipcom_printf("iprohc_c_process_feedback, cid %d, size %d\n", cid, size); #endif /* Find the context according to cid and source address */ context = iprohc_c_find_context_by_cid(compressor, cid, src_addr_type, src_addr); #ifdef ROHC_DEBUG if (context) { ipcom_printf("iprohc_c_process_feedback, find a c_context\n"); iprohc_c_print_a_context(context); } else ipcom_printf("iprohc_c_process_feedback, didn't find a c_context\n"); #endif /* Dispatch the feedback field to the compressor context */ if (context) iprohc.profiles[context->profileid].c_process_feedback(context, feedbacks+fb_p+size-data_size+1, data_size); /* Move pointer and fb_p to point to the next feedback element */ fb_p = (Ip_u8)(fb_p + 1 + size); pointer = fb_p; #ifdef ROHC_DEBUG ipcom_printf("iprohc_c_process_feedback, fb_p %d, pointer %d\n", fb_p, pointer); #endif } leave: ipcom_free(feedbacks); return retval; } /* *=========================================================================== * iprohc_retx_ir_timeout *=========================================================================== * Description: Set next transmitting packet type to be IR if the compression * context is not in Pending state. * Parameters: * Returns: * */ IP_PUBLIC void iprohc_retx_ir_timeout(void *cookie) { Iprohc_c_context *c_context; #ifdef ROHC_DEBUG ipcom_printf("iprohc_retx_ir_timeout: retx IR timer times out\n"); #endif c_context = (Iprohc_c_context *)cookie; IPROHC_C_CONTEXT_LOCK(c_context); if (c_context->trans != ROHC_COMP_TRANS_PENDING) { c_context->pkt_type = ROHC_PKT_IR; c_context->ext_type = ROHC_EXT_NO_EXT; } IPROHC_C_CONTEXT_UNLOCK(c_context); } /* *=========================================================================== * iprohc_c_print_a_context *=========================================================================== * Description: For debugging -- print out a compression context * Parameters: * Returns: * */ IP_PUBLIC void iprohc_c_print_a_context(Iprohc_c_context *context) { Ip_u8 profileid; char buf[48], srcbuf[48]; profileid = context->profileid; ipcom_printf(" Compression Context (%x):\n", context); ipcom_printf(" cid: %d\n", context->cid); ipcom_printf(" state: %s\n", iprohc_comp_state(context->state)); ipcom_printf(" mode: %s\n", iprohc_context_mode(context->mode)); ipcom_printf(" decline_mode_trans: %s\n", context->decline_mode_trans?"Yes":"No"); ipcom_printf(" trans: %s\n", iprohc_comp_trans(context->trans)); ipcom_printf(" pkt_type: %s\n", iprohc_pkt_type(context->pkt_type)); ipcom_printf(" ext_type: %s\n", iprohc_ext_type(context->ext_type)); ipcom_printf(" reject: %s\n", context->reject?"Yes":"No"); ipcom_printf(" num_ir: %d\n", context->num_ir); ipcom_printf(" num_compressed: %d\n", context->num_compressed); ipcom_printf(" stream type: %s\n", (context->stream_type==ROHC_PKT_IPV4)?"IPv4":"IPv6"); if (context->stream_type == ROHC_PKT_IPV4) #ifdef IPCOM_USE_INET { (void)ipcom_inet_ntop(IP_AF_INET, &context->dst.addr4.addr32, buf, sizeof(buf)); (void)ipcom_inet_ntop(IP_AF_INET, &context->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, &context->dst.addr6, buf, sizeof(buf)); (void)ipcom_inet_ntop(IP_AF_INET6, &context->src.addr6, srcbuf, sizeof(srcbuf)); } #endif /* #ifdef IPCOM_USE_INET6 */ ipcom_printf(" src address: %s\n", srcbuf); ipcom_printf(" dst address: %s\n", buf); /* Print profile specific compression context */ iprohc.profiles[profileid].c_print_context(context); } /* *=========================================================================== * iprohc_c_print_context *=========================================================================== * Description: Print out all the contexts in the compressor * Parameters: * Returns: * */ IP_PUBLIC Ip_err iprohc_c_print_context(Iprohc_compressor *compressor, Ip_u8 profile) { Ip_err retval = IPCOM_SUCCESS; Iprohc_c_context *context, *ncontext; if (compressor == IP_NULL) return retval; if (compressor->context_num == 0) { ipcom_printf(" Compression Context: None\n"); return retval; } for (context = IPCOM_LIST_FIRST(&compressor->context_head); context != IP_NULL; context = ncontext) { ncontext = IPCOM_LIST_NEXT(&context->context_list); if (context->profileid != profile) continue; iprohc_c_print_a_context(context); } return retval; } /* *=========================================================================== * iprohc_comp_state *=========================================================================== * Description: Debugging utility to print a compression context state * Parameters: * Returns: * */ IP_PUBLIC char * iprohc_comp_state(Iprohc_comp_state state) { switch (state) { case ROHC_COMP_STATE_IR: ipcom_strcpy(iprohc.buf, "IR"); break; case ROHC_COMP_STATE_FO: ipcom_strcpy(iprohc.buf, "FO"); break; case ROHC_COMP_STATE_SO: ipcom_strcpy(iprohc.buf, "SO"); break; case ROHC_COMP_STATE_NORMAL: ipcom_strcpy(iprohc.buf, "NORM"); break; default: ipcom_strcpy(iprohc.buf, "Illegal"); break; } return iprohc.buf; } /* *=========================================================================== * iprohc_comp_trans *=========================================================================== * Description: Debugging utility to print a compression context mode * transition state * Parameters: * Returns: * */ IP_PUBLIC char * iprohc_comp_trans(Iprohc_comp_trans trans) { switch (trans) { case ROHC_COMP_TRANS_DONE: ipcom_strcpy(iprohc.buf, "Done"); break; case ROHC_COMP_TRANS_PENDING: ipcom_strcpy(iprohc.buf, "Pending"); break; default: ipcom_strcpy(iprohc.buf, "Illegal"); break; } return iprohc.buf; } #ifndef IP_PORT_VXWORKS /* for Linux recursive semaphore */ /* *=========================================================================== * iprohc_comp_lck *=========================================================================== * Description: This function provides a recursive semaphore lock to an ROHC * compressor. * Parameters: * Returns: * */ IP_PUBLIC void iprohc_comp_lck(Iprohc_compressor *comp) { Ip_pid_t cpid = ipcom_getpid(); #ifdef ROHC_DEBUG ipcom_printf("Calling iprohc_comp_lck: pid %d, counter %d, cpid %d\n", comp->pid, comp->s_counter, cpid); #endif if (comp->pid == 0) { /* No one has semaphore, take it */ comp->pid = cpid; comp->s_counter = 1; ipcom_mutex_lock(comp->code_mutex); } else if (comp->pid != cpid) { /* block a different process/task */ ipcom_mutex_lock(comp->code_mutex); comp->pid = cpid; comp->s_counter++; } else /* the semaphore is taken by the same process, increase the counter */ comp->s_counter ++; #ifdef ROHC_DEBUG ipcom_printf("iprohc_comp_lck: pid %d, counter %d, cpid %d\n", comp->pid, comp->s_counter, cpid); #endif } /* *=========================================================================== * iprohc_comp_unlck *=========================================================================== * Description: This function provides a recursive semaphore unlock to an * ROHC compressor. * Parameters: * Returns: * */ IP_PUBLIC void iprohc_comp_unlck(Iprohc_compressor *comp) { Ip_pid_t cpid = ipcom_getpid(); #ifdef ROHC_DEBUG ipcom_printf("Calling iprohc_comp_unlck: pid %d, counter %d, cpid %d\n", comp->pid, comp->s_counter, cpid); #endif if (comp->pid != cpid) { IPCOM_LOG0(ERR, "iprohc_comp_unlck: released by a different process"); return; } /* decrease the counter */ comp->s_counter --; if (comp->s_counter == 0) { /* clear the semaphore PID */ comp->pid = 0; /* release the semaphore */ ipcom_mutex_unlock(comp->code_mutex); } #ifdef ROHC_DEBUG ipcom_printf("iprohc_comp_unlck: pid %d, counter %d, cpid %d\n", comp->pid, comp->s_counter, cpid); #endif } /* *=========================================================================== * iprohc_c_context_lck *=========================================================================== * Description: This function provides a recursive semaphore lock to an ROHC * compression context. * Parameters: * Returns: * */ IP_PUBLIC void iprohc_c_context_lck(Iprohc_c_context *context) { Ip_pid_t cpid = ipcom_getpid(); #ifdef ROHC_DEBUG ipcom_printf("Calling iprohc_c_context_lck: pid %d, counter %d, cpid %d\n", context->pid, context->s_counter, cpid); #endif if (context->pid == 0) { /* No one has semaphore, take it */ context->pid = cpid; context->s_counter = 1; ipcom_mutex_lock(context->code_mutex); } else if (context->pid != cpid) { /* block a different process/task */ ipcom_mutex_lock(context->code_mutex); context->pid = cpid; context->s_counter++; } else /* the semaphore is taken by the same process, increase the counter */ context->s_counter ++; #ifdef ROHC_DEBUG ipcom_printf("iprohc_c_context_lck: pid %d, counter %d, cpid %d\n", context->pid, context->s_counter, cpid); #endif } /* *=========================================================================== * iprohc_c_context_unlck *=========================================================================== * Description: This function provides a recursive semaphore unlock to an * ROHC compression context. * Parameters: * Returns: * */ IP_PUBLIC void iprohc_c_context_unlck(Iprohc_c_context *context) { Ip_pid_t cpid = ipcom_getpid(); #ifdef ROHC_DEBUG ipcom_printf("Enter iprohc_c_context_unlck: pid %d, counter %d, cpid %d\n", context->pid, context->s_counter, cpid); #endif if (context->pid != cpid) { IPCOM_LOG0(ERR,"iprohc_c_context_unlck: released by different process"); return; } /* decrease the counter */ context->s_counter --; if (context->s_counter == 0) { /* clear the semaphore PID */ context->pid = 0; /* release the semaphore */ ipcom_mutex_unlock(context->code_mutex); } #ifdef ROHC_DEBUG ipcom_printf("iprohc_c_context_unlck: pid %d, counter %d, cpid %d\n", context->pid, context->s_counter, cpid); #endif } #endif /* !IP_PORT_VXWORKS */ /* **************************************************************************** * END OF FILE **************************************************************************** */