/* ****************************************************************************** * SOURCE FILE * * Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ * $Source: /home/interpeak/CVSRoot/ipcom/src/ipcom_waitif.c,v $ * $Author: hxie $ * $State: Exp $ $Locker: $ * * INTERPEAK_COPYRIGHT_STRING ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** * ipcom_waitif.c contains an example of how to wait for an interface to * acquire an IP address, e.g. when DHCP is used. * */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #include "ipcom_config.h" #define IPCOM_SYSLOG_FACILITY IPCOM_LOG_IPCOM #ifdef IP_DEBUG #define IPCOM_SYSLOG_PRIORITY IPCOM_LOG_DEBUG #else #define IPCOM_SYSLOG_PRIORITY IPCOM_LOG_WARNING #endif /* **************************************************************************** * 3 INCLUDE FILES **************************************************************************** */ #define IPCOM_USE_CLIB_PROTO #include #include #include #include #include #ifdef IPNET #include #include /* **************************************************************************** * 5 DEFINES **************************************************************************** */ /* Max # of interfaces to poll */ #define IPNET_WAITIF_MAXIF 16 /* Max timeout to wait for an address */ #define IPNET_WAITIF_TIMEOUT 60 /* **************************************************************************** * 9 FUNCTIONS **************************************************************************** */ /* *=========================================================================== * ipcom_waitif_gifaddr *=========================================================================== * Description: Get interface address. * Parameters: fd - socket descriptor * ifindex - Interface index. * domain - The address domain. * Returns: 0 = No address available, 1 = No address available, -1 = error. * */ IP_STATIC int ipcom_waitif_gifaddr(Ip_fd fd, int ifindex, int domain) { int ret = -1; switch (domain) { case IP_AF_INET: { struct Ip_ifreq ifreq; /* Get if name */ ipcom_memset(&ifreq, 0, sizeof(ifreq)); (void)ipcom_if_indextoname(ifindex, ifreq.ifr_name); /* Get main address */ if (ipcom_socketioctl(fd, IP_SIOCGIFADDR, &ifreq) < 0) { if (ipcom_errno != IP_ERRNO_EADDRNOTAVAIL && ipcom_errno != IP_ERRNO_ENXIO) { IPCOM_LOG1(ERR, "ipcom_waitif :: ipcom_socketioctl(SIOCGIFADDR) failed, errno = %d", ipcom_errno); } } else { struct Ip_in_addr network = ((struct Ip_sockaddr_in *)&ifreq.ip_ifr_addr)->sin_addr; if (network.s_addr != IP_INADDR_DEFAULT) { ret = 0; } } break; } #ifdef IPCOM_USE_INET6 case IP_AF_INET6: { int len = IPNET_WAITIF_MAXIF * sizeof(struct Ip_ifreq); char ifname[IP_IFNAMSIZ]; struct Ip_ifconf ifc; char *buf = IP_NULL; char *ptr; /* Get if name */ (void)ipcom_if_indextoname(ifindex, ifname); /* Get if data buffer */ if ((buf = ipcom_malloc(IPNET_WAITIF_MAXIF * sizeof(struct Ip_ifreq))) == IP_NULL) { IPCOM_LOG0(ERR, "ipcom_waitif :: Out of memory"); goto leave; } /* Enter buf in ifconf struct */ ifc.ifc_len = len; ifc.ip_ifc_buf = buf; if (ipcom_socketioctl(fd, IP_SIOCGIFCONF, &ifc) < 0) { IPCOM_LOG1(ERR, "ipcom_socketioctl(SIOCGIFCONF) failed, errno = %d\n", ipcom_errno); goto leave; } /* Loop for all interfaces */ for (ptr = buf; ptr < buf + ifc.ifc_len; ) { struct Ip_ifreq *ifr = (struct Ip_ifreq *)ptr; char *cptr; /* Calculate pointer to next if */ len = (int)IP_MAX(sizeof(struct Ip_sockaddr_in), ifr->ip_ifr_addr.sa_len); ptr += sizeof(ifr->ifr_name) + len; if ((cptr = ipcom_strchr(ifr->ifr_name, ':')) != IP_NULL) { *cptr = '\0'; } /* Only for v6 addresses */ if (ipcom_strcmp(ifr->ifr_name, ifname) == 0 && ifr->ip_ifr_addr.sa_family == IP_AF_INET6) { struct Ip_sockaddr_in6 *in6 = (struct Ip_sockaddr_in6 *)&ifr->ip_ifr_addr; if (!IP_IN6_IS_ADDR_UNSPECIFIED(&in6->sin6_addr)) { ret = 0; break; } } } leave: if (buf != IP_NULL) { ipcom_free(buf); } break; } #endif /* IPCOM_USE_INET6 */ } return ret; } /* *=========================================================================== * ipcom_waitif_address *=========================================================================== * Description: check interface enabled dhcp to get an IP address assigned * Parameters: * Returns: 0 = success, -1 = error, and sets errno. * */ IP_PUBLIC int ipcom_waitif_address() { struct Ip_if_nameindex *oifrs, *ifrs; struct Ip_ifreq ifreq; int fd = IP_INVALID_SOCKET; int ret = IPCOM_SUCCESS; fd = ipcom_socket(IP_AF_INET, IP_SOCK_DGRAM, 0); if (fd == IP_INVALID_SOCKET) return IPCOM_ERR_FAILED; /* Search for interfaces preconfigured for dhcp */ ifrs = ipcom_if_nameindex(); if (ifrs == IP_NULL) { ipcom_socketclose(fd); return IPCOM_ERR_FAILED; } for (oifrs = ifrs; ifrs && ifrs->if_name != IP_NULL; ifrs++) { /* Check if interface is up. */ ipcom_strncpy(ifreq.ifr_name, ifrs->if_name, sizeof(ifreq.ifr_name)); ifreq.ifr_name[sizeof(ifreq.ifr_name)-1] = '\0'; if (ipcom_socketioctl(fd, IP_SIOCGIFFLAGS,(char *)&ifreq) < 0) { IPCOM_LOG2(ERR, "ipcom_waitif[%s] :: ipcom_ioctl(SIOCGIFFLAGS) failed, errno =%d", ifrs->if_name, ipcom_errno); continue; } if (IP_BIT_ISFALSE(ifreq.ifr_ifru.ifru_flags, IP_IFF_UP)) continue; /* Check if DHCP is enabled for this interface. */ if (ipcom_socketioctl(fd, IP_SIOCXGDHCPRUNNING,(char *)&ifreq) < 0) { IPCOM_LOG2(ERR, "ipcom_waitif[%s] :: ipcom_ioctl(IP_SIOCXGDHCPRUNNING) failed, errno =%d", ifrs->if_name, ipcom_errno); continue; } if (ifreq.ifr_ifru.ifru_opt == 1) break; /*find the boot interface that enable dhcp flag*/ } if(ifrs&&ifrs->if_name != IP_NULL) ret = ipcom_waitif(ipcom_if_nametoindex(ifrs->if_name),IP_AF_INET); ipcom_if_freenameindex(oifrs); ipcom_socketclose(fd); return ret; } /* *=========================================================================== * ipcom_waitif *=========================================================================== * Description: Wait for interface to get an IP address assigned. * Parameters: ifindex - Index of the interface to wait for. * 0 = any interface except loopback. * domain - The address domain. * Returns: 0 = success, -1 = error, and sets errno. * */ IP_PUBLIC int ipcom_waitif(int ifindex, int domain) { struct Ipnet_rs_msghdr rtmsg; struct Ip_timeval stop; struct Ip_timeval tv; Ip_fd fd = IP_INVALID_SOCKET; int ret = -1; /* Check domain */ if (domain != IP_AF_INET #ifdef IPCOM_USE_INET6 && domain != IP_AF_INET6 #endif /* IPCOM_USE_INET6 */ ) { IPCOM_LOG1(ERR, "ipcom_waitif :: invalid domain: %d", domain); ipcom_errno_set(IP_ERRNO_EINVAL); goto leave; } /* Get routing socket */ fd = ipcom_socket(IP_AF_ROUTE, IP_SOCK_RAW, 0); if (fd == IP_INVALID_SOCKET) { IPCOM_LOG1(ERR, "ipcom_waitif :: ipcom_socket(ROUTE, RAW) failed, errno = %d", ipcom_errno); goto leave; } /* Get stop time */ ipcom_microtime(&tv); stop.tv_sec = tv.tv_sec + IPNET_WAITIF_TIMEOUT; /* Loop and wait for address */ for (;;) { Ip_ssize_t length; /* Check if address available */ if (ifindex == 0) { int i; /* Any if will do */ for (i = 2; i < IPNET_WAITIF_MAXIF; i++) { if (ipcom_waitif_gifaddr(fd, i, domain) == 0) { ret = 0; goto leave; } } } else if (ipcom_waitif_gifaddr(fd, ifindex, domain) == 0) { ret = 0; goto leave; } again: /* Get timeout time */ ipcom_microtime(&tv); tv.tv_sec = stop.tv_sec - tv.tv_sec; tv.tv_usec = 0; if (tv.tv_sec <= 0) { ipcom_errno_set(IP_ERRNO_ETIMEDOUT); goto leave; } /* Set receive timeout */ if (ipcom_setsockopt(fd, IP_SOL_SOCKET, IP_SO_RCVTIMEO, &tv, sizeof(tv)) < 0) { IPCOM_LOG1(ERR, "ipcom_waitif :: ipcom_setsockopt(RCVTIMEO) failed, errno = %d", ipcom_errno); goto leave; } /* Read routing message headers only (truncated read). */ length = ipcom_recv(fd, &rtmsg, sizeof(rtmsg), 0); if (length == IP_SOCKERR) { if (ipcom_errno != IP_ERRNO_ETIMEDOUT && ipcom_errno != IP_ERRNO_EWOULDBLOCK) { IPCOM_LOG1(ERR, "ipcom_waitif :: ipcom_recv() failed, errno = %d", ipcom_errno); } goto leave; } /* Only bother about newaddr */ if (rtmsg.type != IPNET_RTM_NEWADDR) { goto again; } } leave: if (fd != IP_INVALID_SOCKET) { ipcom_socketclose(fd); } return ret; } #else int ipcom_waitif_empty_file; #endif /* **************************************************************************** * END OF FILE **************************************************************************** */