/* wrnad_addr.c - Wind River network acceleration daemon (NAD) */ /* * Copyright (c) 2010 Wind River Systems, Inc. * * The right to copy, distribute or otherwise make use of this software * may be licensed only pursuant to the terms of an applicable Wind River * license agreement. */ /* includes */ #include #include #include #include #include #include "wrnad.h" /* defines */ /* typedefs */ /* imports */ /* globals */ /* locals */ /******************************************************************************* * * wrnad_rtnl_addr_flagsstr - find rtnetlink addr flags in string format * * This routine returns the rtnetlink addr flags as a string * * RETURNS: string representation of rtnetlink addr flags. * * ERRNO: N/A */ static const char * wrnad_rtnl_addr_flagsstr(int flags) { static char flagsstr[256]; int i; flagsstr[0] = '<'; i = 1; if (flags == 0) i += sprintf(&flagsstr[i], "%s", "0,"); if (flags & IFA_F_SECONDARY) i += sprintf(&flagsstr[i], "%s", "SECONDARY,"); #ifdef IFA_F_NODAD if (flags & IFA_F_NODAD) i += sprintf(&flagsstr[i], "%s", "NODAD,"); #endif #ifdef IFA_F_OPTIMISTIC if (flags & IFA_F_OPTIMISTIC) i += sprintf(&flagsstr[i], "%s", "OPTIMISTIC,"); #endif #ifdef IFA_F_HOMEADDRESS if (flags & IFA_F_HOMEADDRESS) i += sprintf(&flagsstr[i], "%s", "HOMEADDRESS,"); #endif if (flags & IFA_F_DEPRECATED) i += sprintf(&flagsstr[i], "%s", "DEPRECATED,"); if (flags & IFA_F_TENTATIVE) i += sprintf(&flagsstr[i], "%s", "TENTATIVE,"); if (flags & IFA_F_PERMANENT) i += sprintf(&flagsstr[i], "%s", "PERMANENT,"); flagsstr[i-1] = '>'; /* remove last comma */ return flagsstr; } /******************************************************************************* * * wrnad_rtnl_addr_attrstr - find rtnetlink addr attribute in string format * * This routine returns the rtnetlink addr attribute as a string * * RETURNS: string representation of rtnetlink addr attribute. * * ERRNO: N/A */ static const char * wrnad_rtnl_addr_attrstr(int attr) { static char attrstr[32]; switch (attr) { case IFA_UNSPEC: return "IFA_UNSPEC"; case IFA_ADDRESS: return "IFA_ADDRESS"; case IFA_LOCAL: return "IFA_LOCAL"; case IFA_LABEL: return "IFA_LABEL"; case IFA_BROADCAST: return "IFA_BROADCAST"; case IFA_ANYCAST: return "IFA_ANYCAST"; case IFA_CACHEINFO: return "IFA_CACHEINFO"; case IFA_MULTICAST: return "IFA_MULTICAST"; default: sprintf(attrstr, "%d", attr); return attrstr; } } /******************************************************************************* * * wrnad_rtnl_addr_scan - scan rtnetlink socket for addr messages * * This routine scans addr messages received on a rtnetlink socket * * RETURNS: 0 if exited normally, else -1. * * ERRNO: N/A */ static int wrnad_rtnl_addr_scan(struct ifaddrmsg *ifa, int len) { struct rtattr *rta; char buf[64]; rta = (struct rtattr *)((char *)ifa + NLMSG_ALIGN(sizeof(struct ifaddrmsg))); while (RTA_OK(rta, len)) { wrnad_log(LOG_DEBUG, "Rtnetlink ADDR rtattr: rta_len=%d, rta_type=%s.", rta->rta_len, wrnad_rtnl_addr_attrstr(rta->rta_type)); if (rta->rta_type == IFA_ADDRESS) { if (inet_ntop(ifa->ifa_family, RTA_DATA(rta), buf, sizeof(buf)) != NULL) { wrnad_log(LOG_DEBUG, "Rtnetlink ADDR attribute IFA_ADDR: %s", buf); } } else if (rta->rta_type == IFA_LOCAL) { if (inet_ntop(ifa->ifa_family, RTA_DATA(rta), buf, sizeof(buf)) != NULL) { wrnad_log(LOG_DEBUG, "Rtnetlink ADDR attribute IFA_LOCAL: %s", buf); } } else if (rta->rta_type == IFA_LABEL) { wrnad_log(LOG_DEBUG, "Rtnetlink ADDR attribute IFA_LABEL: %s", (char *)RTA_DATA(rta)); } rta = RTA_NEXT(rta, len); } if (len) { wrnad_log(LOG_WARNING, "Rtnetlink ADDR attribute malformed! len=%d rta_len=%d", len, rta->rta_len); return -1; } wrnad_log(LOG_DEBUG, "Rtnetlink ADDR message scanned ok."); return 0; } /******************************************************************************* * * wrnad_rtnl_addr_handler - rtnetlink handler for addr messages * * This routine handles rtnetlink addr messages. * * RETURNS: -1 = failed * 0 = skip * 1 = action * * ERRNO: N/A */ int wrnad_rtnl_addr_handler(struct nlmsghdr *nlh) { struct ifaddrmsg *ifa; int len, ret; Wrnad_proxy_interface *proxy; ifa = NLMSG_DATA(nlh); len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifaddrmsg)); if (len < 0) { wrnad_log(LOG_WARNING, "Rtnetlink message type %s has wrong nlmsg length %d!", wrnad_rtnl_typestr(nlh->nlmsg_type), nlh->nlmsg_len); return -1; } wrnad_log(LOG_DEBUG, "Rtnetlink ADDR operation header: family=%s, prefixlen=%d, flags=%s, scope=%d, index=%d.", wrnad_rtnl_familystr(ifa->ifa_family), ifa->ifa_prefixlen, wrnad_rtnl_addr_flagsstr(ifa->ifa_flags), ifa->ifa_scope, ifa->ifa_index); ret = wrnad_rtnl_addr_scan(ifa, len); if (ret == 0) { proxy = wrnad_rtnl_check_proxy_interface(ifa->ifa_index); if (proxy == NULL) { wrnad_log(LOG_DEBUG, "Rtnetlink message type %s skipped on interface %d", wrnad_rtnl_typestr(nlh->nlmsg_type), ifa->ifa_index); return 0; } /* Accept message */ wrnad_log(LOG_INFO, "Rtnetlink message type %s accepted on interface %s", wrnad_rtnl_typestr(nlh->nlmsg_type), proxy->ifname); /* AF_INET6 has a different value in VxWorks */ ifa->ifa_family = wrnad_af_xlat(ifa->ifa_family); /* Change into request */ nlh->nlmsg_flags = NLM_F_REQUEST; if (nlh->nlmsg_type == RTM_NEWADDR) nlh->nlmsg_flags |= NLM_F_CREATE; return 1; } return ret; }