diff --git a/main/utils.c b/main/utils.c index fc7aa30d7e..fd1edf4902 100644 --- a/main/utils.c +++ b/main/utils.c @@ -2508,72 +2508,226 @@ char *ast_eid_to_str(char *s, int maxlen, struct ast_eid *eid) return os; } +#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__Darwin__) +#include +#include + void ast_set_default_eid(struct ast_eid *eid) { -#if defined(SIOCGIFHWADDR) && defined(HAVE_STRUCT_IFREQ_IFR_IFRU_IFRU_HWADDR) - int s, x = 0; + struct ifaddrs *ifap, *ifaphead; + int rtnerr; + const struct sockaddr_dl *sdl; + int alen; + caddr_t ap; char eid_str[20]; - struct ifreq ifr; - static const unsigned int MAXIF = 10; + unsigned char empty_mac[6] = {0, 0, 0, 0, 0, 0}; + unsigned char full_mac[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; - s = socket(AF_INET, SOCK_STREAM, 0); - if (s < 0) { + rtnerr = getifaddrs(&ifaphead); + if (rtnerr) { + ast_log(LOG_WARNING, "No ethernet interface found for seeding global EID. " + "You will have to set it manually.\n"); return; } - for (x = 0; x < MAXIF; x++) { - static const char *prefixes[] = { "eth", "em", "eno", "ens" }; - unsigned int i; - for (i = 0; i < ARRAY_LEN(prefixes); i++) { - memset(&ifr, 0, sizeof(ifr)); - snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d", prefixes[i], x); - if (!ioctl(s, SIOCGIFHWADDR, &ifr)) { - break; - } + if (!ifaphead) { + ast_log(LOG_WARNING, "No ethernet interface found for seeding global EID. " + "You will have to set it manually.\n"); + return; + } + + for (ifap = ifaphead; ifap; ifap = ifap->ifa_next) { + if (ifap->ifa_addr->sa_family != AF_LINK) { + continue; } - if (i == ARRAY_LEN(prefixes)) { - /* Try pciX#[1..N] */ - for (i = 0; i < MAXIF; i++) { - memset(&ifr, 0, sizeof(ifr)); - snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "pci%d#%u", x, i); - if (!ioctl(s, SIOCGIFHWADDR, &ifr)) { - break; - } - } - if (i == MAXIF) { - continue; - } + sdl = (const struct sockaddr_dl *) ifap->ifa_addr; + ap = ((caddr_t) ((sdl)->sdl_data + (sdl)->sdl_nlen)); + alen = sdl->sdl_alen; + if (alen != 6 || !(memcmp(ap, &empty_mac, 6) && memcmp(ap, &full_mac, 6))) { + continue; } - memcpy(eid, ((unsigned char *)&ifr.ifr_hwaddr) + 2, sizeof(*eid)); - ast_debug(1, "Seeding global EID '%s' from '%s' using 'siocgifhwaddr'\n", ast_eid_to_str(eid_str, sizeof(eid_str), eid), ifr.ifr_name); + memcpy(eid, ap, sizeof(*eid)); + ast_debug(1, "Seeding global EID '%s'\n", + ast_eid_to_str(eid_str, sizeof(eid_str), eid)); + freeifaddrs(ifaphead); + return; + } + + ast_log(LOG_WARNING, "No ethernet interface found for seeding global EID. " + "You will have to set it manually.\n"); + freeifaddrs(ifaphead); + + return; +} + +#elif defined(SOLARIS) +#include +#include + +void ast_set_default_eid(struct ast_eid *eid) +{ + int s; + int x; + int res = 0; + struct lifreq *ifr = NULL; + struct lifnum ifn; + struct lifconf ifc; + struct arpreq ar; + struct sockaddr_in *sa, *sa2; + char *buf = NULL; + char eid_str[20]; + int bufsz; + unsigned char empty_mac[6] = {0, 0, 0, 0, 0, 0}; + unsigned char full_mac[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + + s = socket(AF_INET, SOCK_STREAM, 0); + if (s <= 0) { + ast_log(LOG_WARNING, "Unable to open a socket for seeding global EID. " + " You will have to set it manually.\n"); + return; + } + + /* Get a count of interfaces on the machine */ + ifn.lifn_family = AF_UNSPEC; + ifn.lifn_flags = 0; + ifn.lifn_count = 0; + if (ioctl(s, SIOCGLIFNUM, &ifn) < 0) { + ast_log(LOG_WARNING, "No ethernet interface found for seeding global EID. " + " You will have to set it manually.\n"); close(s); return; } + + bufsz = ifn.lifn_count * sizeof(struct lifreq); + if (!(buf = ast_malloc(bufsz))) { + ast_log(LOG_WARNING, "Unable to allocate memory for seeding global EID. " + "You will have to set it manually.\n"); + close(s); + return; + } + memset(buf, 0, bufsz); + + /* Get a list of interfaces on the machine */ + ifc.lifc_len = bufsz; + ifc.lifc_buf = buf; + ifc.lifc_family = AF_UNSPEC; + ifc.lifc_flags = 0; + if (ioctl(s, SIOCGLIFCONF, &ifc) < 0) { + ast_log(LOG_WARNING, "No ethernet interface found for seeding global EID. " + "You will have to set it manually.\n"); + ast_free(buf); + close(s); + return; + } + + for (ifr = (struct lifreq *)buf, x = 0; x < ifn.lifn_count; ifr++, x++) { + unsigned char *p; + + sa = (struct sockaddr_in *)&(ifr->lifr_addr); + sa2 = (struct sockaddr_in *)&(ar.arp_pa); + *sa2 = *sa; + + if(ioctl(s, SIOCGARP, &ar) >= 0) { + p = (unsigned char *)&(ar.arp_ha.sa_data); + if (!(memcmp(p, &empty_mac, 6) && memcmp(p, &full_mac, 6))) { + continue; + } + + memcpy(eid, p, sizeof(*eid)); + ast_debug(1, "Seeding global EID '%s'\n", + ast_eid_to_str(eid_str, sizeof(eid_str), eid)); + ast_free(buf); + close(s); + return; + } + } + + ast_log(LOG_WARNING, "No ethernet interface found for seeding global EID. " + "You will have to set it manually.\n"); + ast_free(buf); close(s); + + return; +} + #else -#if defined(ifa_broadaddr) && !defined(SOLARIS) +void ast_set_default_eid(struct ast_eid *eid) +{ + int s; + int i; + struct ifreq *ifr; + struct ifreq *ifrp; + struct ifconf ifc; + char *buf = NULL; char eid_str[20]; - struct ifaddrs *ifap; - - if (getifaddrs(&ifap) == 0) { - struct ifaddrs *p; - for (p = ifap; p; p = p->ifa_next) { - if ((p->ifa_addr->sa_family == AF_LINK) && !(p->ifa_flags & IFF_LOOPBACK) && (p->ifa_flags & IFF_RUNNING)) { - struct sockaddr_dl* sdp = (struct sockaddr_dl*) p->ifa_addr; - memcpy(&(eid->eid), sdp->sdl_data + sdp->sdl_nlen, 6); - ast_debug(1, "Seeding global EID '%s' from '%s' using 'getifaddrs'\n", ast_eid_to_str(eid_str, sizeof(eid_str), eid), p->ifa_name); - freeifaddrs(ifap); - return; + int bufsz, num_interfaces; + unsigned char empty_mac[6] = {0, 0, 0, 0, 0, 0}; + unsigned char full_mac[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + + s = socket(AF_INET, SOCK_STREAM, 0); + if (s <= 0) { + ast_log(LOG_WARNING, "Unable to open socket for seeding global EID. " + "You will have to set it manually.\n"); + return; + } + + ifc.ifc_len = 0; + ifc.ifc_buf = NULL; + if (ioctl(s, SIOCGIFCONF, &ifc) || ifc.ifc_len <= 0) { + ast_log(LOG_WARNING, "No ethernet interface found for seeding global EID. " + "You will have to set it manually.\n"); + close(s); + return; + } + bufsz = ifc.ifc_len; + + if (!(buf = ast_malloc(bufsz))) { + ast_log(LOG_WARNING, "Unable to allocate memory for seeding global EID. " + "You will have to set it manually.\n"); + close(s); + return; + } + + ifc.ifc_buf = buf; + if (ioctl(s, SIOCGIFCONF, &ifc) < 0) { + ast_log(LOG_WARNING, "Unable to retrieve ethernet interfaces for seeding global EID. " + "You will have to set it manually.\n"); + ast_free(buf); + close(s); + return; + } + + ifrp = ifc.ifc_req; + num_interfaces = ifc.ifc_len / sizeof(*ifr); + + for (i = 0; i < num_interfaces; i++) { + ifr = &ifrp[i]; + if (!ioctl(s, SIOCGIFHWADDR, ifr)) { + unsigned char *hwaddr = (unsigned char *) ifr->ifr_hwaddr.sa_data; + + if (!(memcmp(hwaddr, &empty_mac, 6) && memcmp(hwaddr, &full_mac, 6))) { + continue; } + + memcpy(eid, hwaddr, sizeof(*eid)); + ast_debug(1, "Seeding global EID '%s' from '%s' using 'siocgifhwaddr'\n", + ast_eid_to_str(eid_str, sizeof(eid_str), eid), ifr->ifr_name); + ast_free(buf); + close(s); + return; } - freeifaddrs(ifap); } -#endif -#endif - ast_log(LOG_WARNING, "No ethernet interface found for seeding global EID. You will have to set it manually.\n"); + + ast_log(LOG_WARNING, "No ethernet interface found for seeding global EID. " + "You will have to set it manually.\n"); + ast_free(buf); + close(s); + + return; } +#endif /* LINUX */ int ast_str_to_eid(struct ast_eid *eid, const char *s) {