/* ****************************************************************************** * INTERPEAK SOURCE FILE * * Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipmip4_if.c,v $ $Revision: 1.24.16.2 $ * $Source: /home/interpeak/CVSRoot/ipmip4/src/ipmip4_if.c,v $ * $Author: jsheng $ * $State: Exp $ $Locker: $ * * INTERPEAK_COPYRIGHT_STRING * Design and implementation by Joel Hortelius ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #include "ipmip4_config.h" /* **************************************************************************** * 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 "ipmip4_h.h" #include #include #include #include /* **************************************************************************** * 4 DEFINES **************************************************************************** */ /* **************************************************************************** * 5 TYPES **************************************************************************** */ /* **************************************************************************** * 6 EXTERN PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 7 LOCAL PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 8 DATA **************************************************************************** */ /* **************************************************************************** * 9 STATIC FUNCTIONS **************************************************************************** */ /* *=========================================================================== * ipmip4_if_destroy_tunnel *=========================================================================== * Description: Destroy a particular tunnel. * Parameters: iff - The tunnel to destroy. * Returns: */ IP_STATIC void ipmip4_if_destroy_tunnel(Ipmip4_context_t *ctx, Ipmip_proc_t *proc, Ipmip4_if_t *iff) { struct Ip_ifreq ifreq; int i; /* No tunnel, don't bother */ if (iff->ipmip.ifindex == 0) return; for (i = 0; i < 4; i++) { /* Do down & destroy */ ipmip_if_clear_flags(&ctx->ipmip, proc, &iff->ipmip, IP_IFF_UP); if (ipmip_if_ioctl(&ctx->ipmip, proc, &iff->ipmip, IP_SIOCIFDESTROY, &ifreq) < 0) { IPCOM_LOG3(ERR, "ipcom_socketioctl(%s, IP_SIOCIFDESTROY) failed: %s [%d]", iff->ipmip.ifname, ipcom_strerror(ipcom_errno), ipcom_errno); ipcom_sleep(1); } else { IPCOM_LOG1(DEBUG, "tunnel interface '%s' destroyed", iff->ipmip.ifname); break; } } /* Reset index */ iff->ipmip.ifindex = 0; } /* *=========================================================================== * ipmip4_if_free *=========================================================================== * Description: Destroy and free the interface specific data. * Parameters: ctx - Context * proc - Process * iff - the interface to destroy * Returns: */ IP_STATIC void ipmip4_if_free(Ipmip4_context_t *ctx, Ipmip_proc_t *proc, Ipmip4_if_t *iff) { /* Invoke cleanup functionality */ if (iff->cleanup) (*iff->cleanup) (&ctx->ipmip, proc, &iff->ipmip); /* Destroy this particular tunnel */ if (iff->ipmip.type == IPMIP_IF_TYPE_TUNNEL) ipmip4_if_destroy_tunnel(ctx, proc, iff); } /* **************************************************************************** * 10 GLOBAL FUNCTIONS **************************************************************************** */ /* *=========================================================================== * ipmip4_if_alloc *=========================================================================== * Description: Allocate and initialize the interface structure * Parameters: ctx - Context * proc - Process * ifsize - the size of the interface structure * ifname - The interface name * ifindex - The interface index. * type - Type of interface * identity- The interface identity. * cleanup - Function to be invoked prior to free. * Returns: The interface structure on success. */ IP_GLOBAL Ipmip4_if_t * ipmip4_if_alloc(Ipmip4_context_t *ctx, Ipmip_proc_t *proc, Ip_size_t ifsize, const char *ifname, Ip_u32 ifindex, Ip_u8 type, Ip_u8 identity, Ipmip_if_cleanup_t cleanup) { Ipmip4_if_t *iff = (Ipmip4_if_t *)ipmip_if_alloc(&ctx->ipmip, proc, ifsize, ifname, ifindex, type, identity, (Ipmip_if_cleanup_t)ipmip4_if_free); if (iff == IP_NULL) return IP_NULL; ipcom_list_init(&iff->pktbufs); iff->cleanup = cleanup; return iff; } /* *=========================================================================== * ipmipfa_if_alloc_tunnel *=========================================================================== * Description: Create a specific tunnel for the provided interface * Parameters: ctx - Context * proc - Process * ifsize - Total size of the interface structure * ifname - Wanted ifname * local - The local endpoint * local_port - Base port for NAT_T setup * remote - Remote endpoint * identity - The identity of the tunnel * tunnel_type - Tunnel type * reorder - Enable reordering if supported by interface * cleanup - Function to be invoked prior to free. * Returns: The interface structure on success. * */ IP_GLOBAL Ipmip4_if_t * ipmip4_if_alloc_tunnel(Ipmip4_context_t *ctx, Ipmip_proc_t *proc, Ip_size_t ifsize, char *ifname, Ip_u32 local, Ip_u16 local_port, Ip_u32 remote, Ip_u8 identity, Ip_u8 tunnel_type, Ip_bool reorder, Ipmip_if_cleanup_t cleanup) { struct Ip_ifreq ifreq; struct Ip_ifaliasreq alias; struct Ip_ip_tunnel_param tun; struct Ip_sockaddr_in *inaddr; Ip_u16 flags; Ipmip4_if_t *iff; /* Allocate the structure */ iff = ipmip4_if_alloc(ctx, proc, ifsize, ifname, 0, IPMIP_IF_TYPE_TUNNEL, identity, cleanup); if (iff == IP_NULL) return IP_NULL; /* Try create the interface */ if (ipmip_if_ioctl(&ctx->ipmip, proc, &iff->ipmip, IP_SIOCIFCREATE, &ifreq) < 0) { IPCOM_LOG3(ERR, "ipcom_socketioctl(%s, IP_SIOCIFCREATE) failed : %s [%d]", iff->ipmip.ifname, ipcom_strerror(ipcom_errno), ipcom_errno); goto destroy; } /* May have been modified */ ipcom_strncpy(iff->ipmip.ifname, ifreq.ifr_name, IP_IFNAMSIZ); /* Store the index */ iff->ipmip.ifindex = ipcom_if_nametoindex(iff->ipmip.ifname); iff->ipmip.tunnel_type = tunnel_type; /* Change tunnel */ ipcom_memset(&tun, 0, sizeof(tun)); if((IP_IFNAMSIZ - 1) < strlen(iff->ipmip.ifname)) { goto destroy; } ipcom_strcpy(tun.ifr_name, iff->ipmip.ifname); tun.local_addr.sin.sin_family = IP_AF_INET; tun.local_addr.sin.sin_addr.s_addr = local; IPCOM_SA_LEN_SET(&tun.local_addr.sin, sizeof(struct Ip_sockaddr_in)); /* Prepare the tunnel for NAT-T */ tun.local_addr.sin.sin_port = local_port; tun.remote_addr.sin.sin_family = IP_AF_INET; tun.remote_addr.sin.sin_addr.s_addr = remote; IPCOM_SA_LEN_SET(&tun.remote_addr.sin, sizeof(struct Ip_sockaddr_in)); tun.ttl = 64; /* Set tunnel interface address */ if (local) { ipcom_memset(&alias, 0, sizeof(alias)); ipcom_strcpy(alias.ifra_name, ifreq.ifr_name); inaddr = (struct Ip_sockaddr_in *)&alias.ifra_addr; inaddr->sin_family = IP_AF_INET; IPCOM_SA_LEN_SET(inaddr, sizeof(struct Ip_sockaddr_in)); inaddr->sin_addr.s_addr = local; inaddr = (struct Ip_sockaddr_in *)&alias.ifra_mask; inaddr->sin_family = IP_AF_INET; IPCOM_SA_LEN_SET(inaddr, sizeof(struct Ip_sockaddr_in)); inaddr->sin_addr.s_addr = 0xffffffff; /* Assign the CoA address */ if (ipmip_netlink_inX_addr(&ctx->ipmip, proc, IP_AF_INET, IP_RTM_NEWADDR, iff->ipmip.ifindex, &local, 32, 0, 0) < 0) { IPMIP4_EVENT_IF(ERR, proc, ipmip_log_event_add(&ctx->ipmip, proc, "Unable to assign address to tunnel interface %s", iff->ipmip.ifname)); goto destroy; } } /**/ flags = IP_IFF_UP; if (tunnel_type == IPMIP_TUNNELTYPE_MINENC) IP_BIT_SET(flags, IP_IFF_LINK0); if (tunnel_type == IPMIP_TUNNELTYPE_GRE && reorder) IP_BIT_SET(flags, IP_IFF_LINK1); if (ipmip_if_set_flags(&ctx->ipmip, proc, &iff->ipmip, flags) < 0) { IPCOM_LOG3(ERR, "ipcom_socketioctl(%s, IP_SIOCSIFFLAGS) failed: %s [%d]", iff->ipmip.ifname, ipcom_strerror(ipcom_errno), ipcom_errno); goto destroy; } /* Set endpoints; will update minenc if set as well. */ if (ipmip_util_ioctl(&ctx->ipmip, proc, IP_SIOCCHGTUNNEL, &tun) < 0) { IPCOM_LOG3(ERR, "ipcom_socketioctl(%s, IP_SIOCCHGTUNNEL) failed: %s [%d]", iff->ipmip.ifname, ipcom_strerror(ipcom_errno), ipcom_errno); goto destroy; } return iff; destroy: ipmip_if_free(&ctx->ipmip, proc, &iff->ipmip); return IP_NULL; } /* *=========================================================================== * ipmip4_if_get_primary_address *=========================================================================== * Description: Get the current primary address of the interface. * Parameters: iff - Interface * Returns: address on success; IP_INADDR_NONE on failure. * */ IP_GLOBAL Ip_u32 ipmip4_if_get_primary_address(Ipmip4_context_t *ctx, Ipmip_proc_t *proc, Ipmip4_if_t *iff) { Ipmip_buffer_t reply; int ret; Ip_u32 addr = IP_INADDR_NONE; ipmip_buffer_init(&reply); if ((ret = ipmip_netlink_inX_addr_dump(&ctx->ipmip, proc, IP_AF_INET, &reply)) < 0) { IPMIP4_EVENT_IF(ERR, proc, ipmip_log_event_add(&ctx->ipmip, proc, "Unable to dump INET addresses error value %d", -ret)); } else { struct Ip_nlmsghdr *nlh = IPMIP_BUFFER_PTR(&reply); Ip_size_t nlh_size = IPMIP_BUFFER_SIZE(&reply); /* */ while (IP_NLMSG_OK(nlh, nlh_size)) { /**/ if (nlh->nlmsg_type == IP_RTM_NEWADDR) { struct Ip_ifaddrmsg *ifa = IP_NLMSG_DATA(nlh); struct Ip_rtattr *ifap[IP_IFA_MAX + 1]; /* Resolve this entry; I want the prefix length and the address */ if (ifa->ifa_index == (Ip_s32)iff->ipmip.ifindex) { /* Parse */ ipmip_netlink_nlmsghdr_rta_parse(IP_IFA_MAX + 1, IP_IFA_RTA(ifa), IP_IFA_PAYLOAD(nlh), ifap); /* Found one */ if (ifap[IP_IFA_LOCAL]) { if (ifa->ifa_family == IP_AF_INET) { addr = IP_GET_32ON8(IP_RTA_DATA(ifap[IP_IFA_LOCAL])); break; } } } } /**/ nlh = IP_NLMSG_NEXT(nlh, nlh_size); } } /**/ ipmip_buffer_release(&reply); return addr; } /* *=========================================================================== * ipmip4_if_findbyaddr *=========================================================================== * Description: Locate an interface in our configuration based on address. * Parameters: iflist - The list of interfaces. * addr - The interface address * Returns: The interface pointer if it exists, IP_NULL otherwise. */ IP_GLOBAL Ipmip4_if_t * ipmip4_if_findbyaddr(Ipcom_list *iflist, Ip_u32 addr) { Ipmip4_if_t *iff; for (iff = IPCOM_LIST_FIRST(iflist); iff; iff = IPCOM_LIST_NEXT(&iff->ipmip.next)) { if (iff->ifaddr == addr) return iff; } return IP_NULL; } /* *=========================================================================== * ipmip4_if_findbypktinfo *=========================================================================== * Description: Locate an interface in our configuration based on address. * Parameters: iflist - The list of interfaces * pktinfo - The interface info * Returns: The interface pointer if it exists, IP_NULL otherwise. */ IP_GLOBAL Ipmip4_if_t * ipmip4_if_findbypktinfo(Ipcom_list *iflist, Ipmip_pktbuf_pktinfo_t *pktinfo) { Ipmip4_if_t *iff; if ((iff = ipmip4_if_findbyaddr(iflist, pktinfo->dst.sin.sin_addr.s_addr)) == IP_NULL) iff = (Ipmip4_if_t *)ipmip_if_findbyindex(iflist, pktinfo->ifindex); return iff; } /* **************************************************************************** * 11 PUBLIC FUNCTIONS **************************************************************************** */ /* **************************************************************************** * END OF FILE **************************************************************************** */