/* *=========================================================================== * ipnet_sysctl_route_add_addr *=========================================================================== * Description: Adds an address in route table format. * Parameters: buf - the buffer to where the address should be written. * domain - the domain this address is part of. * rt_addr - a address or mask from the route table. * Returns: The address to where the next data should be written in * the buffer. * */ IP_STATIC void * ipnet_sysctl_route_add_addr(void *buf, int domain, void *rt_addr) { union Ip_sockaddr_union *addr; addr = (union Ip_sockaddr_union *) buf; #ifdef IPCOM_USE_INET if (domain == IP_AF_INET) { struct Ipnet_ipv4_key *key = (struct Ipnet_ipv4_key *) rt_addr; ipcom_memset(addr, 0, sizeof(struct Ip_sockaddr_in)); addr->sin.sin_family = IP_AF_INET; IPCOM_SA_LEN_SET(&addr->sin, sizeof(struct Ip_sockaddr_in)); ipcom_memcpy(&addr->sin.sin_addr, &key->addr, sizeof(addr->sin.sin_addr)); } #endif /* IPCOM_USE_INET */ #ifdef IPCOM_USE_INET6 if (domain == IP_AF_INET6) { struct Ipnet_ipv6_key *key = (struct Ipnet_ipv6_key *) rt_addr; ipcom_memset(addr, 0, sizeof(struct Ip_sockaddr_in6)); addr->sin6.sin6_family = IP_AF_INET6; IPCOM_SA_LEN_SET(&addr->sin6, sizeof(struct Ip_sockaddr_in6)); ipcom_memcpy(&addr->sin6.sin6_scope_id, &key->scope_id, sizeof(addr->sin6.sin6_scope_id)); ipcom_memcpy(&addr->sin6.sin6_addr, &key->addr, sizeof(addr->sin6.sin6_addr)); } #endif /* IPCOM_USE_INET6 */ return (Ip_u8 *) buf + IPCOM_SA_LEN_GET(&addr->sa); }
/* *=========================================================================== * ipcom_heap_sort_downheap *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC void ipcom_heap_sort_downheap(void *base, Ip_size_t elem_size, int root, int last, Ipcom_heap_sort_cmp_func cmp_func, void *tmp) { int new_r; int max_r = last >> 1; ipcom_memcpy(tmp, IPCOM_HEAP_SORT_GET_ELEM(base, root, elem_size), elem_size); while (root <= max_r) { new_r = root << 1; if (new_r < last && cmp_func(IPCOM_HEAP_SORT_GET_ELEM(base, new_r, elem_size), IPCOM_HEAP_SORT_GET_ELEM(base, new_r + 1, elem_size)) < 0) { new_r++; } if (cmp_func(tmp, IPCOM_HEAP_SORT_GET_ELEM(base, new_r, elem_size)) >= 0) goto done; ipcom_memcpy(IPCOM_HEAP_SORT_GET_ELEM(base, root, elem_size), IPCOM_HEAP_SORT_GET_ELEM(base, new_r, elem_size), elem_size); root = new_r; } done: ipcom_memcpy(IPCOM_HEAP_SORT_GET_ELEM(base, root, elem_size), tmp, elem_size); }
/* *=========================================================================== * ipdnsc_hostent_convert *=========================================================================== * Description: Converts a AF_INET hostent structure to a AF_INET6 hostent * structure. ipv4 addresses are converted to ipv4 mapped ipv6 * addresses * Parameters: he - pointer to the hostent structure to convert * Returns: pointer to the new hostent structure or NULL if failed */ IP_STATIC struct Ip_hostent * ipdnsc_hostent_convert(struct Ip_hostent *he) { struct Ip_hostent *he_new; Ip_s32 num_alias, num_addr, i; Ip_u8 buf[16]; Ip_u8 in6addr_mapped[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}; /* Verify the supplied host entry */ if (he->h_addrtype != IP_AF_INET || he->h_length != IPDNSC_INADDRSZ) return IP_NULL; /* Get the number of alias and address entries */ num_alias = ipdnsc_hostent_alias_count(he); num_addr = ipdnsc_hostent_addr_count(he); /* Create the new host entry structure */ he_new = ipdnsc_hostent_create(IP_AF_INET6); if (he_new == IP_NULL) return IP_NULL; /* Allocate memory for and copy the aliases */ for (i=0; i<(num_alias-1); i++) { if (ipdnsc_hostent_insert_alias(he_new, he->h_aliases[i])) { goto err_out; } } /* Allocate memory for and copy the addresses */ for (i=0; i<(num_addr-1); i++) { ipcom_memcpy(buf, in6addr_mapped, sizeof(in6addr_mapped)); ipcom_memcpy(buf+sizeof(in6addr_mapped), he->h_addr_list[i], he->h_length); if (ipdnsc_hostent_insert_addr(he_new, (char *)buf)) { goto err_out; } } /* Insert the hostname */ if (ipdnsc_hostent_insert_name(he_new, he->h_name)) { goto err_out; } return he_new; err_out: ipdnsc_hostent_free(he_new); return IP_NULL; }
IP_STATIC Ip_size_t ipcom_create_ifaddrs_inet6(Ip_fd fd, const char *ifname, Ip_u8 *ifa_first, Ip_size_t buf_len, struct Ipnet_if_msghdr *ifm, struct Ip_ifaddrs ***tail) { struct Ip_in6_aliasreq ifareq; struct Ipnet_ifa_msghdr *ifa; struct Ip_sockaddr_in6 *addrs[IPNET_RTAX_MAX]; Ip_size_t offset = 0; offset = 0; while (offset < buf_len) { struct Ip_ifaddrs *nifa; ifa = (struct Ipnet_ifa_msghdr *) &ifa_first[offset]; #if defined(IP_PORT_VXWORKS) && !defined(_WRS_KERNEL) ipnet_cmd_init_addrs_rtp(ifa + 1, ifa->ifam_addrs, (struct Ip_sockaddr **) addrs); #else ipnet_cmd_init_addrs(ifa + 1, ifa->ifam_addrs, (struct Ip_sockaddr **) addrs); #endif if (ifa->ifam_type != IPNET_RTM_NEWADDR || addrs[IPNET_RTAX_IFA]->sin6_family != IP_AF_INET6) break; offset += ifa->ifam_msglen; ipcom_memset(&ifareq, 0, sizeof(ifareq)); ipcom_memcpy(ifareq.ifra_name, ifname, IP_IFNAMSIZ); ipcom_memcpy(&ifareq.ifra_addr, addrs[IPNET_RTAX_IFA], sizeof(ifareq.ifra_addr)); (void)ipcom_socketioctl(fd, IP_SIOCXGIFADDR_IN6, &ifareq); if (IP_BIT_ISSET(ifareq.ifra_flags, IP_IN6_IFF_ANYCAST)) continue; if (IP_IN6_IS_ADDR_MULTICAST(&addrs[IPNET_RTAX_IFA]->sin6_addr)) continue; nifa = ipcom_create_ifaddrs_entry(ifname, ifm, ifa, (struct Ip_sockaddr **)addrs); if (nifa != IP_NULL) { **tail = nifa; *tail = &nifa->ifa_next; } } return offset; }
/* *=========================================================================== * ipcom_create_ifaddrs_entry *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC struct Ip_ifaddrs * ipcom_create_ifaddrs_entry(const char *ifname, struct Ipnet_if_msghdr *ifm, struct Ipnet_ifa_msghdr *ifa, struct Ip_sockaddr **addrs) { /**/ struct Ip_ifaddrs *nifa = ipcom_calloc(1, sizeof(*nifa)); if (nifa == IP_NULL) return IP_NULL; /* Interface name */ nifa->ifa_name = ipcom_strdup(ifname); if(nifa->ifa_name == IP_NULL) goto fail; /* Interface flags */ nifa->ifa_flags = ifm->ifm_flags; /* Interface address */ nifa->ifa_addr = ipcom_malloc(sizeof(union Ip_sockaddr_union)); if(nifa->ifa_addr == IP_NULL) goto fail; ipcom_memcpy(nifa->ifa_addr, addrs[IPNET_RTAX_IFA], IPCOM_SA_LEN_GET(addrs[IPNET_RTAX_IFA])); nifa->ifa_netmask = ipcom_malloc(sizeof(union Ip_sockaddr_union)); if(nifa->ifa_netmask == IP_NULL) goto fail; ipcom_memcpy(nifa->ifa_netmask, addrs[IPNET_RTAX_NETMASK], IPCOM_SA_LEN_GET(addrs[IPNET_RTAX_IFA])); if (IP_BIT_ISSET(ifa->ifam_addrs, IPNET_RTA_BRD)) { nifa->ifa_broadaddr = ipcom_malloc(sizeof(union Ip_sockaddr_union)); if(nifa->ifa_broadaddr == IP_NULL) goto fail; ipcom_memcpy(nifa->ifa_broadaddr, addrs[IPNET_RTAX_BRD], IPCOM_SA_LEN_GET(addrs[IPNET_RTAX_BRD])); } return nifa; fail: ipcom_ifaddrs_free(nifa); return IP_NULL; }
/* *=========================================================================== * ipnet_nat_proxy_sip_callidstr *=========================================================================== * Description: Extract the callid string * Parameters: pdata - pointer to message. * Returns: pointer to allocated buffer with callid string or * IP_NULL if wrong format or out of memory. */ IP_STATIC char * ipnet_nat_proxy_sip_callidstr(char *pmsg) { char *pstart; char *pcallid; int i; SIP_SKIP_SPACES(pmsg); pstart = pmsg; for (i = 0; i < 200; i++) { if (*pmsg != '\r') pmsg++; else break; } /* in case we have a wrong string format */ if (i >= 200) { IPCOM_LOG0(ERR, "ipnet_nat_proxy_sip_callidstr() :: ERROR, wrong string format"); return IP_NULL; } if ((pcallid = ipcom_malloc((pmsg - pstart) + 1)) == IP_NULL) return IP_NULL; ipcom_memcpy(pcallid, pstart, pmsg - pstart); *(pcallid + (pmsg - pstart)) = 0; IPCOM_LOG1(DEBUG, "ipnet_nat_proxy_sip_callidstr() :: callid=%s", pcallid); return pcallid; }
/* *=========================================================================== * ipcom_inet6_rth_reverse *=========================================================================== * Description: * Parameters: * Returns: * */ IP_PUBLIC int ipcom_inet6_rth_reverse(const void *in, void *out) { Ip_pkt_ip6_rthdr *rthdr = (Ip_pkt_ip6_rthdr *) in; struct Ip_in6_addr temp_addr; struct Ip_in6_addr *addr1; struct Ip_in6_addr *addr2; int i; int segments; segments = ipcom_inet6_rth_segments(in); if (segments < 0) return -1; if (in != out) { ipcom_memcpy(out, in, (rthdr->ip6r_len + 1) * 8); return ipcom_inet6_rth_reverse(out, out); } for (i = 0; i < segments / 2; i++) { addr1 = ipcom_inet6_rth_getaddr(out, i); addr2 = ipcom_inet6_rth_getaddr(out, segments - i - 1); IPCOM_INET6_SET_ADDR(&temp_addr, addr1); IPCOM_INET6_SET_ADDR(addr1, addr2); IPCOM_INET6_SET_ADDR(addr2, &temp_addr); } return 0; }
/* *=========================================================================== * ipcom_drv_eth_filter_add_mcast_addr *=========================================================================== * Description: Adds a multicast Ethernet address that should be passed * by the filter. * Parameters: filter - A filter to where the address should be added. * eth_mcast_addr - The address to add. * Returns: 0 = success, <0 = error code. * */ IP_PUBLIC int ipcom_drv_eth_filter_add_mcast_addr(Ipcom_drv_eth_filter *filter, Ip_u8 eth_mcast_addr[IPCOM_DRV_ETH_ADDR_SIZE]) { int i; int insert = -1; for (i = IPCOM_DRV_ETH_MAX_MULTIADDR - 1; i >= 0 ; i--) { if (filter->ref[i] == 0) insert = i; else { if (ipcom_memcmp(eth_mcast_addr, filter->mcast_addr[i], IPCOM_DRV_ETH_ADDR_SIZE) == 0) { filter->ref[i]++; return 0; } } } if (insert < 0) /* Cannot join any more Ethernet multicast addresses */ return -IP_ERRNO_ENOSPC; /* Add this multicast address */ filter->ref[insert] = 1; ipcom_memcpy(filter->mcast_addr[insert], eth_mcast_addr, IPCOM_DRV_ETH_ADDR_SIZE); return 0; }
/* *=========================================================================== * ipnet_nat_proxy_sip_modmsg *=========================================================================== * Description: Modify message and adjust length * Parameters: newdata - pointer to new data * newlen - length of new data * olddata - pointer to old data * oldlen - length of old data * ppend - pointer to pointer to last byte of message * Returns: 0 = ok * -1 = message too long */ IP_STATIC int ipnet_nat_proxy_sip_modmsg(char *newdata, int newlen, char *olddata, int oldlen, char **ppend) { char *pmax = (char *)sipbuf + sizeof(sipbuf) - 1; int diff = newlen - oldlen; int movelen = (*ppend + 1) - (olddata + oldlen); ip_assert(movelen >= 0); if (pmax - *ppend < diff) { IPCOM_LOG0(ERR, "ipnet_nat_proxy_sip_modmsg() :: message to long"); return -1; } /* Make space for new data */ ipcom_memmove(olddata + newlen, olddata + oldlen, movelen); *ppend += diff; /* Copy in new data */ ipcom_memcpy(olddata, newdata, newlen); return 0; }
/* *=========================================================================== * ipcom_drv_eth_filter_set_unicast_addr *=========================================================================== * Description: Sets the unicast address of the local interface. * Parameters: filter - The current filter for this interface. * eth_unicast_addr - The unicast address for this node. * Returns: * */ IP_PUBLIC void ipcom_drv_eth_filter_set_unicast_addr(Ipcom_drv_eth_filter *filter, Ip_u8 eth_unicast_addr[IPCOM_DRV_ETH_ADDR_SIZE]) { ipcom_memcpy(filter->unicast_addr, eth_unicast_addr, IPCOM_DRV_ETH_ADDR_SIZE); }
/* *=========================================================================== * ipcom_buffer_put *=========================================================================== * Description: Appends data to the buffer, expanding it if necessary. * Parameters: * Returns: * */ IP_PUBLIC Ip_err ipcom_buffer_put(Ipcom_buffer *buffer, const Ip_u8 *data, Ip_u32 len) { Ip_u8 *cp; if(ipcom_buffer_append_space(buffer, &cp, len)) return IPCOM_ERR_FAILED; ipcom_memcpy(cp, data, len); return IPCOM_SUCCESS; }
/* *=========================================================================== * ipcom_buffer_get *=========================================================================== * Description: Gets data from the beginning of the buffer. * Parameters: * Returns: * */ IP_PUBLIC Ip_err ipcom_buffer_get(Ipcom_buffer *buffer, Ip_u8 *buf, Ip_u32 len) { ip_assert(len <= (buffer->end - buffer->offset)); if(len > (buffer->end - buffer->offset)) return IPCOM_ERR_FAILED; ipcom_memcpy(buf, buffer->buf + buffer->offset, len); buffer->offset += len; return IPCOM_SUCCESS; }
IP_STATIC void * ipnet_sysctl_if_add_ip4_addr(void *buf, Ip_u32 addr_n) { struct Ip_sockaddr_in *in = (struct Ip_sockaddr_in *) buf; ipcom_memset(in, 0, sizeof(struct Ip_sockaddr_in)); in->sin_family = IP_AF_INET; IPCOM_SA_LEN_SET(in, sizeof(struct Ip_sockaddr_in)); ipcom_memcpy(&in->sin_addr, &addr_n, sizeof(in->sin_addr)); return in + 1; }
/* *=========================================================================== * ipcom_egd *=========================================================================== * Description: This process gathers random data by calling ipcom_random_bingo_lotto() * * Applications can access the random data before the full entropy * has been gathered. This will of course mean that the quality of * the random data will not be as good, but in some situations that * may be a better trade-off than no random data at all. * Parameters: * Returns: * */ IP_STATIC IPCOM_PROCESS(ipcom_egd) { Ipcom_egd_hash_ctx md5_ctx; Ipcom_egd_hash_ctx tmp_md5_ctx; Ip_s32 rnd; Ipcom_tmo tmo; #ifdef IPCOM_EGD_DEBUG int i; #endif ipcom_proc_init(); IPCOM_LOG0(DEBUG, "ipcom_egd :: starting"); ipcom_egd_hash_init(&md5_ctx); ipcom_egd_laps = 0; #ifdef IPCOM_EGD_DEBUG ipcom_memset(ipcom_egd_raw_data, 0, sizeof(ipcom_egd_raw_data)); #endif while(ipcom_egd_laps < IPCOM_RANDOM_LAPS) { ipcom_egd_tmo_flag = 0; if(ipcom_tmo_request(&tmo, ipcom_random_tmo_handler, (int*)&ipcom_egd_tmo_flag, 50) != IPCOM_SUCCESS) { IPCOM_LOG0(ERR, "ipcom_egd :: timeout request failed, seed aborted"); goto exit; } rnd = ipcom_random_bingo_lotto(); #ifdef IPCOM_EGD_DEBUG ipcom_egd_raw_data[ipcom_egd_laps] = rnd; #endif ipcom_egd_hash_update(&md5_ctx, (void*) &rnd, sizeof(Ip_u32)); ipcom_memcpy(&tmp_md5_ctx, &md5_ctx, sizeof(Ipcom_egd_hash_ctx)); ipcom_egd_hash_final(ipcom_random_state, &tmp_md5_ctx); ipcom_egd_laps++; ipcom_millisleep(IPCOM_EGD_SLEEP_TIME); } exit: #ifdef IPCOM_EGD_DEBUG for (i=0; i < ipcom_egd_laps; i++) { IPCOM_LOG2(INFO, "ipcom_egd_raw_data[%d] = %d", i, ipcom_egd_raw_data[i]); ipcom_millisleep(100); } #endif IPCOM_LOG0(DEBUG, "ipcom_egd :: terminating"); ipcom_proc_exit(); }
/* *=========================================================================== * ipcom_env_create *=========================================================================== * Description: * Parameters: * Returns: */ IP_STATIC Ipcom_env_entry * ipcom_env_create(const char *name, const char *value) { Ip_size_t name_length; Ip_size_t value_length; Ipcom_env_entry *env; /* Create environment variable */ name_length = ipcom_strlen(name) + 1; value_length = ipcom_strlen(value) + 1; env = ipcom_malloc(sizeof(Ipcom_env_entry) + name_length + value_length); if(env == IP_NULL) return IP_NULL; /* Init environment variable */ env->name = (const char *)env + sizeof(Ipcom_env_entry); ipcom_memcpy((void *)env->name, name, name_length); env->value = env->name + name_length; ipcom_memcpy((void *)env->value, value, value_length); return env; }
/* *=========================================================================== * ipcom_random_get *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC void ipcom_random_get(Ip_u8 *buf) { Ipcom_egd_hash_ctx ctx; static Ip_u32 counter = 0; counter++; ipcom_egd_hash_init(&ctx); ipcom_egd_hash_update(&ctx, ipcom_random_state, sizeof(ipcom_random_state)); ipcom_egd_hash_update(&ctx, (void*) &counter, sizeof(counter)); ipcom_egd_hash_final(ipcom_random_state, &ctx); ipcom_memcpy(buf, ipcom_random_state, sizeof(ipcom_random_state)); }
IP_PUBLIC void ipcom_heap_sort(void *base, Ip_size_t num_members, Ip_size_t elem_size, Ipcom_heap_sort_cmp_func cmp_func, void *tmp) { int i; for (i = num_members >> 1; i >= 1; i--) ipcom_heap_sort_downheap(base, elem_size, i, num_members, cmp_func, tmp); for (i = num_members; i > 1; i--) { ipcom_memcpy(tmp, IPCOM_HEAP_SORT_GET_ELEM(base, i, elem_size), elem_size); ipcom_memcpy(IPCOM_HEAP_SORT_GET_ELEM(base, i, elem_size), IPCOM_HEAP_SORT_GET_ELEM(base, 1, elem_size), elem_size); ipcom_memcpy(IPCOM_HEAP_SORT_GET_ELEM(base, 1, elem_size), tmp, elem_size); ipcom_heap_sort_downheap(base, elem_size, 1, i - 1, cmp_func, tmp); } }
/* *=========================================================================== * ipcom_inet6_rth_add *=========================================================================== * Description: * Parameters: * Returns: * */ IP_PUBLIC int ipcom_inet6_rth_add(void *bp, const struct Ip_in6_addr *addr) { Ip_pkt_ip6_rthdr0 *rthdr = (Ip_pkt_ip6_rthdr0 *) bp; struct Ip_in6_addr *rtaddr; if (rthdr->ip6r0_type != IP_IPV6_RTHDR_TYPE_0) return -1; rtaddr = (struct Ip_in6_addr *) (rthdr + 1); ipcom_memcpy(&rtaddr[rthdr->ip6r0_segleft], addr, sizeof(struct Ip_in6_addr)); ++rthdr->ip6r0_segleft; rthdr->ip6r0_len += sizeof(struct Ip_in6_addr) / 8; return 0; }
/* *=========================================================================== * ipnet_rtnetlink_rta_sz_put *=========================================================================== * Description: Add a NETLINK route attribute to a NETLINK message. * Parameters: nlh - Current NLMSG * sz - Total size * attrtype - Attribute type * attrlen - Lenght of attribute * data - Attribute data * * Returns: * */ IP_GLOBAL void * ipnet_rtnetlink_rta_sz_put(Ipnet_netlink_mem_t *mem, int attrtype, int attrlen, IP_CONST void *data) { struct Ip_rtattr *rta = ipnet_netlink_sz_put(mem, IP_NULL, IP_RTA_LENGTH(attrlen)); if (!rta) return IP_NULL; rta->rta_type = (Ip_u16) attrtype; rta->rta_len = (Ip_u16) IP_RTA_LENGTH (attrlen); if (data) ipcom_memcpy(IP_RTA_DATA(rta), data, attrlen); return rta; }
/* *=========================================================================== * ipcom_egd_random *=========================================================================== * Description: This function will return the required number of random data, * regardless of the seed state. A caller that requires high quality * random data should check the random seed state first by calling * ipcom_egd_random_seed_state(). * Parameters: rand_size: * the number of random bytes requested. * buf: * the buffer to store the random data in. * Returns: */ IP_STATIC void ipcom_egd_random(Ip_u8 *buf, Ip_s32 rand_size) { Ip_u8 tmp_buf[sizeof(ipcom_random_state)]; while(rand_size >= (Ip_s32) sizeof(ipcom_random_state)) { ipcom_random_get(buf); buf += sizeof(ipcom_random_state); rand_size -= sizeof(ipcom_random_state); } if(rand_size > 0) { ipcom_random_get(tmp_buf); ipcom_memcpy(buf, tmp_buf, rand_size); } }
IP_STATIC int ipnet_cmd_qc_show_children(Ipnet_cmd_qc *p, struct Ipnet_ifqueue_container *container) { int i; int ret = 0; struct Ipnet_ifqueue_container c; ipcom_memcpy(&c, container, sizeof(c)); p->recurse_level++; p->p.ifq.ifq_parent_id = p->p.ifq.ifq_id; for (i = 0; ret == 0 && i < c.child_count; i++) { p->p.ifq.ifq_id = c.child_ids[i]; ret = ipnet_cmd_qc_show_queue(p); } p->recurse_level--; return ret; }
/* *=========================================================================== * ipdnsc_hostent_insert_addr *=========================================================================== * Description: Inserts an address in a hostent structure * Parameters: he - pointer to the hostent structure * addr - the addr to insert * Returns: 0 for OK, -1 for fail. */ IP_GLOBAL Ip_s32 ipdnsc_hostent_insert_addr(struct Ip_hostent *he, char *addr) { Ip_s32 num_addr, i=0; char **tmp; /* Find out the current number of addresses */ num_addr = ipdnsc_hostent_addr_count(he); /* Allocate memory for the another address list entry */ tmp = ipcom_realloc(he->h_addr_list, (num_addr+1) * sizeof(char *)); if(tmp == IP_NULL) return -1; he->h_addr_list = tmp; /* Allocate memory for the address */ he->h_addr_list[num_addr-1] = ipcom_malloc(he->h_length); if (he->h_addr_list[num_addr-1] == IP_NULL) { /* We have to free to whole list here */ while (he->h_addr_list[i] != IP_NULL) { ipcom_free(he->h_addr_list[i]); i++; } /* Free the address list */ ipcom_free(he->h_addr_list); he->h_addr_list = IP_NULL; return -1; } /* Set the address */ ipcom_memcpy(he->h_addr_list[num_addr-1], addr, he->h_length); /* Null terminate the list */ he->h_addr_list[num_addr] = IP_NULL; return 0; }
/* *=========================================================================== * ipcom_cmd_sockperf_echo_buf *=========================================================================== * Description: Prints the contents of the buffer. * Parameters: buf - The buffer to print. * size - The size of 'buf' * pattern_id - The pattern number the buffer should start at. * Returns: */ IP_STATIC void ipcom_cmd_sockperf_echo_buf(char *buf, int size, int pattern_id) { char pbuf[9]; int i; if (size == 0) { ipcom_printf(IP_LF); return; } pbuf[8] = '\0'; for (i = 0; i < size; i += 8) { ipcom_memcpy(pbuf, buf + i, 8); if ((pattern_id % 16) == 0) ipcom_printf("%04d ", i); if ((++pattern_id % 16) == 0) pbuf[7] = '\n'; ipcom_printf(pbuf); } }
/* *=========================================================================== * ipcom_cmd_ipd *=========================================================================== * Description: * Parameters: * Returns: */ IP_PUBLIC int ipcom_cmd_ipd(int argc, char **argv) { Ipcom_getopt opt; int i, c, msgtype; Ip_err err = IPCOM_SUCCESS; #if IPCOM_VR_MAX > 1 int vr = ipcom_proc_vr_get(); int vr_new = vr; #endif if (argc < 2) { usage: ipcom_fprintf(ip_stderr, "Interpeak daemon (IPD) command, version 1.2"IP_LF "usage: "IP_LF " ipd [-V <vr>] list"IP_LF " ipd [-V <vr>] start <service>"IP_LF " ipd [-V <vr>] kill <service>"IP_LF " ipd [-V <vr>] reconfigure <service>"IP_LF " ipd [-V <vr>] <#> <service>"IP_LF IP_LF); return 0; } ipcom_getopt_clear_r(&opt); while ((c = ipcom_getopt_r(argc, argv, "V:", &opt)) != -1) { switch(c) { case 'V': #if IPCOM_VR_MAX > 1 vr_new = ipcom_atoi(opt.optarg); #endif break; default: ipcom_printf("ipd: unknown option %c"IP_LF, (char)c); return -1; } } if (opt.optind >= argc) { ipcom_printf("ipd: missing <command> argument"IP_LF); goto usage; } if(ipcom_strcmp(argv[opt.optind], "list") == 0) { #if IPCOM_VR_MAX > 1 if (vr != vr_new) ipcom_proc_vr_set(vr_new); #endif ipcom_printf("Services:"IP_LF); for (i = 0; ipcom_ipd_products[i].name != IP_NULL; i++) { if ((argc - (opt.optind + 1)) > 0) { int p; for (p = opt.optind + 1; p < argc; p++) { if (ipcom_strcasecmp(ipcom_ipd_products[i].name, argv[p]) == 0) goto print_service; } continue; } print_service: if (IP_BIT_ISSET(ipcom_ipd_products[i].flags, IPCOM_IPD_FLAG_IPD_START)) { #ifdef IP_PORT_OSE5 if (ipcom_ipd_products[i].start == IP_NULL && ipcom_ipd_isinstalled_ose5(ipcom_ipd_products[i].name) != IPCOM_SUCCESS) continue; #endif err = ipcom_ipd_send(ipcom_ipd_products[i].name, IPCOM_IPD_MSGTYPE_PING); ipcom_printf("%-20s %-s"IP_LF, ipcom_ipd_products[i].name, err == IPCOM_SUCCESS ? "started" : "killed"); } else if (ipcom_ipd_products[i].start) ipcom_printf("%-20s %-s"IP_LF, ipcom_ipd_products[i].name, "started"); } ipcom_printf(IP_LF); #if IPCOM_VR_MAX > 1 if (vr != vr_new) ipcom_proc_vr_set(vr); #endif return 0; } if ((argc - opt.optind) < 2) { ipcom_printf("ipd: missing <service> argument"IP_LF); return -1; } for (i = 0; ipcom_cmd_ipd_messages[i].name; i++) if (ipcom_strcmp(argv[opt.optind], ipcom_cmd_ipd_messages[i].name) == 0) { msgtype = ipcom_cmd_ipd_messages[i].msgtype; goto sendmsg; } if (*argv[opt.optind] == '-' && ipcom_isdigit(argv[opt.optind][1])) { /* "UNIX" signal support (using negative numbers) */ msgtype = -ipcom_atoi(argv[opt.optind] + 1); goto sendmsg; } if (ipcom_isdigit(argv[opt.optind][0])) { /* positive numbers */ msgtype = ipcom_atoi(argv[1]); goto sendmsg; } /* unknown command. */ ipcom_printf ("ipd: unknown command '%s'"IP_LF, argv[opt.optind]); return -1; /* send msg */ sendmsg: #if IPCOM_VR_MAX > 1 if (vr != vr_new) ipcom_proc_vr_set(vr_new); #endif if ((argc - opt.optind) < 3) err = ipcom_ipd_send(argv[opt.optind+1], msgtype); else { Ipcom_ipd_msg *msg; int sz = ipcom_strlen(argv[opt.optind + 2]) + 1; msg = ipcom_calloc(1, sz + sizeof(*msg)); if (msg != IP_NULL) { msg->msgtype = msgtype; ipcom_memcpy(msg + 1, argv[opt.optind + 2], sz); err = ipcom_ipd_sendmsg(argv[opt.optind+1], msg, sz + sizeof(*msg)); ipcom_free(msg); } } if(err == IPCOM_SUCCESS) ipcom_printf("ipd: %s %s ok"IP_LF, argv[opt.optind], argv[opt.optind+1]); else ipcom_printf("ipd: %s %s failed: %s"IP_LF, argv[opt.optind], argv[opt.optind+1], ipcom_err_string(err)); #if IPCOM_VR_MAX > 1 if (vr != vr_new) ipcom_proc_vr_set(vr); #endif return 0; }
IP_STATIC IPCOM_PROCESS( ipcom_cmd_smptest_client_spawn ) { union { struct Ip_sockaddr sa; #ifdef IPCOM_USE_INET6 struct Ip_sockaddr_in6 sin6; #endif struct Ip_sockaddr_storage ss; struct Ip_sockaddr_in sin; } addr; Ip_fd socket; unsigned char *buf = 0; int portadd = spawn_number_client++; int opt_val = 1; int sec = SECONDS_CLIENT; int send = 0; int num_sends = 0; unsigned long num_bytes = 0; ipcom_proc_init(); ipcom_memset( &addr.ss, 0, sizeof( addr.ss ) ); ipcom_memcpy( &addr.sa, smp_opt_client.res->ai_addr, smp_opt_client.res->ai_addrlen ); socket = ipcom_socket( smp_opt_client.res->ai_family, smp_opt_client.res->ai_socktype, smp_opt_client.res->ai_protocol ); if (socket == IP_SOCKERR) { ipcom_printf("Failed to create socket for thread %d: %s"IP_LF, portadd, ipcom_strerror(ipcom_errno)); return_client = 1; ipcom_sem_post( sem_wait_client ); return; } if ( 0 != ipcom_setsockopt(socket, IP_SOL_SOCKET, IP_SO_REUSEPORT, &opt_val, sizeof (opt_val)) ) { ipcom_printf("ipcom_setsockopt failed: %s"IP_LF, ipcom_strerror(ipcom_errno)); return_client = 1; ipcom_sem_post( sem_wait_client ); return; } if ( 0 != ipcom_socketioctl( socket, IP_X_SIOCSINTR, &sec ) ) { ipcom_printf("ipcom_socketioctl failed: %s"IP_LF, ipcom_strerror(ipcom_errno)); return_client = 1; ipcom_sem_post( sem_wait_client ); return; } addr.sin.sin_port = ip_htons( smp_opt_client.port + portadd ); /* port is in the same place for IPv4 and IPv6 */ if ( smp_opt_client.tcp ) { if ( 0 != ipcom_connect( socket, &addr.sa, smp_opt_client.res->ai_addrlen ) ) { ipcom_printf("Thread %d failed to connect: %s"IP_LF, portadd, ipcom_strerror(ipcom_errno)); return_client = 1; ipcom_sem_post( sem_wait_client ); return; } if ( verbose ) ipcom_printf("Thread %d connected to port %d"IP_LF, portadd, smp_opt_client.port + portadd ); } buf = ipcom_malloc( smp_opt_client.num_bytes ); while ( 1 ) { if ( smp_opt_client.tcp ) send = ipcom_send( socket, buf, smp_opt_client.num_bytes, 0); else send = ipcom_sendto( socket, buf, smp_opt_client.num_bytes, 0, &addr.sa, smp_opt_client.res->ai_addrlen ); if ( send > 0 ) num_bytes += send; num_sends++; if ( send == 0 ) { ipcom_printf( "Error: Disconnected"IP_LF ); return_client = 1; break; } else if ( send < 0 ) { if ( ipcom_errno == IP_ERRNO_EINTR ) { if ( verbose ) { ipcom_printf("Thread %d done."IP_LF, portadd ); ipcom_printf(" Sends: %d"IP_LF, num_sends ); ipcom_printf(" MB/s: %f"IP_LF, ((float)(num_bytes)/(1024.0f*1024.0f) )/5.0f ); } break; } return_client = 1; ipcom_printf("Error on thread %d: %s"IP_LF, portadd, ipcom_strerror(ipcom_errno)); break; } } if ( verbose ) { if ( spawn_number_client != smp_opt_client.num_sock ) { ipcom_printf("Error. Only %d client-sockets seemed to work."IP_LF, spawn_number_client ); } } ipcom_socketclose( socket ); ipcom_free( buf ); if ( 0 == ipcom_atomic_sub_and_return( &num_wait_client, 1 ) ) ipcom_sem_post( sem_wait_client ); ipcom_proc_exit(); }
IP_STATIC IPCOM_PROCESS( ipcom_cmd_smptest_server_spawn ) { union { struct Ip_sockaddr sa; #ifdef IPCOM_USE_INET6 struct Ip_sockaddr_in6 sin6; #endif struct Ip_sockaddr_storage ss; struct Ip_sockaddr_in sin; } addr; Ip_fd listen_socket; Ip_fd connect_sock = 0; int opt_val = 1; int portadd = spawn_number_server++; int bytes = 0; int sec = SECONDS_CLIENT + SECONDS_SERVER; unsigned char *buf = 0; int num_recives = 0; unsigned long num_bytes = 0; struct Ip_sockaddr from; struct Ip_linger linger; Ip_socklen_t from_length = 0; int retry_count = 0; ipcom_proc_init(); ipcom_memset( &addr.ss, 0, sizeof( addr.ss ) ); ipcom_memcpy( &addr.sa, smp_opt_server.res->ai_addr, smp_opt_server.res->ai_addrlen ); linger.l_onoff = 1; linger.l_linger = 2; listen_socket = ipcom_socket( smp_opt_server.res->ai_family, smp_opt_server.res->ai_socktype, smp_opt_server.res->ai_protocol ); if (listen_socket == IP_SOCKERR) { ipcom_printf("Failed to create socket: %s"IP_LF, ipcom_strerror(ipcom_errno)); return_server = 1; ipcom_sem_post( sem_wait_server ); return; } if ( 0 != ipcom_setsockopt(listen_socket, IP_SOL_SOCKET, IP_SO_REUSEPORT, &opt_val, sizeof (opt_val)) ) { ipcom_printf("ipcom_setsockopt failed: %s"IP_LF, ipcom_strerror(ipcom_errno)); return_server = 1; ipcom_sem_post( sem_wait_server ); return; } addr.sin.sin_port = ip_htons( smp_opt_server.port + portadd ); /* port is in the same place for IPv4 and IPv6 */ if ( 0 != ipcom_bind( listen_socket, &addr.sa, sizeof( addr.ss ) ) ) { ipcom_printf("Failed to bind: %s"IP_LF, ipcom_strerror(ipcom_errno)); return_server = 1; ipcom_sem_post( sem_wait_server ); return; } buf = ipcom_malloc( smp_opt_server.num_bytes ); if ( smp_opt_server.tcp ) { if ( -1 == ipcom_listen( listen_socket, 0 ) ) { ipcom_printf("Listen failed: %s"IP_LF, ipcom_strerror(ipcom_errno)); return_server = 1; ipcom_sem_post( sem_wait_server ); return; } if ( verbose ) ipcom_printf("Thread %d listens to %s:%d"IP_LF, portadd, smp_opt_server.res->ai_canonname, ip_ntohs( addr.sin.sin_port ) ); } if ( 0 == ipcom_atomic_sub_and_return( &listen_wait, 1 ) ) { /* Send to the test-server or write to stdout? */ if ( server_out >= 0 ) { char ready[] = "Ready."; ipcom_socketwrite(server_out, ready, 8 ); } else ipcom_printf("Ready."IP_LF ); } if ( 0 != ipcom_socketioctl( listen_socket, IP_X_SIOCSINTR, &sec ) ) { ipcom_printf("ipcom_socketioctl failed: %s"IP_LF, ipcom_strerror(ipcom_errno)); return_server = 1; ipcom_sem_post( sem_wait_server ); return; } if ( smp_opt_server.tcp ) { retry: connect_sock = ipcom_accept( listen_socket, IP_NULL, 0 ); if ( -1 == connect_sock ) { if ( ipcom_errno == IP_ERRNO_EINTR ) { if ( verbose ) { if ( ++retry_count < 5 ) { ipcom_printf("Accept failed for thread %d: %s.. Retrying."IP_LF, portadd, ipcom_strerror(ipcom_errno)); goto retry; } } } ipcom_printf("Accept failed for thread %d: %s"IP_LF, portadd, ipcom_strerror(ipcom_errno)); return_server = 1; ipcom_socketclose( listen_socket ); ipcom_sem_post( sem_wait_server ); return; } if ( 0 != ipcom_socketioctl( connect_sock, IP_X_SIOCSINTR, &sec ) ) { ipcom_printf("ipcom_socketioctl failed: %s"IP_LF, ipcom_strerror(ipcom_errno)); return_server = 1; ipcom_sem_post( sem_wait_server ); return; } if ( 0 != ipcom_setsockopt( connect_sock, IP_SOL_SOCKET, IP_SO_LINGER, &linger, sizeof (linger)) ) { ipcom_printf("ipcom_setsockopt failed: %s"IP_LF, ipcom_strerror(ipcom_errno)); return_server = 1; ipcom_sem_post( sem_wait_server ); return; } } while ( 1 ) { num_recives++; if ( smp_opt_server.tcp ) bytes = ipcom_recv( connect_sock, buf, smp_opt_server.num_bytes, 0); else { bytes = ipcom_recvfrom( listen_socket, buf, smp_opt_server.num_bytes, 0, &from, &from_length ); if ( num_recives == 1 && 0 == smp_opt_server.tcp ) { sec = SECONDS_CLIENT+2+portadd; if ( 0 != ipcom_socketioctl( listen_socket, IP_X_SIOCSINTR, &sec ) ) { ipcom_printf("ipcom_socketioctl failed: %s"IP_LF, ipcom_strerror(ipcom_errno)); return_server = 1; ipcom_sem_post( sem_wait_server ); return; } } } if ( bytes > 0 ) num_bytes += bytes; if (bytes == 0) { if ( verbose ) { ipcom_printf("Thread %d done."IP_LF, portadd ); ipcom_printf(" Recives: %d"IP_LF, num_recives ); ipcom_printf(" MB/s: %f"IP_LF, ((float)(num_bytes)/(1024.0f*1024.0f) )/5.0f ); } break; } else if (bytes < 0) { if ( ipcom_errno == IP_ERRNO_EINTR ) { if ( smp_opt_server.tcp ) { return_server = 1; ipcom_printf("Error! Out of time!"IP_LF ); break; } else { if ( verbose ) { ipcom_printf("Thread %d done."IP_LF, portadd ); ipcom_printf(" Recives: %d"IP_LF, num_recives ); ipcom_printf(" MB/s: %f"IP_LF, ((float)(num_bytes)/(1024.0f*1024.0f) )/5.0f ); } break; } } else if ( bytes == IP_SOCKERR ) /* Connection reset by peer */ { } return_server = 1; ipcom_printf("recv failed: %s"IP_LF, ipcom_strerror(ipcom_errno)); return; } } if ( verbose ) { if ( spawn_number_server != smp_opt_server.num_sock ) { ipcom_printf("Error. Only %d server-sockets seemed to work."IP_LF, spawn_number_server ); } } if ( smp_opt_server.tcp ) ipcom_shutdown( connect_sock, IP_SHUT_RDWR ); ipcom_free( buf ); ipcom_socketclose( listen_socket ); if ( 0 == ipcom_atomic_sub_and_return( &num_wait_server, 1 ) ) ipcom_sem_post( sem_wait_server ); if ( smp_opt_server.tcp ) ipcom_socketclose( connect_sock ); ipcom_proc_exit(); }
/* *=========================================================================== * ipnet_sysctl_route_dump_cb *=========================================================================== * Description: Checks if this entry should be added and adds it if it should. * Parameters: rt - the route entry to add * data - callback data. * Returns: IP_FALSE (the entry should never be deleted). * */ IP_STATIC Ip_bool ipnet_sysctl_route_dump_cb(Ipnet_route_entry *rt, Ipnet_sysctl_route_data *data) { struct Ipnet_rt_msghdr *rt_msg; Ip_u16 len; if (rt->next) (void)ipnet_sysctl_route_dump_cb(rt->next, data); if (rt->narrow) (void) ipnet_sysctl_route_dump_cb(rt->narrow, data); if ((rt->hdr.flags & data->flags) != data->flags) return IP_FALSE; /* Do not list the 255.255.255.255, 224.0.0.0/4 or IPv6 multicast routes. */ if (IP_BIT_ISSET(rt->hdr.flags, IPNET_RTF_X_MCAST_RO | IPNET_RTF_X_BCAST_RO | IPNET_RTF_X_HIDDEN)) return IP_FALSE; len = ipnet_sysctl_route_dump_elem_len(rt); data->bytes_written += len; if (data->bytes_written > data->buf_len) { /* Buffer to small */ if (data->buf != IP_NULL) data->soerrno = -IP_ERRNO_ENOMEM; return IP_FALSE; } rt_msg = (struct Ipnet_rt_msghdr *) data->buf; data->buf = (Ip_u8 *) data->buf + sizeof(struct Ipnet_rt_msghdr); ipcom_memset(rt_msg, 0, sizeof(struct Ipnet_rt_msghdr)); rt_msg->rtm_msglen = len; rt_msg->rtm_version = IPNET_RTM_VERSION; rt_msg->rtm_type = IPNET_RTM_GET; rt_msg->rtm_index = rt->netif ? rt->netif->ipcom.ifindex : 0; rt_msg->rtm_table = data->table; rt_msg->rtm_flags = rt->hdr.flags; rt_msg->rtm_use = rt->use; rt_msg->rtm_rmx = rt->metrics; /* add destination address */ IP_BIT_SET(rt_msg->rtm_addrs, IPNET_RTA_DST); data->buf = ipnet_sysctl_route_add_addr(data->buf, IPNET_ROUTE_GET_FAMILY(rt->head), rt->hdr.key); if (rt->gateway) { IP_BIT_SET(rt_msg->rtm_addrs, IPNET_RTA_GATEWAY); ipcom_memcpy(data->buf, rt->gateway, IPCOM_SA_LEN_GET(rt->gateway)); data->buf = (Ip_u8 *) data->buf + IPCOM_SA_LEN_GET(rt->gateway); } else if (IP_BIT_ISSET(rt->hdr.flags, IPNET_RTF_CLONING)) { struct Ip_sockaddr_dl *dl = data->buf; IP_BIT_SET(rt_msg->rtm_addrs, IPNET_RTA_GATEWAY); ipcom_memset(data->buf, 0, sizeof(struct Ip_sockaddr_dl)); IPCOM_SA_LEN_SET(dl, sizeof(struct Ip_sockaddr_dl)); dl->sdl_family = IP_AF_LINK; ip_assert(rt->netif != IP_NULL); if (rt->netif != IP_NULL) { dl->sdl_index = (Ip_u16)rt->netif->ipcom.ifindex; dl->sdl_type = (Ip_u8)rt->netif->ipcom.type; } data->buf = (Ip_u8 *) data->buf + sizeof(struct Ip_sockaddr_dl); } if (rt->hdr.mask) { /* add destination mask */ IP_BIT_SET(rt_msg->rtm_addrs, IPNET_RTA_NETMASK); data->buf = ipnet_sysctl_route_add_addr(data->buf, IPNET_ROUTE_GET_FAMILY(rt->head), rt->hdr.mask); } ip_assert((Ip_u16)((Ip_ptrdiff_t) data->buf - (Ip_ptrdiff_t) rt_msg) == len); return IP_FALSE; }
/* *=========================================================================== * ipcom_sysvar_set_internal *=========================================================================== * Description: * Parameters: * Returns: */ IP_GLOBAL Ip_err ipcom_sysvar_set_tree(const char *name, const char *value, int flags, Ipcom_sysvar_tree *tree) { Ip_size_t name_length; Ip_size_t value_length; Ipcom_sysvar_entry *sysvar; Ip_err retval = IPCOM_SUCCESS; /* Check for duplicate. */ sysvar = ipcom_hash_get(tree->sysvars, name); if (sysvar) { if (IP_BIT_ISSET(sysvar->flags, IPCOM_SYSVAR_FLAG_READONLY)) { retval = IPCOM_ERR_READONLY; goto leave; } else if (IP_BIT_ISFALSE(flags, IPCOM_SYSVAR_FLAG_OVERWRITE)) { retval = IPCOM_ERR_DUPLICATE; goto leave; } else { flags |= sysvar->flags & IPCOM_SYSVAR_FLAG_KERNEL; ipcom_hash_remove(tree->sysvars, sysvar); ipcom_free(sysvar); goto set; } } /* No current entry found and not allowed to create a new entry. */ if(IP_BIT_ISSET(flags, IPCOM_SYSVAR_FLAG_NOCREATE)) { retval = IPCOM_ERR_FAILED; goto leave; } /* Add the new sysvar. */ set: name_length = ipcom_strlen(name) + 1; value_length = ipcom_strlen(value) + 1; sysvar = ipcom_malloc(sizeof(Ipcom_sysvar_entry) + name_length + value_length); if(sysvar == IP_NULL) { retval = IPCOM_ERR_NO_MEMORY; goto leave; } sysvar->refcount = 1; sysvar->flags = flags; if (IP_BIT_ISFALSE(flags, IPCOM_SYSVAR_FLAG_INIT)) { tree->modified = IP_TRUE; sysvar->flags |= IPCOM_SYSVAR_FLAG_MODIFIED; } sysvar->name = (const char *)sysvar + sizeof(Ipcom_sysvar_entry); ipcom_memcpy((void *)sysvar->name, name, name_length); sysvar->value = sysvar->name + name_length; ipcom_memcpy((void *)sysvar->value, value, value_length); retval = ipcom_hash_add(tree->sysvars, sysvar); leave: return retval; /*lint !e429 Custodial pointer 'sysvar' has not been freed or returned */ }
/* *=========================================================================== * ipcom_sysvar_getvr *=========================================================================== * Description: * Parameters: * Returns: */ IP_GLOBAL char * ipcom_sysvar_getvr(const char *name, char *value, Ip_size_t *value_size, Ip_bool usr, int vr) { Ipcom_sysvar_entry *sysvar; Ip_size_t value_length; char *ret_value = IP_NULL; Ip_err retval; Ipcom_sysvar_tree *tree; if (name == IP_NULL) return IP_NULL; retval = ipcom_once(&ipcom_sysvar_once, ipcom_sysvar_init, IP_NULL); if (retval != IPCOM_SUCCESS) { IP_PANIC(); return IP_NULL; } IPCOM_CODE_LOCK(); tree = ipcom_sysvar_tree_get(vr); if (tree == IP_NULL) goto leave; sysvar = ipcom_hash_get(tree->sysvars, name); if (sysvar) { if (value == IP_NULL) { #ifdef IP_PORT_OSE5 if (usr) ret_value = ipcom_strdup_usr(sysvar->value); else #else (void)usr; #endif ret_value = ipcom_strdup(sysvar->value); } else { value_length = ipcom_strlen(sysvar->value) + 1; if (value_length > *value_size) { ret_value = IP_NULL; *value_size = value_length; } else { ret_value = value; ipcom_memcpy(ret_value, sysvar->value, value_length); *value_size = value_length - 1; } } } #ifdef IP_PORT_OSE5 else { ret_value = ipcom_sysvar_get_ose5(name, value, value_size); } #endif /* IP_PORT_OSE5 */ leave: ipcom_sysvar_tree_done(tree); IPCOM_CODE_UNLOCK(); return ret_value; }
/* *=========================================================================== * ipnet_nat_proxy_sip_payload_parse *=========================================================================== * Description: Parse SIP payload. * Parameters: appdata - pointer to application data. * applen - pointer to length of application data. * growspace - space available to extend application data. * param - pointer to proxy parameters. * newdata - pointer to pointer to new application data. * Returns: IP_TRUE = Packet modified. * IP_FALSE = Packet untouched. */ IP_STATIC Ip_bool ipnet_nat_proxy_sip_payload_parse(Ip_u8 *appdata, int *applen, int growspace, Ipnet_nat_proxy_param *param, Ip_u8 **newdata) { char *psipmsg = (char *)appdata; char *pcallid = IP_NULL; char *pendstr, *pstartstr, *psearch; Ip_bool retcode = IP_FALSE; int pos, sdpdatalen, searchlen, msgtype = 0; char tmpholder[50]; char laddrstr[20]; char gaddrstr[20]; char *pend = (char *)sipbuf + *applen - 1; char *sdplen_start, *sdplen_end, *sdp_end; int newlen, diff; if (param->incoming == IP_TRUE) { /* Incoming message*/ goto parseFalseExit; } if (param->inbound == IP_FALSE) { /* Outbound session */ if ((psipmsg = ipnet_nat_proxy_sip_outboundmsgtypecheck(psipmsg, &msgtype, *applen)) == IP_NULL) return IP_FALSE; /* not the message we're looking for */ } else { /* Inbound session */ if ((psipmsg = ipnet_nat_proxy_sip_inboundmsgtypecheck(psipmsg, &msgtype, *applen)) == IP_NULL) return IP_FALSE; /* not the message we're looking for */ } /* find the call-id field */ if (ipnet_nat_proxy_sip_keyfind(psipmsg, SIP_CALLID_STR, &pos, *applen - (psipmsg - (char *)appdata)) == IP_FALSE) { IPCOM_LOG0(ERR, "ipnet_nat_proxy_sip_payload_parse() :: no callid field"); return IP_FALSE; } /* get callid string */ pcallid = ipnet_nat_proxy_sip_callidstr(psipmsg + pos + SIP_TAG_TO_DATAPOS(SIP_CALLID_STR)); if (pcallid == IP_NULL) { IPCOM_LOG0(ERR, "ipnet_nat_proxy_sip_payload_parse() :: failed to parse callid string"); return IP_FALSE; } if (msgtype == SIP_MSG_TYPE_INVITE) { if (param->inbound == IP_FALSE) { /* Update the mapping timeout */ IPCOM_LOG1(DEBUG, "ipnet_nat_proxy_sip_payload_parse() :: setting mapping timeout to %d seconds", IPNET_NAT_SIP_ENTRY_INVITE_TIMEOUT); ipnet_nat_proxy_set_mapping_timeout(IPNET_NAT_SIP_ENTRY_INVITE_TIMEOUT, param->mapping); } else { /* ALG will not detect the ACK for inbound calls so use the INVITE response to set established timeout */ IPCOM_LOG1(DEBUG, "ipnet_nat_proxy_sip_payload_parse() :: setting mapping timeout to %d seconds", IPNET_NAT_SIP_ENTRY_ESTABLISHED_TIMEOUT); ipnet_nat_proxy_set_mapping_timeout(IPNET_NAT_SIP_ENTRY_ESTABLISHED_TIMEOUT, param->mapping); } } else if (msgtype == SIP_MSG_TYPE_ACK) { /* Update the mapping timeout */ IPCOM_LOG1(DEBUG, "ipnet_nat_proxy_sip_payload_parse() :: setting mapping timeout to %d seconds", IPNET_NAT_SIP_ENTRY_ESTABLISHED_TIMEOUT); ipnet_nat_proxy_set_mapping_timeout(IPNET_NAT_SIP_ENTRY_ESTABLISHED_TIMEOUT, param->mapping); } /* Copy the message to scratch buffer and set pointer */ if (*applen > (int)sizeof(sipbuf)) { IPCOM_LOG0(ERR, "ipnet_nat_proxy_sip_payload_parse() :: message to long"); goto parseFalseExit; } ipcom_memcpy(sipbuf, appdata, *applen); psipmsg = (char *)sipbuf + (psipmsg - (char *)appdata); /* first the via field * For response message, the Via field will not contain the private address. * The localAddrProcess() will check if the address is private. */ laddrstr[0] = gaddrstr[0] = 0; if (ipnet_nat_proxy_sip_keyfind(psipmsg, SIP_VIA_STR, &pos, (pend - psipmsg) + 1) == IP_TRUE) { /* advance to IP/Port string */ psipmsg += (pos + ipcom_strlen(SIP_VIA_STR) + SIP_VIA_FIELD_IPADDR_DIS); IPCOM_LOG0(DEBUG, "ipnet_nat_proxy_sip_payload_parse() :: parse via field"); psipmsg = ipnet_nat_proxy_sip_localaddrprocess(psipmsg, laddrstr, gaddrstr, pcallid, SIP_ADDRESS_PORT_STRING, param, &pend); if (psipmsg == IP_NULL) goto parseFalseExit; } /* find the contact field */ if (ipnet_nat_proxy_sip_keyfind (psipmsg, SIP_CONTACT_STR, &pos, (pend - psipmsg) + 1) == IP_TRUE) { /* advance to IP/Port string */ psipmsg += (pos + ipcom_strlen(SIP_CONTACT_STR) + SIP_CTAC_FIELD_IPADDR_DIS); IPCOM_LOG0(DEBUG, "ipnet_nat_proxy_sip_payload_parse() :: parse contact field"); psipmsg = ipnet_nat_proxy_sip_localaddrprocess(psipmsg, laddrstr, gaddrstr, pcallid, SIP_ADDRESS_PORT_STRING, param, &pend); if (psipmsg == IP_NULL) goto parseFalseExit; } /* exit if there isn't any private info in SIP message header */ if (laddrstr[0] == 0 || gaddrstr[0] == 0) goto parseFalseExit; /* When program reaches here, it indicates at least one place in the * packet should be modified. Use parseFalseExit only if it is an error */ /* find the Content-Type field */ if (ipnet_nat_proxy_sip_keyfind (psipmsg, SIP_CONTYPE_STR, &pos, (pend - psipmsg) + 1) == IP_FALSE) goto parseTrueExit; /* advance to start of data field */ psipmsg += (pos + SIP_TAG_TO_DATAPOS(SIP_CONTYPE_STR)); SIP_SKIP_SPACES(psipmsg); /*check the application/sdp type, if not, exit */ if (!SIP_IS_STRING_SAME(psipmsg, SIP_APPSDP_STR)) goto parseTrueExit; /* find the content length field */ if (ipnet_nat_proxy_sip_keyfind (psipmsg, SIP_CONTLEN_STR, &pos, (pend - psipmsg) + 1) == IP_FALSE) goto parseTrueExit; IPCOM_LOG0(DEBUG, "ipnet_nat_proxy_sip_payload_parse() :: parse Content-Length field"); /* reach to the content length field, advance to length data */ psipmsg += (pos + SIP_TAG_TO_DATAPOS(SIP_CONTLEN_STR)); SIP_SKIP_SPACES(psipmsg); sdpdatalen = ipcom_strtol(psipmsg, &pendstr, 10); IPCOM_LOG1(DEBUG, "ipnet_nat_proxy_sip_payload_parse() :: data length = %d", sdpdatalen); if (sdpdatalen == 0) goto parseTrueExit; /* store start and end of sdp datalength string as well as end of message */ sdplen_start = psipmsg; sdplen_end = pendstr; sdp_end = pend; /* advance to the start of SDP data */ if (ipnet_nat_proxy_sip_keyfind (psipmsg, IP_NULL, &pos, (pend - psipmsg) + 1) == IP_FALSE) { IPCOM_LOG0(DEBUG, "ipnet_nat_proxy_sip_payload_parse() :: Can't find header end mark"); goto parseTrueExit; } /* start of the SIP data field */ psipmsg += pos; searchlen = sdpdatalen; /* search the local IP address, and replace it with global address */ pstartstr = psipmsg; while (IP_TRUE) { psearch = ipnet_nat_proxy_sip_faststrsearch(laddrstr, ipcom_strlen(laddrstr), pstartstr, searchlen, IP_FALSE); if (psearch != IP_NULL) { IPCOM_LOG1(DEBUG, "ipnet_nat_proxy_sip_payload_parse() :: Local IP address in SDP: %s", laddrstr); if (ipnet_nat_proxy_sip_modmsg(gaddrstr, ipcom_strlen(gaddrstr), psearch, ipcom_strlen(laddrstr), &pend) < 0) { goto parseFalseExit; } searchlen = searchlen - (psearch + ipcom_strlen(gaddrstr) - pstartstr); pstartstr = psearch + ipcom_strlen(gaddrstr); } else break; } IPCOM_LOG1(DEBUG, "ipnet_nat_proxy_sip_payload_parse() :: the last search length %d", searchlen); /* search for the audio port */ if (ipnet_nat_proxy_sip_keyfind (psipmsg, SIP_AUDIO_STR, &pos, sdpdatalen) == IP_TRUE) { /* advance to the port field */ psipmsg += (pos + SIP_TAG_TO_DATAPOS(SIP_AUDIO_STR)); SIP_SKIP_SPACES(psipmsg); ipnet_nat_proxy_sip_localaddrprocess(psipmsg, laddrstr, gaddrstr, pcallid, SIP_PORT_STRING, param, &pend); } /* search for the audio control port */ if (ipnet_nat_proxy_sip_keyfind (psipmsg, SIP_RTCP_STR, &pos, sdpdatalen) == IP_TRUE) { /* advance to the port field */ psipmsg += (pos + SIP_TAG_TO_DATAPOS(SIP_RTCP_STR)); SIP_SKIP_SPACES(psipmsg); ipnet_nat_proxy_sip_localaddrprocess(psipmsg, laddrstr, gaddrstr, pcallid, SIP_PORT_STRING, param, &pend); } /* adjust the length node */ sdpdatalen += pend - sdp_end; ipcom_sprintf(tmpholder, "%d", sdpdatalen); if (ipnet_nat_proxy_sip_modmsg(tmpholder, ipcom_strlen(tmpholder), sdplen_start, sdplen_end - sdplen_start, &pend) < 0) { goto parseFalseExit; } parseTrueExit: /* Update application data with the modified buffer */ newlen = pend - (char *)sipbuf + 1; diff = newlen - *applen; if (diff > growspace) { /* Must allocate a new buffer */ *newdata = ipcom_malloc(*applen + diff); if (*newdata == IP_NULL) { IPCOM_LOG1(ERR, "ipnet_nat_proxy_sip_payload_parse() :: ipcom_malloc(%d) failed", *applen + diff); goto parseFalseExit; } ipcom_memcpy(*newdata, sipbuf, newlen); } else { /* Let the current buffer grow */ ipcom_memcpy(appdata, sipbuf, newlen); } *applen = newlen; IPCOM_LOG1(DEBUG, "ipnet_nat_proxy_sip_msg() :: the delta length = %d ", diff); retcode = IP_TRUE; parseFalseExit: if (msgtype == SIP_MSG_TYPE_BYE) ipnet_nat_proxy_sip_endmsgprocess(pcallid, param); if (pcallid) ipcom_free(pcallid); return retcode; }