/* wrnad_link.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_link_flagsstr - find rtnetlink link flags in string format * * This routine returns the rtnetlink link flags as a string * * RETURNS: string representation of rtnetlink link flags. * * ERRNO: N/A */ static const char * wrnad_rtnl_link_flagsstr(int flags) { static char flagsstr[256]; int i; flagsstr[0] = '<'; i = 1; if (flags == 0) i += sprintf(&flagsstr[i], "%s", "0,"); if (flags & IFF_UP) i += sprintf(&flagsstr[i], "%s", "UP,"); if (flags & IFF_BROADCAST) i += sprintf(&flagsstr[i], "%s", "BROADCAST,"); if (flags & IFF_DEBUG) i += sprintf(&flagsstr[i], "%s", "DEBUG,"); if (flags & IFF_LOOPBACK) i += sprintf(&flagsstr[i], "%s", "LOOPBACK,"); if (flags & IFF_POINTOPOINT) i += sprintf(&flagsstr[i], "%s", "POINTOPOINT,"); if (flags & IFF_NOTRAILERS) i += sprintf(&flagsstr[i], "%s", "NOTRAILERS,"); if (flags & IFF_RUNNING) i += sprintf(&flagsstr[i], "%s", "RUNNING,"); if (flags & IFF_NOARP) i += sprintf(&flagsstr[i], "%s", "NOARP,"); if (flags & IFF_PROMISC) i += sprintf(&flagsstr[i], "%s", "PROMISC,"); if (flags & IFF_ALLMULTI) i += sprintf(&flagsstr[i], "%s", "ALLMULTI,"); if (flags & IFF_MASTER) i += sprintf(&flagsstr[i], "%s", "MASTER,"); if (flags & IFF_SLAVE) i += sprintf(&flagsstr[i], "%s", "SLAVE,"); if (flags & IFF_MULTICAST) i += sprintf(&flagsstr[i], "%s", "MULTICAST,"); if (flags & IFF_PORTSEL) i += sprintf(&flagsstr[i], "%s", "PORTSEL,"); if (flags & IFF_AUTOMEDIA) i += sprintf(&flagsstr[i], "%s", "AUTOMEDIA,"); if (flags & IFF_DYNAMIC) i += sprintf(&flagsstr[i], "%s", "DYNAMIC,"); flagsstr[i-1] = '>'; /* remove last comma */ return flagsstr; } /******************************************************************************* * * wrnad_rtnl_link_typestr - find rtnetlink link type in string format * * This routine returns the rtnetlink link type as a string * * RETURNS: string representation of rtnetlink link type. * * ERRNO: N/A */ static const char * wrnad_rtnl_link_typestr(int type) { static char typestr[32]; switch (type) { case ARPHRD_ETHER: return "ether"; default: sprintf(typestr, "%d", type); return typestr; } } /******************************************************************************* * * wrnad_rtnl_link_attrstr - find rtnetlink link attribute in string format * * This routine returns the rtnetlink link attribute as a string * * RETURNS: string representation of rtnetlink link attribute. * * ERRNO: N/A */ static const char * wrnad_rtnl_link_attrstr(int attr) { static char attrstr[32]; switch (attr) { case IFLA_UNSPEC: return "IFLA_UNSPEC"; case IFLA_ADDRESS: return "IFLA_ADDRESS"; case IFLA_BROADCAST: return "IFLA_BROADCAST"; case IFLA_IFNAME: return "IFLA_IFNAME"; case IFLA_MTU: return "IFLA_MTU"; case IFLA_LINK: return "IFLA_LINK"; case IFLA_QDISC: return "IFLA_QDISC"; case IFLA_STATS: return "IFLA_STATS"; case IFLA_COST: return "IFLA_COST"; case IFLA_PRIORITY: return "IFLA_PRIORITY"; case IFLA_MASTER: return "IFLA_MASTER"; case IFLA_WIRELESS: return "IFLA_WIRELESS"; case IFLA_PROTINFO: return "IFLA_PROTINFO"; case IFLA_TXQLEN: return "IFLA_TXQLEN"; case IFLA_MAP: return "IFLA_MAP"; case IFLA_WEIGHT: return "IFLA_WEIGHT,"; #ifdef IFLA_OPERSTATE case IFLA_OPERSTATE: return "IFLA_OPERSTATE"; #endif #ifdef IFLA_LINKMODE case IFLA_LINKMODE: return "IFLA_LINKMODE"; #endif #ifdef IFLA_LINKINFO case IFLA_LINKINFO: return "IFLA_LINKINFO"; #endif #if 0 case IFLA_NET_NS_PID: return "IFLA_NET_NS_PID"; case IFLA_IFALIAS: return "IFLA_IFALIAS"; #endif default: sprintf(attrstr, "%d", attr); return attrstr; } } /******************************************************************************* * * wrnad_rtnl_link_statestr - find rtnetlink link operational state in string format * * This routine returns the rtnetlink link operational state as a string * * RETURNS: string representation of rtnetlink link operational state. * * ERRNO: N/A */ static const char * wrnad_rtnl_link_statestr(int state) { static char statestr[32]; switch (state) { #ifdef IF_OPER_UNKNOWN case IF_OPER_UNKNOWN: return "UNKNOWN"; case IF_OPER_NOTPRESENT: return "NOTPRESENT"; case IF_OPER_DOWN: return "DOWN"; case IF_OPER_LOWERLAYERDOWN: return "LOWERLAYERDOWN"; case IF_OPER_TESTING: return "TESTING"; case IF_OPER_DORMANT: return "DORMANT"; case IF_OPER_UP: return "UP"; #endif default: sprintf(statestr, "%x", state); return statestr; } } /******************************************************************************* * * wrnad_rtnl_link_scan - scan rtnetlink socket for link messages * * This routine scans link messages received on a rtnetlink socket * * RETURNS: 0 if exited normally, else -1. * * ERRNO: N/A */ static int wrnad_rtnl_link_scan(struct ifinfomsg *ifi, int len, char *ifname) { struct rtattr *rta; char buf[64]; rta = (struct rtattr *)((char *)ifi + NLMSG_ALIGN(sizeof(struct ifinfomsg))); while (RTA_OK(rta, len)) { wrnad_log(LOG_DEBUG, "Rtnetlink LINK rtattr: rta_len=%d, rta_type=%s.", rta->rta_len, wrnad_rtnl_link_attrstr(rta->rta_type)); if (rta->rta_type == IFLA_IFNAME) { wrnad_log(LOG_DEBUG, "Rtnetlink LINK attribute IFLA_IFNAME: %s", RTA_DATA(rta)); /* Save interface name */ strcpy(ifname, RTA_DATA(rta)); } else if (rta->rta_type == IFLA_ADDRESS && ifi->ifi_type == ARPHRD_ETHER) { wrnad_rtnl_eth_ntop(RTA_DATA(rta), buf); wrnad_log(LOG_DEBUG, "Rtnetlink LINK attribute IFLA_ADDRESS: %s", buf); } else if (rta->rta_type == IFLA_BROADCAST && ifi->ifi_type == ARPHRD_ETHER) { wrnad_rtnl_eth_ntop(RTA_DATA(rta), buf); wrnad_log(LOG_DEBUG, "Rtnetlink LINK attribute IFLA_BROADCAST: %s", buf); } else if (rta->rta_type == IFLA_MTU) { wrnad_log(LOG_DEBUG, "Rtnetlink LINK attribute IFLA_MTU: %d", *(int *)RTA_DATA(rta)); } #ifdef IFLA_OPERSTATE else if (rta->rta_type == IFLA_OPERSTATE) { wrnad_log(LOG_DEBUG, "Rtnetlink LINK attribute IFLA_OPERSTATE: %s", wrnad_rtnl_link_statestr(*(int *)RTA_DATA(rta))); } #endif rta = RTA_NEXT(rta, len); } if (len) { wrnad_log(LOG_WARNING, "Rtnetlink LINK attribute malformed! len=%d rta_len=%d", len, rta->rta_len); return -1; } wrnad_log(LOG_DEBUG, "Rtnetlink LINK message scanned ok."); return 0; } /******************************************************************************* * * wrnad_rtnl_link_handler - rtnetlink handler for link messages * * This routine handles rtnetlink link messages. * * RETURNS: -1 = failed * 0 = skip * 1 = action * * ERRNO: N/A */ int wrnad_rtnl_link_handler(struct nlmsghdr *nlh) { struct ifinfomsg *ifi; int ret, len; char ifname[IFNAMSIZ]; ifi = NLMSG_DATA(nlh); len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifinfomsg)); 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 LINK operation header: family=%s, type=%s, index=%d, flags=%s, change=%d.", wrnad_rtnl_familystr(ifi->ifi_family), wrnad_rtnl_link_typestr(ifi->ifi_type), ifi->ifi_index, wrnad_rtnl_link_flagsstr(ifi->ifi_flags), ifi->ifi_change); ifname[0] = '\0'; ret = wrnad_rtnl_link_scan(ifi, len, ifname); if (ret == 0) { #ifdef IPWRNAD /* Skip dev name check. Otherwise the bond device events will not be propagated */ if (strncmp(ifname, WRNAD_PROXY_IFNAME, strlen(WRNAD_PROXY_IFNAME)) == 0) #endif { if (ifi->ifi_index < WRNAD_MAX_IF) { if (nlh->nlmsg_type == RTM_NEWLINK) wrnad_rtnl_add_proxy_interface(ifi->ifi_index, ifname); else if (nlh->nlmsg_type == RTM_DELLINK) wrnad_rtnl_del_proxy_interface(ifi->ifi_index, ifname); } else { wrnad_log(LOG_INFO, "Proxy interface index to big: %d", ifi->ifi_index); } /* Accept message */ wrnad_log(LOG_INFO, "Rtnetlink message type %s accepted on interface %s", wrnad_rtnl_typestr(nlh->nlmsg_type), ifname); ifi->ifi_family = wrnad_af_xlat(ifi->ifi_family); /* Change into request */ nlh->nlmsg_flags = NLM_F_REQUEST; return 1; } #ifdef IPWRNAD /* Skip dev name check. Otherwise the bond device events will not be propagated */ else { wrnad_log(LOG_DEBUG, "Rtnetlink message type %s skipped on interface %d", wrnad_rtnl_typestr(nlh->nlmsg_type), ifi->ifi_index); } #endif } return ret; }