/* ****************************************************************************** * INTERPEAK SOURCE FILE * * Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipnet_ppp.c,v $ $Revision: 1.118.10.2 $ * $Source: /home/interpeak/CVSRoot/ipnet2/src/ipnet_ppp.c,v $ * $Author: qsun $ * $State: Exp $ $Locker: $ * * INTERPEAK_COPYRIGHT_STRING * Design and implementation by Lennart Bang ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #ifndef IPCOM_KERNEL #define IPCOM_KERNEL #endif #include "ipnet_config.h" /* **************************************************************************** * 3 INCLUDE FILES **************************************************************************** */ #ifdef IPPPP #define IPCOM_USE_CLIB_PROTO #include #include #include #include #include #include "ipnet_h.h" #include "ipnet_netif.h" #include "ipnet_pkt_queue.h" /* **************************************************************************** * 4 DEFINES **************************************************************************** */ /* Number of bits in the host part (EUI-64) when using the * PPP to create a IPv6 address (RFC 2464?) */ #define IPPPP_IP6_ID_BITS 64 /* **************************************************************************** * 5 TYPES **************************************************************************** */ /* **************************************************************************** * 6 EXTERN PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 7 LOCAL PROTOTYPES **************************************************************************** */ IP_STATIC int ipnet_ppp_input(struct Ipnet_netif_struct *netif, Ipcom_pkt *pkt); IP_STATIC int ipnet_ppp_ioctl(struct Ipnet_netif_struct *netif, Ip_u32 command, void *data); IP_STATIC int ipnet_ppp_ioevent(Ipcom_netif *netif, int command, void *data, int fcflags); IP_PUBLIC int ipppp_if_init2(void *voidif); /* **************************************************************************** * 8 DATA **************************************************************************** */ Ipcom_once_t ipnet_ppp_ioevent_once = IPCOM_ONCE_INIT; /* **************************************************************************** * 9 STATIC FUNCTIONS **************************************************************************** */ /* *=========================================================================== * ipnet_ppp_input *=========================================================================== * Description: Input handler for ethernet frames. pkt->start is the offset * to the ethernet header. * Parameters: pkt - The ethernet frame. * Returns: 0 = success, <0 error code * */ IP_STATIC int ipnet_ppp_input(struct Ipnet_netif_struct *netif, Ipcom_pkt *pkt) { int vr; int ret; ip_assert(ipnet_is_stack_task()); vr = ipcom_proc_vr_get(); /* Set virtual router index */ if (vr != netif->vr_index) ipcom_proc_vr_set(netif->vr_index); ret = ipppp_input(&netif->ipcom, pkt); /* Restore virtual router index */ if (vr != netif->vr_index) ipcom_proc_vr_set(vr); return ret; } /* *=========================================================================== * ipnet_ppp_ioctl *=========================================================================== * Description: PPP IO control. * Parameters: netif - The interface on which the multicast address will * be used. * command - ioctl command. * data - Depends on command. * Returns: 0 = success, < 0 = error code * */ IP_STATIC int ipnet_ppp_ioctl(struct Ipnet_netif_struct *netif, Ip_u32 command, void *data) { int vr; int ret; ip_assert(ipnet_is_stack_task()); vr = ipcom_proc_vr_get(); /* Set virtual router index */ if (vr != netif->vr_index) ipcom_proc_vr_set(netif->vr_index); ret = ipppp_ioctl(&netif->ipcom, command, data); /* Restore virtual router index */ if (vr != netif->vr_index) ipcom_proc_vr_set(vr); return ret; } IP_STATIC int ipnet_ppp_tx(Ipnet_neigh *neigh, Ipcom_pkt *pkt) { ip_assert(ipnet_is_stack_task()); switch (neigh->domain) { #ifdef IPCOM_USE_INET case IP_AF_INET: return ipppp_ip4_output(&neigh->netif->ipcom, pkt); #endif #ifdef IPCOM_USE_INET6 case IP_AF_INET6: return ipppp_ip6_output(&neigh->netif->ipcom, pkt); #endif } return -IP_ERRNO_EINVAL; } #ifdef IPCOM_USE_INET6 /* *=========================================================================== * ipnet_ppp_ip6_create_addr *=========================================================================== * Description: Creates an unique address based on the passed prefix. * Parameters: netif - The interface to which this address will be bound. * prefix - The network identifier part of the address. * in6_addr - Will hold a unique address if the function is * successful. * Returns: 0 = succeess. <0 = error code. * */ IP_STATIC int ipnet_ppp_ip6_create_addr(Ipnet_netif *netif, IP_CONST struct Ip_in6_addr *prefix, struct Ip_in6_addr *in6_addr) { struct Ip_in6_addr mask; struct Ip_in6_addr host_id; unsigned i; /* Create the EUI-64 ideaantifier for the PPP interface */ ip_assert(ipnet_is_stack_task()); if (netif->inet6_addr_list != IP_NULL && IP_IN6_IS_ADDR_MULTICAST(netif->inet6_addr_list) == IP_FALSE) /* Host ID already generated, reuse that host ID */ IPNET_IP6_SET_ADDR(&host_id, &netif->inet6_addr_list->addr); else { /* Generate a random host ID */ long pid_tick; pid_tick = (long)ipcom_getpid() + (long)ipcom_time(IP_NULL); /* Let's create a random number */ host_id.in6.addr32[0] = (Ip_u32) (ipcom_random() + pid_tick); host_id.in6.addr32[1] = (Ip_u32) (ipcom_random() + pid_tick); host_id.in6.addr32[2] = (Ip_u32) (ipcom_random() + pid_tick); host_id.in6.addr32[3] = (Ip_u32) (ipcom_random() + pid_tick); /* The universal/local bit must be 0 in this case */ IP_BIT_CLR(in6_addr->in6.addr16[4], IP_SWAP16(0x0200)); } /* Create an inverted mask */ ipcom_memset(&mask, 0, sizeof(mask)); ipnet_route_create_mask(&mask, netif->inet6_if_id_bits); mask.in6.addr32[0] = ~mask.in6.addr32[0]; mask.in6.addr32[1] = ~mask.in6.addr32[1]; mask.in6.addr32[2] = ~mask.in6.addr32[2]; mask.in6.addr32[3] = ~mask.in6.addr32[3]; ipnet_route_apply_mask(&host_id, &mask, netif->inet6_if_id_bits); IPNET_IP6_SET_ADDR(in6_addr, prefix); for (i = 0; i < sizeof(host_id) / sizeof(host_id.in6.addr16[0]); i++) in6_addr->in6.addr16[i] |= host_id.in6.addr16[i]; return 0; } #endif /* IPCOM_USE_INET6 */ /* *=========================================================================== * ipnet_ppp_ioevent *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC int ipnet_ppp_ioevent(Ipcom_netif *netif, int command, void *data, int fcflags) { int retval = 0; IPCOM_UNUSED_ARG(fcflags); if (ipnet_is_stack_task()) retval = ipppp_ioevent(netif, command, data); else { } return retval; } /* *=========================================================================== * ipnet_ppp_ioevent_init *=========================================================================== * Description: Creates the ppp code mutex. * Parameters: * Returns: * */ IP_STATIC Ip_err ipnet_ppp_ioevent_init(Ipcom_mutex *ppp_code_mutex) { return ipcom_mutex_create(ppp_code_mutex); } /* **************************************************************************** * 10 GLOBAL FUNCTIONS **************************************************************************** */ /* **************************************************************************** * 11 PUBLIC FUNCTIONS **************************************************************************** */ /* *=========================================================================== * ipppp_if_init2 *=========================================================================== * Description: * Parameters: * Returns: * */ IP_PUBLIC int ipppp_if_init2(void *voidif) { Ipnet_netif *netif = voidif; int ret; Ip_bool is_stack_task = ipnet_is_stack_task(); if (!is_stack_task) ipcom_ppp_ioevent(voidif, IPPPP_EIOXCODE_LOCK, IP_NULL); /* Setup link functions for PPP use. */ netif->link_input = ipnet_ppp_input; netif->link_ioctl = ipnet_ppp_ioctl; netif->ipcom.link_ioevent = ipnet_ppp_ioevent; netif->link_output = ipnet_ppp_tx; #ifdef IPCOM_USE_INET6 netif->inet6_if_id_bits = IPPPP_IP6_ID_BITS; netif->link_ip6_create_addr = ipnet_ppp_ip6_create_addr; #endif ret = ipppp_if_init(&netif->ipcom); if (!is_stack_task) ipcom_ppp_ioevent(voidif, IPPPP_EIOXCODE_UNLOCK, IP_NULL); return ret; } /* *=========================================================================== * ipcom_ppp_ioevent *=========================================================================== * Description: * Parameters: * Returns: * */ IP_PUBLIC long ipcom_ppp_ioevent(Ipcom_netif *netif, int command, void *data) { struct Ipnet_route_add_param param; struct Ipnet_rt_metrics metrics; Ip_u32 netmask_n; Ipnet_netif *ipnet_netif = (Ipnet_netif *)netif; long ret = 0; static Ipcom_mutex ppp_code_mutex = IPCOM_MUTEX_INVALID; static void *suspend_handle = IP_NULL; switch(command) { case IPPPP_EIOXBLOCKOK: if (ipnet_is_stack_task() == IP_FALSE) ret = 1; /* user process -> block is ok. */ break; case IPPPP_EIOXDRVIOCTL: { Ipppp_eio_ioctl *eio_ioctl = data; ip_assert(netif); ip_assert(ipnet_is_stack_task()); ret = netif->drv_ioctl(netif, eio_ioctl->command, eio_ioctl->data); break; } case IPPPP_EIOXOUTPUT_IF: ip_assert(ipnet_netif); ip_assert(ipnet_is_stack_task()); ret = ipnet_if_output(ipnet_netif, data); break; case IPPPP_EIOXINDEXTONETIF: { Ipnet_netif *ptr; unsigned long dataul = (unsigned long)data; ip_assert(ipnet_is_stack_task()); ptr = ipnet_if_indextonetif(IPCOM_VR_ANY, (Ip_u32)dataul); return (long)ptr; } case IPPPP_EIOXCODE_LOCK: if (ipcom_once(&ipnet_ppp_ioevent_once, (Ip_err(*)(void*)) ipnet_ppp_ioevent_init, (void *) &ppp_code_mutex) != IPCOM_SUCCESS) { IP_PANIC(); return -1; } (void)ipcom_mutex_lock(ppp_code_mutex); suspend_handle = ipnet_suspend_stack(); break; case IPPPP_EIOXCODE_UNLOCK: ipnet_resume_stack(suspend_handle); (void)ipcom_mutex_unlock(ppp_code_mutex); break; case IPPPP_EIOXIF_LOCK: ip_assert(netif); ip_assert(ipnet_is_stack_task()); IPNET_IF_LOCK(ipnet_netif); break; case IPPPP_EIOXIF_UNLOCK: ip_assert(netif); ip_assert(ipnet_is_stack_task()); IPNET_IF_UNLOCK(ipnet_netif); break; #ifdef IPCOM_USE_INET case IPPPP_EIOXINPUT_IN: ip_assert(ipnet_netif); ip_assert(ipnet_is_stack_task()); ret = ipnet_ip4_input(ipnet_netif, data); break; case IPPPP_EIOXUP_IN: { Ipppp_eio_in *eio_in = data; ip_assert(netif); ip_assert(ipnet_is_stack_task()); /* Add local IPv4 address to this interface. */ ip_assert(ipnet_netif->inet4_addr_list == IP_NULL || ipnet_netif->inet4_addr_list->type != IPNET_ADDR_TYPE_UNICAST); netmask_n = 0xffffffff; ret = ipnet_ip4_add_addr(ipnet_netif, eio_in->local_addr_n, netmask_n, IP_TRUE, IPNET_ADDR_TYPE_UNICAST); if (ret < 0) { IP_PANIC2(); return ret; } /* Add a host route to the peer. */ ipcom_memset(¶m, 0, sizeof(struct Ipnet_route_add_param)); ipcom_memset(&metrics, 0, sizeof(struct Ipnet_rt_metrics)); param.domain = IP_AF_INET; param.vr = ipnet_netif->vr_index; param.table = IPCOM_ROUTE_TABLE_DEFAULT; param.netif = ipnet_netif; param.key = &eio_in->peer_addr_n; param.flags = IPNET_RTF_UP | IPNET_RTF_HOST | IPNET_RTF_DONE; if (ipppp_sysvar_get_conf_string(netif, IP_NULL, "ipppp.flags", "proxyarp")) IP_BIT_SET(param.flags, IPNET_RTF_PROTO2); param.metrics = &metrics; metrics.rmx_hopcount = netif->metric; metrics.rmx_expire = IPCOM_ADDR_INFINITE; ret = ipnet_route_add(¶m); if (ret < 0) { IP_PANIC2(); return ret; } /* Add/Change default gateway to peer. */ if (ipppp_sysvar_get_conf_string(netif, IP_NULL, "ipppp.flags", "defaultroute")) { struct Ip_sockaddr_in gw; Ip_u32 inaddr_any = 0; (void)ipnet_route_delete(IP_AF_INET, ipnet_netif->vr_index, &inaddr_any); ipcom_memset(&gw, 0, sizeof(struct Ip_sockaddr_in)); gw.sin_family = IP_AF_INET; IPCOM_SA_LEN_SET(&gw, sizeof(struct Ip_sockaddr_in)); gw.sin_addr.s_addr = eio_in->peer_addr_n; param.flags = IPNET_RTF_UP | IPNET_RTF_GATEWAY | IPNET_RTF_DONE; param.gateway = (struct Ip_sockaddr *)&gw; param.key = &inaddr_any; param.netmask = &inaddr_any; ret = ipnet_route_add(¶m); if (ret < 0) { IP_PANIC2(); return ret; } } } break; case IPPPP_EIOXDOWN_IN: ip_assert(ipnet_netif); ip_assert(ipnet_is_stack_task()); ipnet_if_clean(ipnet_netif, IP_TRUE, IP_FALSE); break; case IPPPP_EIOXDSTADDR_IN: { struct Ip_ifreq ifreq; struct Ip_sockaddr_in *inaddr = (struct Ip_sockaddr_in *)&ifreq.ip_ifr_addr; Ip_u32 dstaddr = ((struct Ip_in_addr *)data)->s_addr; Ipnet_netif *tmpif; unsigned i; ip_assert(ipnet_is_stack_task()); dstaddr = ip_htonl(dstaddr); /* * IPNET_NETIF_FOR_EACH sets netif to NULL after the for loop, * this is a performance optimized defination */ /* coverity[result_independent_of_operands] */ IPNET_NETIF_FOR_EACH(tmpif, i) { if (IP_BIT_ISFALSE(tmpif->ipcom.flags, IP_IFF_POINTOPOINT)) continue; (void)ipnet_if_link_ioctl(tmpif, IP_SIOCGIFDSTADDR, &ifreq); if (inaddr->sin_addr.s_addr == dstaddr) return 1; } } return 0; #endif /* ifdef IPCOM_USE_INET */ #ifdef IPCOM_USE_INET6 case IPPPP_EIOXINPUT_IN6: ip_assert(ipnet_netif); ip_assert(ipnet_is_stack_task()); ret = ipnet_ip6_input(ipnet_netif, data); break; case IPPPP_EIOXUP_IN6: { struct Ipnet_ipv6_key rt6[2]; Ipppp_eio_in6 *eio_in6 = data; ip_assert(netif); ip_assert(ipnet_is_stack_task()); /* Add IPv6 address. */ ret = ipnet_ip6_add_addr(ipnet_netif, &eio_in6->local_addr, 0, IPCOM_ADDR_INFINITE, IPCOM_ADDR_INFINITE, 128); if (ret < 0) return ret; /* Add cloning route for link local net. */ ipcom_memset(¶m, 0, sizeof(struct Ipnet_route_add_param)); ipcom_memset(&metrics, 0, sizeof(struct Ipnet_rt_metrics)); ipcom_memset(rt6, 0, sizeof(struct Ipnet_ipv6_key) * 2); rt6[0].scope_id = netif->ifindex; rt6[0].addr.in6.addr8[0] = 0xfe; rt6[0].addr.in6.addr8[1] = 0x80; rt6[1].scope_id = 0xffffffff; rt6[1].addr.in6.addr32[0] = 0xffffffff; rt6[1].addr.in6.addr32[1] = 0xffffffff; param.domain = IP_AF_INET6; param.vr = ipnet_netif->vr_index; param.table = IPCOM_ROUTE_TABLE_DEFAULT; param.netif = ipnet_netif; param.key = &rt6[0]; param.netmask = &rt6[1]; param.flags = IPNET_RTF_UP | IPNET_RTF_MASK | IPNET_RTF_CLONING | IPNET_RTF_DONE; param.metrics = &metrics; metrics.rmx_hopcount = netif->metric; metrics.rmx_expire = IPCOM_ADDR_INFINITE; ret = ipnet_route_add(¶m); if (ret < 0) { IP_PANIC2(); return ret; } /* Add link local multicast route. */ rt6[0].addr.in6.addr8[0] = 0xff; rt6[0].addr.in6.addr8[1] = 0x02; param.flags = IPNET_RTF_UP | IPNET_RTF_MASK | IPNET_RTF_DONE; ret = ipnet_route_add(¶m); if (ret < 0) { IP_PANIC2(); return ret; } /* Add IPv6 host route to peer. */ ipcom_memcpy(&rt6[0].addr, &eio_in6->peer_addr, sizeof(struct Ip_in6_addr)); param.netmask = IP_NULL; param.flags = IPNET_RTF_UP | IPNET_RTF_HOST | IPNET_RTF_DONE; ret = ipnet_route_add(¶m); if (ret < 0) { IP_PANIC2(); return ret; } } break; case IPPPP_EIOXDOWN_IN6: ip_assert(ipnet_netif); ip_assert(ipnet_is_stack_task()); ipnet_if_clean(ipnet_netif, IP_FALSE, IP_TRUE); break; #endif /* ifdef IPCOM_USE_INET6 */ default: ip_assert(ipnet_netif); ip_assert(ipnet_is_stack_task()); ipnet_kioevent(ipnet_netif, command, data, 0); break; } return ret; } #endif /* IPPPP */ /* **************************************************************************** * END OF FILE **************************************************************************** */