/* ****************************************************************************** * INTERPEAK SOURCE FILE * * Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipmip_inet.c,v $ $Revision: 1.11.10.3 $ * $Source: /home/interpeak/CVSRoot/ipmip/src/ipmip_inet.c,v $ * $Author: jsheng $ * $State: Exp $ $Locker: $ * * INTERPEAK_COPYRIGHT_STRING * Design and implementation by Joel Hortelius ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ /* ****************************************************************************** * INTERPEAK SOURCE FILE * * Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipmip_inet.c,v $ $Revision: 1.11.10.3 $ * $Source: /home/interpeak/CVSRoot/ipmip/src/ipmip_inet.c,v $ * $Author: jsheng $ * $State: Exp $ $Locker: $ * * INTERPEAK_COPYRIGHT_STRING * Design and implementation by Joel Hortelius ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #include "ipmip_config.h" #ifdef IPMIP_USE_INET /* **************************************************************************** * 3 INCLUDE FILES **************************************************************************** */ #define IPCOM_USE_CLIB_PROTO #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* **************************************************************************** * 4 DEFINES **************************************************************************** */ #define IPMIP_INET_PKT_CLEN 128 #define IPCOM_SYSLOG_PRIORITY IPCOM_LOG_DEBUG2 #define IPCOM_SYSLOG_FACILITY IPCOM_LOG_IPMIP /* **************************************************************************** * 5 TYPES **************************************************************************** */ /* **************************************************************************** * 6 EXTERN PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 7 LOCAL PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 8 DATA **************************************************************************** */ static Ip_u16 ipmip_pkt_ipid = 1; /* **************************************************************************** * 9 STATIC FUNCTIONS **************************************************************************** */ IP_STATIC unsigned ipmip_inet_arp_key_ifindex(Ip_u32 *ifindex) { return ipcom_hash_update(ifindex, sizeof(*ifindex), 0); } IP_STATIC unsigned ipmip_inet_arp_obj_ifindex(Ipmip_arp_node_t *node) { return ipmip_inet_arp_key_ifindex(&node->ifindex); } IP_STATIC Ip_bool ipmip_inet_arp_cmp_ifindex(Ipmip_arp_node_t *node, Ip_u32 *ifindex) { /* Compare */ return node->ifindex == *ifindex; } IP_STATIC void ipmip_inet_arp_context_create(struct Ipmip_context *ctx, struct Ipmip_proc *proc) { IPMIP_UNUSED_PARAMETER(proc); if (ctx->arp != IP_NULL) return; ctx->arp = ipcom_calloc(1, sizeof(*ctx->arp)); if(IP_NULL == ctx->arp) { return; } ctx->arp->fd_arp_in = IP_INVALID_SOCKET; ctx->arp->fd_arp_out = IP_INVALID_SOCKET; (void)ipcom_mutex_create(&ctx->arp->mutex); ctx->arp->ifindex_table = ipcom_hash_new((Ipcom_hash_obj_func) ipmip_inet_arp_obj_ifindex, (Ipcom_hash_key_func) ipmip_inet_arp_key_ifindex, (Ipcom_hash_cmp_func) ipmip_inet_arp_cmp_ifindex); } IP_STATIC Ipmip_pktbuf_t * ipmip_inet_arp_recvmsg(Ipmip_context_t *ctx, Ipmip_proc_t *proc, Ip_size_t vlen, Ip_fd fd) { int len; struct Ip_sockaddr_ll ll; struct Ip_msghdr msg; struct Ip_iovec vec; /* Set when the option is located */ Ipmip_pktbuf_t *pbuf = IP_NULL; /* Allocate pktbuf */ pbuf = (Ipmip_pktbuf_t *)ipmip_pktbuf_alloc(ctx, proc, vlen); /* Failed to allocate buffer? */ if (pbuf == IP_NULL) return IP_NULL; /* Initialize vector */ vec.iov_base = IPMIP_BUFFER_DATA(&pbuf->packet); vec.iov_len = vlen; /* Initialize name */ msg.msg_name = ≪ msg.msg_namelen = sizeof(ll); /* Initialize io */ msg.msg_iov = &vec; msg.msg_iovlen = 1; /* Initialize control */ msg.msg_control = IP_NULL; msg.msg_controllen = 0; /* Clear flags */ msg.msg_flags = 0; /* Read and process a Mobile Header message */ if ((len = ipcom_recvmsg(fd, &msg, 0)) < 0) { /* Failure */ IPCOM_LOG2(ERR, "%s: Failed to receive from ARP socket = %x", ctx->name, ipcom_errno); ipmip_util_sock_clear(fd); goto error_out; } /* Sanity, must be atleast the mobility header */ if ((Ip_size_t)len < sizeof(Ipmip_arp_hdr_t)) { /* Failure */ IPCOM_LOG1(INFO, "%s: ARP Received packet was too short", ctx->name); goto error_out; } /* We've gotten something */ if ((msg.msg_flags & (IP_MSG_TRUNC | IP_MSG_CTRUNC)) != 0) { /* Failure */ IPCOM_LOG1(INFO, "%s: ARP TRUNC or CTRUNC set, not all data read. Discarding", ctx->name); goto error_out; } /* Store value */ ipmip_util_dup(&pbuf->srcinfo.ll, &ll, sizeof(ll)); /**/ pbuf->srcinfo.lladdr = ipmip_lladdr_ll_to_lladdr(pbuf->srcinfo.ll); /* Move past the read length */ ipmip_buffer_append(&pbuf->packet, IP_NULL, len); /* */ return pbuf; error_out: ipmip_pktbuf_release(ctx, proc, pbuf); return IP_NULL; } /* **************************************************************************** * 10 GLOBAL FUNCTIONS **************************************************************************** */ IP_GLOBAL void ipmip_inet_arp_write(Ipmip_context_t *ctx, Ipmip_proc_t *proc, Ip_u32 from, Ip_u32 to, Ipmip_if_t *iff, Ipmip_lladdr_t *lladdr) { IPMIP_UNUSED_PARAMETER(proc); /* Only do MAC */ if (lladdr->type == IPMIP_LLADDR_TYPE_MAC && iff->lladdr != IP_NULL && iff->lladdr->type == lladdr->type) { struct Ip_iovec iov; struct Ip_msghdr m; Ipmip_arp_hdr_t arp; struct Ip_sockaddr_ll to_ll; ipcom_memset(&m, 0, sizeof(m)); /* Set the base values */ arp.hrd = IPMIP_ARP_HRD_ETHER; arp.pro = IPMIP_ARP_PRO_IP; arp.hln_pln = IPMIP_ARP_HLN_PLN; arp.op = IPMIP_ARP_OP_REPLY; /* Setup the structures */ ipcom_memcpy(arp.eth_src, iff->lladdr->lla, IPMIP_ETH_ADDR_SIZE); ipcom_memcpy(arp.eth_dst, lladdr->lla, IPMIP_ETH_ADDR_SIZE); IP_SET_32ON8(arp.ip_src, from); IP_SET_32ON8(arp.ip_dst, to); IPCOM_SA_LEN_SET(&to_ll, sizeof(to_ll)); to_ll.sll_family = IP_AF_PACKET; to_ll.sll_protocol = ip_htons(IPMIP_ETH_P_ARP); to_ll.sll_ifindex = iff->ifindex; to_ll.sll_halen = IPMIP_ETH_ADDR_SIZE; ipcom_memcpy(to_ll.sll_addr, lladdr->lla, IPMIP_ETH_ADDR_SIZE); iov.iov_base = &arp; iov.iov_len = sizeof(arp); m.msg_iov = &iov; m.msg_iovlen = 1; m.msg_name = &to_ll; m.msg_namelen = sizeof(to_ll); /* */ if (ipcom_sendmsg(ctx->arp->fd_arp_out, &m, 0) < 0) ipmip_util_sock_clear(ctx->arp->fd_arp_out); } } IP_GLOBAL void ipmip_inet_arp_reply(Ipmip_context_t *ctx, Ipmip_proc_t *proc, Ipmip_arp_hdr_t *arp_req, Ipmip_if_t *iff) { IPMIP_UNUSED_PARAMETER(proc); /* Only do MAC */ if (iff->lladdr != IP_NULL && iff->lladdr->type == IPMIP_LLADDR_TYPE_MAC) { Ipmip_lladdr_t *lla = ipmip_lladdr_build((Ipmip_lladdr_t *)proc->ntop.ntop_pbuf, iff->lladdr->type, iff->lladdr->type, &arp_req->eth_src[0], IPMIP_ETH_ADDR_SIZE); ipmip_inet_arp_write(ctx, proc, IP_GET_32ON8(&arp_req->ip_dst), IP_GET_32ON8(&arp_req->ip_src), iff, lla); } } IP_GLOBAL Ipmip_pktbuf_t * ipmip_inet_udp_recvmsg(Ipmip_context_t *ctx, Ipmip_proc_t *proc, Ip_size_t vlen, Ip_fd fd) { struct Ip_cmsghdr *cmsghdr; int len; /* Destination Option & Packet Info */ struct Ip_msghdr msg; struct Ip_iovec vec; Ipmip_pktbuf_t *pbuf = IP_NULL; struct Ip_sockaddr_in src; /* Allocate pktbuf */ pbuf = (Ipmip_pktbuf_t *)ipmip_pktbuf_alloc(ctx, proc, vlen + IPMIP_INET_PKT_CLEN); /* Failed to allocate buffer? */ if (pbuf == IP_NULL) return IP_NULL; /* Initialize vector */ vec.iov_base = IPMIP_BUFFER_DATA(&pbuf->packet); vec.iov_len = vlen; /* Initialize name */ msg.msg_name = &src; msg.msg_namelen = sizeof(src); /* Initialize io */ msg.msg_iov = &vec; msg.msg_iovlen = 1; /* Initialize control */ msg.msg_control = ipmip_buffer_offset(&pbuf->packet, vlen); msg.msg_controllen = IPMIP_INET_PKT_CLEN; /* Clear flags */ msg.msg_flags = 0; /* Read and process a Mobile Header message */ if ((len = ipcom_recvmsg(fd, &msg, 0)) <= 0) { ipmip_util_sock_clear(fd); goto error_out; } /* We've gotten something */ if ((msg.msg_flags & (IP_MSG_TRUNC | IP_MSG_CTRUNC)) != 0) goto error_out; /* Store value */ ipmip_util_dup(&pbuf->srcinfo.src, &src, sizeof(src)); /* Move past the read length */ ipmip_buffer_append(&pbuf->packet, IP_NULL, len); /* Did we get any ancillary data? */ if (msg.msg_controllen > 0) { /* Loop the ancillary data, see what we find */ for (cmsghdr = IP_CMSG_FIRSTHDR(&msg); cmsghdr != 0; cmsghdr = IP_CMSG_NXTHDR(&msg, cmsghdr)) { /* Correct level? */ if (cmsghdr->cmsg_level == IP_IPPROTO_IP) { /* Type? */ switch (cmsghdr->cmsg_type) { case IP_IP_X_SENDERLINKADDR: { struct Ip_sockaddr_dl *dl = IP_CMSG_DATA(cmsghdr); ipmip_util_dup(&pbuf->srcinfo.dl, dl, IPCOM_SA_LEN_GET(dl)); } break; case IP_IP_PKTINFO: { struct Ip_in_pktinfo *pktinfo = IP_CMSG_DATA(cmsghdr); ipmip_pktbuf_srcinfo_dst_inet(pbuf, pktinfo); } break; case IP_IP_TTL: { int *ttl = IP_CMSG_DATA(cmsghdr); pbuf->srcinfo.ttl = IP_GET_32ON8(ttl); } break; default: break; } } } } if (pbuf->srcinfo.dst == IP_NULL) goto error_out; pbuf->srcinfo.lladdr = ipmip_lladdr_dl_to_lladdr(pbuf->srcinfo.dl, pbuf->srcinfo.dst->ifindex); return pbuf; error_out: ipmip_pktbuf_release(ctx, proc, pbuf); return IP_NULL; } /* *=========================================================================== * ipmip4_pkt_udp_write *=========================================================================== * Description: Send a UDP message to a link local host with the * indicated MAC address. * Parameters: ctx - The context * proc - Process context * payload - The payload buffer * from - The source address * from_port - The source port in netwrok byte order * to - The destination address * to_port - The destination port in network byte order * iff - Outgoing interface * lla - MAC address * Returns: The resulting return code. * */ IP_GLOBAL int ipmip_inet_udp_write(Ipmip_context_t *ctx, Ipmip_proc_t *proc, Ip_fd fd_pkt, Ip_fd fd_raw, Ipmip_buffer_t *payload, Ip_u32 from, Ip_u16 from_port, Ip_u32 to, Ip_u16 to_port, Ipmip_if_t *iff, Ipmip_lladdr_t *lladdr) { int ret = -IP_ERRNO_EINVAL; Ip_u32 chk; Ip_size_t tot_size = 0; struct Ip_iovec iov[3]; Ipcom_ip_header iph; Ipcom_udp_header udph; struct Ip_msghdr m; IPMIP_UNUSED_PARAMETER(proc); /* */ if (fd_raw != IP_INVALID_SOCKET) { if (lladdr == IP_NULL || fd_pkt == IP_INVALID_SOCKET || lladdr->type != IPMIP_LLADDR_TYPE_MAC) return ipmip_inet_udp_sendmsg(ctx, proc, fd_raw, payload, from, from_port, to, to_port, iff); } else if (lladdr == IP_NULL) return -IP_ERRNO_EINVAL; chk = 0; /* Create the IO vector */ iov[0].iov_base = &iph; iov[0].iov_len = sizeof(iph); iov[1].iov_base = &udph; iov[1].iov_len = sizeof(udph); iov[2].iov_base = IPMIP_BUFFER_DATA(payload); iov[2].iov_len = IPMIP_BUFFER_SIZE(payload); /* Start with the payload as total size */ tot_size = IPMIP_BUFFER_SIZE(payload); /* Zero the memory */ ipcom_memset(&iph, 0, sizeof(iph)); ipcom_memset(&udph, 0, sizeof(udph)); ipcom_memset(&m, 0, sizeof(m)); /* Include the UDP header */ tot_size += sizeof(udph); if (to == 0) /* Send to world wide broadcast */ to = IP_INADDR_BROADCAST; /* Create the UDP packet */ udph.src_port = from_port; udph.dst_port = to_port; udph.length = ip_htons((Ip_u16) tot_size); /* IPv4 header */ tot_size += sizeof(iph); iph.vers_len = 0x45; iph.id = ip_htons(ipmip_pkt_ipid); iph.ttl = 255; iph.protocol = IP_IPPROTO_UDP; iph.src.addr32 = from; iph.dst.addr32 = to; ipmip_pkt_ipid++; /* UDP checksum (including pseudo-header) */ chk = ((Ip_u16 *) &iph.src)[0]; chk += ((Ip_u16 *) &iph.src)[1]; chk += ((Ip_u16 *) &iph.dst)[0]; chk += ((Ip_u16 *) &iph.dst)[1]; chk += udph.length; { Ip_u16 tmp = iph.protocol; chk += ip_htons(tmp); } chk += ipcom_in_checksum_update(&udph, sizeof(udph)); /* Do the checksum calculation */ chk += ipcom_in_checksum_update(iov[2].iov_base, iov[2].iov_len); udph.checksum = ipcom_in_checksum_finish(chk); m.msg_iov = iov; m.msg_iovlen = 3; /* Is it a local packet or routed packet? */ iph.length = ip_htons(((Ip_u16)tot_size)); /* Local; build IP & UDP header */ chk = ipcom_in_checksum_update(&iph, sizeof(iph)); iph.checksum = ipcom_in_checksum_finish(chk); /**/ if (fd_pkt != IP_INVALID_SOCKET) { /* Only deal with MAC's right now */ if (lladdr->type == IPMIP_LLADDR_TYPE_MAC) { struct Ip_sockaddr_ll to_ll; IPCOM_SA_LEN_SET(&to_ll, sizeof(to_ll)); to_ll.sll_family = IP_AF_PACKET; to_ll.sll_protocol = ip_htons(0x800); to_ll.sll_ifindex = iff->ifindex; to_ll.sll_halen = 6; ipcom_memcpy(to_ll.sll_addr, lladdr->lla, IPMIP_ETH_ADDR_SIZE); m.msg_name = &to_ll; m.msg_namelen = sizeof(to_ll); if ((ipcom_sendmsg(fd_pkt, &m, 0)) < 0) { ret = -ipcom_errno; ipmip_util_sock_clear(fd_pkt); } else { ret = IPCOM_SUCCESS; } goto done_out; } } /**/ done_out: return ret; } IP_GLOBAL Ip_fd ipmip_inet_udp_socket(struct Ip_sockaddr_in *s_in) { Ip_fd s; int i = 1; Ip_socklen_t slen; /* Create raw IP socket for all IPv4 input on this interface */ if ((s = ipcom_socket(IP_AF_INET, IP_SOCK_DGRAM, IP_IPPROTO_UDP)) == IP_INVALID_SOCKET) return IP_INVALID_SOCKET; /* Allow reusage of address */ if (ipcom_setsockopt(s, IP_SOL_SOCKET, IP_SO_REUSEADDR, &i, sizeof(i))) goto fail; /* Allow reusage of ports */ if (ipcom_setsockopt(s, IP_SOL_SOCKET, IP_SO_REUSEPORT, &i, sizeof(i))) goto fail; /* I want to receive PACKET INFO as ancillary data */ if (ipcom_setsockopt(s, IP_IPPROTO_IP, IP_IP_PKTINFO, &i, sizeof(i)) < 0) goto fail; if (ipcom_setsockopt(s, IP_IPPROTO_IP, IP_IP_RECVTTL, &i, sizeof(i))) goto fail; /* Enable IP_X_SENDERLINKADDR to get source link address */ if (ipcom_setsockopt(s, IP_IPPROTO_IP, IP_IP_X_SENDERLINKADDR, &i, sizeof(i)) < 0) goto fail; if (s_in != IP_NULL) { /* */ if (ipcom_bind(s, (struct Ip_sockaddr *) s_in, sizeof(*s_in)) < 0) goto fail; slen = sizeof(*s_in); if (ipcom_getsockname(s, (struct Ip_sockaddr *) s_in, &slen) < 0) goto fail; } return s; fail: ipcom_socketclose(s); return IP_INVALID_SOCKET; } /* *=========================================================================== * ipmip_inet_udp_sendmsg *=========================================================================== * Description: Send a UDP message to a remote host * Parameters: ctx - The context * proc - Process context * payload - The payload buffer * from - The source address * from_port - The source port in network byte order * to - The destination address * to_port - The destination port in network byte order * iff - If set; the interface to force the output on. * Returns: The resulting return code. * */ IP_GLOBAL int ipmip_inet_udp_sendmsg(Ipmip_context_t *ctx, Ipmip_proc_t *proc, Ip_fd fd_raw, Ipmip_buffer_t *payload, Ip_u32 from, Ip_u16 from_port, Ip_u32 to, Ip_u16 to_port, Ipmip_if_t *iff) { int ret = IPCOM_SUCCESS; Ip_u32 chk; Ip_size_t tot_size = 0; struct Ip_iovec iov[3]; Ipcom_ip_header iph; Ipcom_udp_header udph; struct Ip_msghdr m; Ip_u8 cmsg_buf[IP_CMSG_SPACE(sizeof(struct Ip_in_pktinfo))]; struct Ip_cmsghdr *c; struct Ip_in_pktinfo *pktinfo; struct Ip_sockaddr_in sin4; IPMIP_UNUSED_PARAMETER(ctx); IPMIP_UNUSED_PARAMETER(proc); chk = 0; /* Create the IO vector */ iov[0].iov_base = &iph; iov[0].iov_len = sizeof(iph); iov[1].iov_base = &udph; iov[1].iov_len = sizeof(udph); iov[2].iov_base = IPMIP_BUFFER_DATA(payload); iov[2].iov_len = IPMIP_BUFFER_SIZE(payload); /* Start with the payload as total size */ tot_size = IPMIP_BUFFER_SIZE(payload); /* Zero the memory */ ipcom_memset(&iph, 0, sizeof(iph)); ipcom_memset(&udph, 0, sizeof(udph)); ipcom_memset(&m, 0, sizeof(m)); /* Include the UDP header */ tot_size += sizeof(udph); if (to == 0) to = IP_INADDR_BROADCAST; /* Create the UDP packet */ udph.src_port = from_port; udph.dst_port = to_port; udph.length = ip_htons((Ip_u16) tot_size); /* IPv4 header */ tot_size += sizeof(iph); iph.vers_len = 0x45; iph.id = ip_htons(ipmip_pkt_ipid); iph.ttl = 255; iph.protocol = IP_IPPROTO_UDP; iph.src.addr32 = from; iph.dst.addr32 = to; ipcom_memset(&sin4, 0, sizeof(sin4)); sin4.sin_family = IP_AF_INET; IPCOM_SA_LEN_SET(&sin4, sizeof(sin4)); sin4.sin_port = to_port; sin4.sin_addr.s_addr = to; ipmip_pkt_ipid++; /* UDP checksum (including pseudo-header) */ chk = ((Ip_u16 *) &iph.src)[0]; chk += ((Ip_u16 *) &iph.src)[1]; chk += ((Ip_u16 *) &iph.dst)[0]; chk += ((Ip_u16 *) &iph.dst)[1]; chk += udph.length; { Ip_u16 tmp = iph.protocol; chk += ip_htons(tmp); } chk += ipcom_in_checksum_update(&udph, sizeof(udph)); /* Do the checksum calculation */ chk += ipcom_in_checksum_update(iov[2].iov_base, iov[2].iov_len); udph.checksum = ipcom_in_checksum_finish(chk); m.msg_iov = iov; m.msg_iovlen = 3; /* Is it a local packet or routed packet? */ iph.length = (Ip_u16) tot_size; m.msg_name = &sin4; m.msg_namelen = sizeof(sin4); /* Force it out the indicated interface */ if (iff != IP_NULL) { /* Use ancillary data to specify outgoing interface and address. */ c = (struct Ip_cmsghdr *) cmsg_buf; c->cmsg_len = IP_CMSG_LEN(sizeof(struct Ip_in_pktinfo)); c->cmsg_level = IP_IPPROTO_IP; c->cmsg_type = IP_IP_PKTINFO; pktinfo = IP_CMSG_DATA(c); ipcom_memset(pktinfo, 0, sizeof(*pktinfo)); /* Bind to the correct interface */ pktinfo->ipi_ifindex = iff->ifindex; m.msg_control = c; m.msg_controllen = sizeof(cmsg_buf); } /* Do send */ if (ipcom_sendmsg(fd_raw, &m, 0) <0) { ret = -ipcom_errno; ipmip_util_sock_clear(fd_raw); } /**/ return ret; } IP_GLOBAL void ipmip_inet_arp_context_in_create(struct Ipmip_context *ctx, struct Ipmip_proc *proc) { ipmip_inet_arp_context_create(ctx, proc); if (ctx->arp->fd_arp_in == IP_INVALID_SOCKET) { ctx->arp->fd_arp_in = ipcom_socket(IP_AF_PACKET, IP_SOCK_DGRAM, ip_htons(0x0806)); ipcom_shutdown(ctx->arp->fd_arp_in, IP_SHUT_WR); } } IP_GLOBAL void ipmip_inet_arp_context_out_create(struct Ipmip_context *ctx, struct Ipmip_proc *proc) { ipmip_inet_arp_context_create(ctx, proc); if (ctx->arp->fd_arp_out == IP_INVALID_SOCKET) { ctx->arp->fd_arp_out = ipcom_socket(IP_AF_PACKET, IP_SOCK_DGRAM, ip_htons(0x0806)); ipcom_shutdown(ctx->arp->fd_arp_out, IP_SHUT_RD); } } IP_GLOBAL void ipmip_inet_arp_context_destroy(struct Ipmip_context *ctx, struct Ipmip_proc *proc) { IPMIP_UNUSED_PARAMETER(proc); if (ctx->arp != IP_NULL) { if (ctx->arp->fd_arp_in != IP_INVALID_SOCKET) ipcom_socketclose(ctx->arp->fd_arp_in); if (ctx->arp->fd_arp_out != IP_INVALID_SOCKET) ipcom_socketclose(ctx->arp->fd_arp_out); if (ctx->arp->ifindex_table) ipcom_hash_delete(ctx->arp->ifindex_table); ipcom_mutex_delete(&ctx->arp->mutex); ipcom_free(ctx->arp); ctx->arp = IP_NULL; } } IP_GLOBAL void ipmip_inet_arp_process(struct Ipmip_context *ctx, struct Ipmip_proc *proc) { Ipmip_pktbuf_t *pbuf = ipmip_inet_arp_recvmsg(ctx, proc, 1024, ctx->arp->fd_arp_in); /* Invoke callback */ if (pbuf) { Ipmip_arp_node_t *node = IP_NULL; ipcom_mutex_lock(ctx->arp->mutex); node = ipcom_hash_get(ctx->arp->ifindex_table, &pbuf->srcinfo.ll->sll_ifindex); /* Time to invoke function */ if (node != IP_NULL) ipmip_timer_request(ctx, proc, &pbuf->timeout, node->lock, node->process_func, node, pbuf, 0); else ipmip_pktbuf_release(ctx, proc, pbuf); ipcom_mutex_unlock(ctx->arp->mutex); } } IP_GLOBAL void ipmip_inet_arp_register(struct Ipmip_context *ctx, struct Ipmip_proc *proc, Ipmip_arp_node_t *node) { IPMIP_UNUSED_PARAMETER(proc); /* We're going to relay */ ipcom_mutex_lock(ctx->arp->mutex); if (node->ifindex) ipcom_hash_add(ctx->arp->ifindex_table, node); ipcom_mutex_unlock(ctx->arp->mutex); } IP_GLOBAL void ipmip_inet_arp_unregister(struct Ipmip_context *ctx, struct Ipmip_proc *proc, Ipmip_arp_node_t *node) { IPMIP_UNUSED_PARAMETER(proc); /* We're going to relay */ ipcom_mutex_lock(ctx->arp->mutex); if (node->ifindex) ipcom_hash_remove(ctx->arp->ifindex_table, node); ipcom_mutex_unlock(ctx->arp->mutex); } /* *=========================================================================== * ipmip_inet_arp_proxy *=========================================================================== * Description: This is run when initiating proxying for an address * Sets(/deletes) a static, permanent, public and blackholed arp entry, * plus sends out a gratuitous arp. * Parameters: * Returns: IP_TRUE on success. * */ IP_GLOBAL Ip_bool ipmip_inet_arp_proxy(Ipmip_context_t *ctx, Ipmip_proc_t *proc, Ip_u32 ifindex, Ip_u32 address, Ip_bool set) { return ipmip_netlink_inX_neigh(ctx, proc, IP_AF_INET, set? IP_RTM_NEWNEIGH : IP_RTM_DELNEIGH, IP_NLM_F_CREATE, ifindex, IP_NTF_PROXY|IP_NTF_GRAT, IP_NUD_PERMANENT|IP_NUD_REACHABLE, &address, IP_NULL) == 0; } /* **************************************************************************** * 11 PUBLIC FUNCTIONS **************************************************************************** */ #else int ipmip_inet_empty_file = 0; #endif /* **************************************************************************** * END OF FILE **************************************************************************** */