112016SGirish.Moodalbail@Sun.COM /*
212016SGirish.Moodalbail@Sun.COM * CDDL HEADER START
312016SGirish.Moodalbail@Sun.COM *
412016SGirish.Moodalbail@Sun.COM * The contents of this file are subject to the terms of the
512016SGirish.Moodalbail@Sun.COM * Common Development and Distribution License (the "License").
612016SGirish.Moodalbail@Sun.COM * You may not use this file except in compliance with the License.
712016SGirish.Moodalbail@Sun.COM *
812016SGirish.Moodalbail@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
912016SGirish.Moodalbail@Sun.COM * or http://www.opensolaris.org/os/licensing.
1012016SGirish.Moodalbail@Sun.COM * See the License for the specific language governing permissions
1112016SGirish.Moodalbail@Sun.COM * and limitations under the License.
1212016SGirish.Moodalbail@Sun.COM *
1312016SGirish.Moodalbail@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
1412016SGirish.Moodalbail@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1512016SGirish.Moodalbail@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
1612016SGirish.Moodalbail@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
1712016SGirish.Moodalbail@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
1812016SGirish.Moodalbail@Sun.COM *
1912016SGirish.Moodalbail@Sun.COM * CDDL HEADER END
2012016SGirish.Moodalbail@Sun.COM */
2112016SGirish.Moodalbail@Sun.COM
2212016SGirish.Moodalbail@Sun.COM /*
2312805SDarren.Reed@Oracle.COM * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
2412016SGirish.Moodalbail@Sun.COM */
2512016SGirish.Moodalbail@Sun.COM
2612016SGirish.Moodalbail@Sun.COM #include <netdb.h>
2712016SGirish.Moodalbail@Sun.COM #include <nss_dbdefs.h>
2812016SGirish.Moodalbail@Sun.COM #include <netinet/in.h>
2912016SGirish.Moodalbail@Sun.COM #include <sys/socket.h>
3012016SGirish.Moodalbail@Sun.COM #include <string.h>
3112016SGirish.Moodalbail@Sun.COM #include <stdio.h>
3212016SGirish.Moodalbail@Sun.COM #include <sys/sockio.h>
3312016SGirish.Moodalbail@Sun.COM #include <sys/types.h>
3412016SGirish.Moodalbail@Sun.COM #include <stdlib.h>
3512016SGirish.Moodalbail@Sun.COM #include <net/if.h>
3612016SGirish.Moodalbail@Sun.COM #include <ifaddrs.h>
3712016SGirish.Moodalbail@Sun.COM #include <libsocket_priv.h>
3812016SGirish.Moodalbail@Sun.COM
3912016SGirish.Moodalbail@Sun.COM /*
4012016SGirish.Moodalbail@Sun.COM * Create a linked list of `struct ifaddrs' structures, one for each
4112016SGirish.Moodalbail@Sun.COM * address that is UP. If successful, store the list in *ifap and
4212016SGirish.Moodalbail@Sun.COM * return 0. On errors, return -1 and set `errno'.
4312016SGirish.Moodalbail@Sun.COM *
4412016SGirish.Moodalbail@Sun.COM * The storage returned in *ifap is allocated dynamically and can
4512016SGirish.Moodalbail@Sun.COM * only be properly freed by passing it to `freeifaddrs'.
4612016SGirish.Moodalbail@Sun.COM */
4712016SGirish.Moodalbail@Sun.COM int
getifaddrs(struct ifaddrs ** ifap)4812016SGirish.Moodalbail@Sun.COM getifaddrs(struct ifaddrs **ifap)
4912016SGirish.Moodalbail@Sun.COM {
5012016SGirish.Moodalbail@Sun.COM int err;
5112016SGirish.Moodalbail@Sun.COM char *cp;
5212016SGirish.Moodalbail@Sun.COM struct ifaddrs *curr;
5312016SGirish.Moodalbail@Sun.COM
5412016SGirish.Moodalbail@Sun.COM if (ifap == NULL) {
5512016SGirish.Moodalbail@Sun.COM errno = EINVAL;
5612016SGirish.Moodalbail@Sun.COM return (-1);
5712016SGirish.Moodalbail@Sun.COM }
5812016SGirish.Moodalbail@Sun.COM *ifap = NULL;
5912016SGirish.Moodalbail@Sun.COM err = getallifaddrs(AF_UNSPEC, ifap, LIFC_ENABLED);
6012016SGirish.Moodalbail@Sun.COM if (err == 0) {
6112016SGirish.Moodalbail@Sun.COM for (curr = *ifap; curr != NULL; curr = curr->ifa_next) {
6212016SGirish.Moodalbail@Sun.COM if ((cp = strchr(curr->ifa_name, ':')) != NULL)
6312016SGirish.Moodalbail@Sun.COM *cp = '\0';
6412016SGirish.Moodalbail@Sun.COM }
6512016SGirish.Moodalbail@Sun.COM }
6612016SGirish.Moodalbail@Sun.COM return (err);
6712016SGirish.Moodalbail@Sun.COM }
6812016SGirish.Moodalbail@Sun.COM
6912016SGirish.Moodalbail@Sun.COM void
freeifaddrs(struct ifaddrs * ifa)7012016SGirish.Moodalbail@Sun.COM freeifaddrs(struct ifaddrs *ifa)
7112016SGirish.Moodalbail@Sun.COM {
7212016SGirish.Moodalbail@Sun.COM struct ifaddrs *curr;
7312016SGirish.Moodalbail@Sun.COM
7412016SGirish.Moodalbail@Sun.COM while (ifa != NULL) {
7512016SGirish.Moodalbail@Sun.COM curr = ifa;
7612016SGirish.Moodalbail@Sun.COM ifa = ifa->ifa_next;
7712016SGirish.Moodalbail@Sun.COM free(curr->ifa_name);
7812016SGirish.Moodalbail@Sun.COM free(curr->ifa_addr);
7912016SGirish.Moodalbail@Sun.COM free(curr->ifa_netmask);
8012016SGirish.Moodalbail@Sun.COM free(curr->ifa_dstaddr);
8112016SGirish.Moodalbail@Sun.COM free(curr);
8212016SGirish.Moodalbail@Sun.COM }
8312016SGirish.Moodalbail@Sun.COM }
8412016SGirish.Moodalbail@Sun.COM
8512016SGirish.Moodalbail@Sun.COM /*
8612016SGirish.Moodalbail@Sun.COM * Returns all addresses configured on the system. If flags contain
8712016SGirish.Moodalbail@Sun.COM * LIFC_ENABLED, only the addresses that are UP are returned.
8812016SGirish.Moodalbail@Sun.COM * Address list that is returned by this function must be freed
8912016SGirish.Moodalbail@Sun.COM * using freeifaddrs().
9012016SGirish.Moodalbail@Sun.COM */
9112016SGirish.Moodalbail@Sun.COM int
getallifaddrs(sa_family_t af,struct ifaddrs ** ifap,int64_t flags)9212016SGirish.Moodalbail@Sun.COM getallifaddrs(sa_family_t af, struct ifaddrs **ifap, int64_t flags)
9312016SGirish.Moodalbail@Sun.COM {
9412016SGirish.Moodalbail@Sun.COM struct lifreq *buf = NULL;
9512016SGirish.Moodalbail@Sun.COM struct lifreq *lifrp;
9612016SGirish.Moodalbail@Sun.COM struct lifreq lifrl;
9712016SGirish.Moodalbail@Sun.COM int ret;
9812016SGirish.Moodalbail@Sun.COM int s, n, numifs;
9912016SGirish.Moodalbail@Sun.COM struct ifaddrs *curr, *prev;
10012016SGirish.Moodalbail@Sun.COM sa_family_t lifr_af;
10112016SGirish.Moodalbail@Sun.COM int sock4;
10212016SGirish.Moodalbail@Sun.COM int sock6;
10312016SGirish.Moodalbail@Sun.COM int err;
10412016SGirish.Moodalbail@Sun.COM
10512016SGirish.Moodalbail@Sun.COM if ((sock4 = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
10612016SGirish.Moodalbail@Sun.COM return (-1);
10712016SGirish.Moodalbail@Sun.COM if ((sock6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
10812016SGirish.Moodalbail@Sun.COM err = errno;
10912016SGirish.Moodalbail@Sun.COM close(sock4);
11012016SGirish.Moodalbail@Sun.COM errno = err;
11112016SGirish.Moodalbail@Sun.COM return (-1);
11212016SGirish.Moodalbail@Sun.COM }
11312016SGirish.Moodalbail@Sun.COM
11412016SGirish.Moodalbail@Sun.COM retry:
11512016SGirish.Moodalbail@Sun.COM /* Get all interfaces from SIOCGLIFCONF */
11612016SGirish.Moodalbail@Sun.COM ret = getallifs(sock4, af, &buf, &numifs, (flags & ~LIFC_ENABLED));
11712016SGirish.Moodalbail@Sun.COM if (ret != 0)
11812016SGirish.Moodalbail@Sun.COM goto fail;
11912016SGirish.Moodalbail@Sun.COM
12012016SGirish.Moodalbail@Sun.COM /*
12112016SGirish.Moodalbail@Sun.COM * Loop through the interfaces obtained from SIOCGLIFCOMF
12212016SGirish.Moodalbail@Sun.COM * and retrieve the addresses, netmask and flags.
12312016SGirish.Moodalbail@Sun.COM */
12412016SGirish.Moodalbail@Sun.COM prev = NULL;
12512016SGirish.Moodalbail@Sun.COM lifrp = buf;
12612016SGirish.Moodalbail@Sun.COM *ifap = NULL;
12712016SGirish.Moodalbail@Sun.COM for (n = 0; n < numifs; n++, lifrp++) {
12812016SGirish.Moodalbail@Sun.COM
12912016SGirish.Moodalbail@Sun.COM /* Prepare for the ioctl call */
13012016SGirish.Moodalbail@Sun.COM (void) strncpy(lifrl.lifr_name, lifrp->lifr_name,
13112016SGirish.Moodalbail@Sun.COM sizeof (lifrl.lifr_name));
13212016SGirish.Moodalbail@Sun.COM lifr_af = lifrp->lifr_addr.ss_family;
13312016SGirish.Moodalbail@Sun.COM if (af != AF_UNSPEC && lifr_af != af)
13412016SGirish.Moodalbail@Sun.COM continue;
13512016SGirish.Moodalbail@Sun.COM
13612016SGirish.Moodalbail@Sun.COM s = (lifr_af == AF_INET ? sock4 : sock6);
13712016SGirish.Moodalbail@Sun.COM
13812016SGirish.Moodalbail@Sun.COM if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifrl) < 0)
13912016SGirish.Moodalbail@Sun.COM goto fail;
14012016SGirish.Moodalbail@Sun.COM if ((flags & LIFC_ENABLED) && !(lifrl.lifr_flags & IFF_UP))
14112016SGirish.Moodalbail@Sun.COM continue;
14212016SGirish.Moodalbail@Sun.COM
14312016SGirish.Moodalbail@Sun.COM /*
14412016SGirish.Moodalbail@Sun.COM * Allocate the current list node. Each node contains data
14512016SGirish.Moodalbail@Sun.COM * for one ifaddrs structure.
14612016SGirish.Moodalbail@Sun.COM */
14712016SGirish.Moodalbail@Sun.COM curr = calloc(1, sizeof (struct ifaddrs));
14812016SGirish.Moodalbail@Sun.COM if (curr == NULL)
14912016SGirish.Moodalbail@Sun.COM goto fail;
15012016SGirish.Moodalbail@Sun.COM
15112016SGirish.Moodalbail@Sun.COM if (prev != NULL) {
15212016SGirish.Moodalbail@Sun.COM prev->ifa_next = curr;
15312016SGirish.Moodalbail@Sun.COM } else {
15412016SGirish.Moodalbail@Sun.COM /* First node in the linked list */
15512016SGirish.Moodalbail@Sun.COM *ifap = curr;
15612016SGirish.Moodalbail@Sun.COM }
15712016SGirish.Moodalbail@Sun.COM prev = curr;
15812016SGirish.Moodalbail@Sun.COM
15912016SGirish.Moodalbail@Sun.COM curr->ifa_flags = lifrl.lifr_flags;
16012016SGirish.Moodalbail@Sun.COM if ((curr->ifa_name = strdup(lifrp->lifr_name)) == NULL)
16112016SGirish.Moodalbail@Sun.COM goto fail;
16212016SGirish.Moodalbail@Sun.COM
16312016SGirish.Moodalbail@Sun.COM curr->ifa_addr = malloc(sizeof (struct sockaddr_storage));
16412016SGirish.Moodalbail@Sun.COM if (curr->ifa_addr == NULL)
16512016SGirish.Moodalbail@Sun.COM goto fail;
16612805SDarren.Reed@Oracle.COM (void) memcpy(curr->ifa_addr, &lifrp->lifr_addr,
16712805SDarren.Reed@Oracle.COM sizeof (struct sockaddr_storage));
16812016SGirish.Moodalbail@Sun.COM
16912016SGirish.Moodalbail@Sun.COM /* Get the netmask */
17012016SGirish.Moodalbail@Sun.COM if (ioctl(s, SIOCGLIFNETMASK, (caddr_t)&lifrl) < 0)
17112016SGirish.Moodalbail@Sun.COM goto fail;
17212016SGirish.Moodalbail@Sun.COM curr->ifa_netmask = malloc(sizeof (struct sockaddr_storage));
17312016SGirish.Moodalbail@Sun.COM if (curr->ifa_netmask == NULL)
17412016SGirish.Moodalbail@Sun.COM goto fail;
17512805SDarren.Reed@Oracle.COM (void) memcpy(curr->ifa_netmask, &lifrl.lifr_addr,
17612805SDarren.Reed@Oracle.COM sizeof (struct sockaddr_storage));
17712016SGirish.Moodalbail@Sun.COM
17812016SGirish.Moodalbail@Sun.COM /* Get the destination for a pt-pt interface */
17912016SGirish.Moodalbail@Sun.COM if (curr->ifa_flags & IFF_POINTOPOINT) {
18012016SGirish.Moodalbail@Sun.COM if (ioctl(s, SIOCGLIFDSTADDR, (caddr_t)&lifrl) < 0)
18112016SGirish.Moodalbail@Sun.COM goto fail;
18212016SGirish.Moodalbail@Sun.COM curr->ifa_dstaddr = malloc(
18312016SGirish.Moodalbail@Sun.COM sizeof (struct sockaddr_storage));
18412016SGirish.Moodalbail@Sun.COM if (curr->ifa_dstaddr == NULL)
18512016SGirish.Moodalbail@Sun.COM goto fail;
186*13086SVasumathi.Sundaram@oracle.COM (void) memcpy(curr->ifa_dstaddr, &lifrl.lifr_addr,
18712805SDarren.Reed@Oracle.COM sizeof (struct sockaddr_storage));
18812016SGirish.Moodalbail@Sun.COM } else if (curr->ifa_flags & IFF_BROADCAST) {
18912016SGirish.Moodalbail@Sun.COM if (ioctl(s, SIOCGLIFBRDADDR, (caddr_t)&lifrl) < 0)
19012016SGirish.Moodalbail@Sun.COM goto fail;
19112016SGirish.Moodalbail@Sun.COM curr->ifa_broadaddr = malloc(
19212016SGirish.Moodalbail@Sun.COM sizeof (struct sockaddr_storage));
19312016SGirish.Moodalbail@Sun.COM if (curr->ifa_broadaddr == NULL)
19412016SGirish.Moodalbail@Sun.COM goto fail;
195*13086SVasumathi.Sundaram@oracle.COM (void) memcpy(curr->ifa_broadaddr, &lifrl.lifr_addr,
19612805SDarren.Reed@Oracle.COM sizeof (struct sockaddr_storage));
19712016SGirish.Moodalbail@Sun.COM }
19812016SGirish.Moodalbail@Sun.COM
19912016SGirish.Moodalbail@Sun.COM }
20012016SGirish.Moodalbail@Sun.COM free(buf);
20112016SGirish.Moodalbail@Sun.COM close(sock4);
20212016SGirish.Moodalbail@Sun.COM close(sock6);
20312016SGirish.Moodalbail@Sun.COM return (0);
20412016SGirish.Moodalbail@Sun.COM fail:
20512016SGirish.Moodalbail@Sun.COM err = errno;
20612016SGirish.Moodalbail@Sun.COM free(buf);
20712016SGirish.Moodalbail@Sun.COM freeifaddrs(*ifap);
20812016SGirish.Moodalbail@Sun.COM *ifap = NULL;
20912016SGirish.Moodalbail@Sun.COM if (err == ENXIO)
21012016SGirish.Moodalbail@Sun.COM goto retry;
21112016SGirish.Moodalbail@Sun.COM close(sock4);
21212016SGirish.Moodalbail@Sun.COM close(sock6);
21312016SGirish.Moodalbail@Sun.COM errno = err;
21412016SGirish.Moodalbail@Sun.COM return (-1);
21512016SGirish.Moodalbail@Sun.COM }
21612016SGirish.Moodalbail@Sun.COM
21712016SGirish.Moodalbail@Sun.COM /*
21812016SGirish.Moodalbail@Sun.COM * Do a SIOCGLIFCONF and store all the interfaces in `buf'.
21912016SGirish.Moodalbail@Sun.COM */
22012016SGirish.Moodalbail@Sun.COM int
getallifs(int s,sa_family_t af,struct lifreq ** lifr,int * numifs,int64_t lifc_flags)22112016SGirish.Moodalbail@Sun.COM getallifs(int s, sa_family_t af, struct lifreq **lifr, int *numifs,
22212016SGirish.Moodalbail@Sun.COM int64_t lifc_flags)
22312016SGirish.Moodalbail@Sun.COM {
22412016SGirish.Moodalbail@Sun.COM struct lifnum lifn;
22512016SGirish.Moodalbail@Sun.COM struct lifconf lifc;
22612016SGirish.Moodalbail@Sun.COM size_t bufsize;
22712016SGirish.Moodalbail@Sun.COM char *tmp;
22812016SGirish.Moodalbail@Sun.COM caddr_t *buf = (caddr_t *)lifr;
22912016SGirish.Moodalbail@Sun.COM
23012016SGirish.Moodalbail@Sun.COM lifn.lifn_family = af;
23112016SGirish.Moodalbail@Sun.COM lifn.lifn_flags = lifc_flags;
23212016SGirish.Moodalbail@Sun.COM
23312016SGirish.Moodalbail@Sun.COM *buf = NULL;
23412016SGirish.Moodalbail@Sun.COM retry:
23512016SGirish.Moodalbail@Sun.COM if (ioctl(s, SIOCGLIFNUM, &lifn) < 0)
23612016SGirish.Moodalbail@Sun.COM goto fail;
23712016SGirish.Moodalbail@Sun.COM
23812016SGirish.Moodalbail@Sun.COM /*
23912016SGirish.Moodalbail@Sun.COM * When calculating the buffer size needed, add a small number
24012016SGirish.Moodalbail@Sun.COM * of interfaces to those we counted. We do this to capture
24112016SGirish.Moodalbail@Sun.COM * the interface status of potential interfaces which may have
24212016SGirish.Moodalbail@Sun.COM * been plumbed between the SIOCGLIFNUM and the SIOCGLIFCONF.
24312016SGirish.Moodalbail@Sun.COM */
24412016SGirish.Moodalbail@Sun.COM bufsize = (lifn.lifn_count + 4) * sizeof (struct lifreq);
24512016SGirish.Moodalbail@Sun.COM
24612016SGirish.Moodalbail@Sun.COM if ((tmp = realloc(*buf, bufsize)) == NULL)
24712016SGirish.Moodalbail@Sun.COM goto fail;
24812016SGirish.Moodalbail@Sun.COM
24912016SGirish.Moodalbail@Sun.COM *buf = tmp;
25012016SGirish.Moodalbail@Sun.COM lifc.lifc_family = af;
25112016SGirish.Moodalbail@Sun.COM lifc.lifc_flags = lifc_flags;
25212016SGirish.Moodalbail@Sun.COM lifc.lifc_len = bufsize;
25312016SGirish.Moodalbail@Sun.COM lifc.lifc_buf = *buf;
25412016SGirish.Moodalbail@Sun.COM if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) < 0)
25512016SGirish.Moodalbail@Sun.COM goto fail;
25612016SGirish.Moodalbail@Sun.COM
25712016SGirish.Moodalbail@Sun.COM *numifs = lifc.lifc_len / sizeof (struct lifreq);
25812016SGirish.Moodalbail@Sun.COM if (*numifs >= (lifn.lifn_count + 4)) {
25912016SGirish.Moodalbail@Sun.COM /*
26012016SGirish.Moodalbail@Sun.COM * If every entry was filled, there are probably
26112016SGirish.Moodalbail@Sun.COM * more interfaces than (lifn.lifn_count + 4).
26212016SGirish.Moodalbail@Sun.COM * Redo the ioctls SIOCGLIFNUM and SIOCGLIFCONF to
26312016SGirish.Moodalbail@Sun.COM * get all the interfaces.
26412016SGirish.Moodalbail@Sun.COM */
26512016SGirish.Moodalbail@Sun.COM goto retry;
26612016SGirish.Moodalbail@Sun.COM }
26712016SGirish.Moodalbail@Sun.COM return (0);
26812016SGirish.Moodalbail@Sun.COM fail:
26912016SGirish.Moodalbail@Sun.COM free(*buf);
27012016SGirish.Moodalbail@Sun.COM *buf = NULL;
27112016SGirish.Moodalbail@Sun.COM return (-1);
27212016SGirish.Moodalbail@Sun.COM }
273