xref: /titanic_44/usr/src/cmd/hal/addons/network-devices/common.c (revision 18c4e255539c8eac2a18c73be8729ec1f6fa818a)
14e9cfc9aSjacobs /*
2*18c4e255SLin Guo - Sun Microsystems  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
34e9cfc9aSjacobs  *
44e9cfc9aSjacobs  * Licensed under the Academic Free License version 2.1
54e9cfc9aSjacobs  */
64e9cfc9aSjacobs 
74e9cfc9aSjacobs #include <stdio.h>
84e9cfc9aSjacobs #include <stdlib.h>
94e9cfc9aSjacobs #include <unistd.h>
104e9cfc9aSjacobs #include <signal.h>
114e9cfc9aSjacobs #include <string.h>
124e9cfc9aSjacobs #include <sys/types.h>
134e9cfc9aSjacobs #include <sys/socket.h>
144e9cfc9aSjacobs #include <sys/ioctl.h>
154e9cfc9aSjacobs #include <sys/sockio.h>
164e9cfc9aSjacobs #include <net/if.h>
174e9cfc9aSjacobs #include <net/if_arp.h>
184e9cfc9aSjacobs #include <netinet/in.h>
194e9cfc9aSjacobs #include <arpa/inet.h>
204e9cfc9aSjacobs #include <netdb.h>
214e9cfc9aSjacobs 
224e9cfc9aSjacobs #include <libhal.h>
234e9cfc9aSjacobs #include <logger.h>
244e9cfc9aSjacobs 
254e9cfc9aSjacobs #include <glib.h>
264e9cfc9aSjacobs 
274e9cfc9aSjacobs #include "network-discovery.h"
284e9cfc9aSjacobs #define	NP(x)	(x?x:"NULL")
294e9cfc9aSjacobs 
304e9cfc9aSjacobs extern int snmp_printer_info(char *hostname, char *community,
314e9cfc9aSjacobs 		char **manufacturer, char **model, char **description,
324e9cfc9aSjacobs 		char **serial_no, char ***command_set, char **uri);
334e9cfc9aSjacobs 
344e9cfc9aSjacobs void
network_device_name_to_udi(char * udi,size_t size,...)354e9cfc9aSjacobs network_device_name_to_udi(char *udi, size_t size, ...)
364e9cfc9aSjacobs {
374e9cfc9aSjacobs 	va_list ap;
384e9cfc9aSjacobs 	char *element;
394e9cfc9aSjacobs 	int i;
404e9cfc9aSjacobs 
414e9cfc9aSjacobs 	udi[0] = '\0';
424e9cfc9aSjacobs 	va_start(ap, size);
434e9cfc9aSjacobs 	while ((element = va_arg(ap, char *)) != NULL) {
444e9cfc9aSjacobs 		if (element[0] != '/')
454e9cfc9aSjacobs 			strlcat(udi, "/", size);
464e9cfc9aSjacobs 		strlcat(udi, element, size);
474e9cfc9aSjacobs 	}
484e9cfc9aSjacobs 	va_end(ap);
494e9cfc9aSjacobs 
504e9cfc9aSjacobs 	for (i = 0; udi[i] != NULL; i++)
514e9cfc9aSjacobs 		if (udi[i] == '.')
524e9cfc9aSjacobs 			udi[i] = '_';
534e9cfc9aSjacobs }
544e9cfc9aSjacobs 
nop(int sig)554e9cfc9aSjacobs static void nop(int sig) {}
564e9cfc9aSjacobs 
574e9cfc9aSjacobs static int
test_socket_access(struct in6_addr * addr,int port)584e9cfc9aSjacobs test_socket_access(struct in6_addr *addr, int port)
594e9cfc9aSjacobs {
604e9cfc9aSjacobs 	int sd, rc;
614e9cfc9aSjacobs 	struct sockaddr_in6 sin6;
624e9cfc9aSjacobs 	void (*hndlr)(int);
634e9cfc9aSjacobs 
644e9cfc9aSjacobs 	memset(&sin6, 0, sizeof (sin6));
654e9cfc9aSjacobs 	sin6.sin6_family = AF_INET6;
664e9cfc9aSjacobs 	memcpy(&sin6.sin6_addr, addr, sizeof (*addr));
674e9cfc9aSjacobs 	sin6.sin6_port = htons(port);
684e9cfc9aSjacobs 
694e9cfc9aSjacobs 	sd = socket(AF_INET6, SOCK_STREAM, 0);
704e9cfc9aSjacobs 	hndlr = signal(SIGALRM, nop);
714e9cfc9aSjacobs 	alarm(1);
724e9cfc9aSjacobs 	rc = connect(sd, (struct sockaddr *)&sin6, sizeof (sin6));
734e9cfc9aSjacobs 	alarm(0);
744e9cfc9aSjacobs 	if (hndlr != NULL)
754e9cfc9aSjacobs 		signal(SIGALRM, hndlr);
764e9cfc9aSjacobs 	close(sd);
774e9cfc9aSjacobs 
784e9cfc9aSjacobs 	return ((rc < 0) ? 1 : 0);
794e9cfc9aSjacobs }
804e9cfc9aSjacobs 
814e9cfc9aSjacobs int
is_listening(char * hostname,int port)824e9cfc9aSjacobs is_listening(char *hostname, int port)
834e9cfc9aSjacobs {
844e9cfc9aSjacobs 	char *uri = NULL, addr_string[INET6_ADDRSTRLEN];
854e9cfc9aSjacobs 	struct in6_addr ipv6addr[1];
864e9cfc9aSjacobs 	int errnum;
874e9cfc9aSjacobs 	struct hostent *hp;
884e9cfc9aSjacobs 
894e9cfc9aSjacobs 	hp = getipnodebyname(hostname, AF_INET6,
904e9cfc9aSjacobs 			AI_ALL | AI_ADDRCONFIG | AI_V4MAPPED, &errnum);
914e9cfc9aSjacobs 	if (hp != NULL) {
924e9cfc9aSjacobs 		(void) memcpy(&ipv6addr, hp->h_addr_list[0], hp->h_length);
934e9cfc9aSjacobs 	} else
944e9cfc9aSjacobs 		return (-1);
954e9cfc9aSjacobs 
964e9cfc9aSjacobs 	return (test_socket_access(ipv6addr, port));
974e9cfc9aSjacobs }
984e9cfc9aSjacobs 
994e9cfc9aSjacobs static char *
addr_to_string(char * prefix,uchar_t * mac,int mac_len,char * buf,int buf_len)1004e9cfc9aSjacobs addr_to_string(char *prefix, uchar_t *mac, int mac_len, char *buf, int buf_len)
1014e9cfc9aSjacobs {
1024e9cfc9aSjacobs 	int i, n = 0;
1034e9cfc9aSjacobs 
1044e9cfc9aSjacobs 	buf[0] = '\0';
1054e9cfc9aSjacobs 	if (prefix != NULL)
1064e9cfc9aSjacobs 		n = sprintf(buf, prefix);
1074e9cfc9aSjacobs 	for (i = 0; ((i < (mac_len)) && (n < buf_len)); i++)
1084e9cfc9aSjacobs 		n += sprintf(buf + n, "%2.2X", *mac++);
1094e9cfc9aSjacobs 
1104e9cfc9aSjacobs 	return (buf);
1114e9cfc9aSjacobs }
1124e9cfc9aSjacobs 
1134e9cfc9aSjacobs static char *
pseudo_serialno_from_addr(char * name)1144e9cfc9aSjacobs pseudo_serialno_from_addr(char *name)
1154e9cfc9aSjacobs {
1164e9cfc9aSjacobs 	int sd, rc, errnum;
1174e9cfc9aSjacobs 	char buf[128];
1184e9cfc9aSjacobs 	struct hostent *hp;
1194e9cfc9aSjacobs 	struct xarpreq ar;
1204e9cfc9aSjacobs 
1214e9cfc9aSjacobs 	if (name == NULL)
1224e9cfc9aSjacobs 		return (NULL);
1234e9cfc9aSjacobs 
1244e9cfc9aSjacobs 	memset(&ar, 0, sizeof (ar));
1254e9cfc9aSjacobs 
1264e9cfc9aSjacobs 	hp = getipnodebyname(name, AF_INET6, AI_ADDRCONFIG, &errnum);
1274e9cfc9aSjacobs 	if (hp != NULL) {
1284e9cfc9aSjacobs 		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ar.xarp_pa;
1294e9cfc9aSjacobs 
1304e9cfc9aSjacobs 		sin6->sin6_family = AF_INET6;
1314e9cfc9aSjacobs 		(void) memcpy(&sin6->sin6_addr, hp->h_addr_list[0],
1324e9cfc9aSjacobs 				hp->h_length);
1334e9cfc9aSjacobs 	} else {
1344e9cfc9aSjacobs 		struct sockaddr_in *sin = (struct sockaddr_in *)&ar.xarp_pa;
1354e9cfc9aSjacobs 
1364e9cfc9aSjacobs 		sin->sin_family = AF_INET;
1374e9cfc9aSjacobs 		sin->sin_addr.s_addr = inet_addr(name);
1384e9cfc9aSjacobs 	}
1394e9cfc9aSjacobs 
1404e9cfc9aSjacobs 	sd = socket(AF_INET, SOCK_DGRAM, 0);
1414e9cfc9aSjacobs 
1424e9cfc9aSjacobs 	ar.xarp_ha.sdl_family = AF_LINK;
1434e9cfc9aSjacobs 	rc = ioctl(sd, SIOCGXARP, (caddr_t)&ar);
1444e9cfc9aSjacobs 
1454e9cfc9aSjacobs 	close(sd);
1464e9cfc9aSjacobs 
1474e9cfc9aSjacobs 	if (ar.xarp_flags & ATF_COM) {  /* use the MAC address */
1484e9cfc9aSjacobs 		uchar_t *ea = (uchar_t *)LLADDR(&ar.xarp_ha);
1494e9cfc9aSjacobs 
1504e9cfc9aSjacobs 		addr_to_string("LLADDR-", ea, ar.xarp_ha.sdl_alen,
1514e9cfc9aSjacobs 					buf, sizeof (buf));
1524e9cfc9aSjacobs 
1534e9cfc9aSjacobs 	} else if (hp != NULL) {	  /* use the IPv6 address */
1544e9cfc9aSjacobs 		addr_to_string("IPV6ADDR-", (uchar_t *)&hp->h_addr_list[0],
1554e9cfc9aSjacobs 					hp->h_length, buf, sizeof (buf));
1564e9cfc9aSjacobs 	} else {			  /* use the IPv4 address */
1574e9cfc9aSjacobs 		struct sockaddr_in *sin = (struct sockaddr_in *)&ar.xarp_pa;
1584e9cfc9aSjacobs 
1594e9cfc9aSjacobs 		addr_to_string("IPV4ADDR-", (uchar_t *)&sin->sin_addr.s_addr, 4,
1604e9cfc9aSjacobs 					buf, sizeof (buf));
1614e9cfc9aSjacobs 	}
1624e9cfc9aSjacobs 
1634e9cfc9aSjacobs 	return (strdup(buf));
1644e9cfc9aSjacobs }
1654e9cfc9aSjacobs 
1664e9cfc9aSjacobs int
add_network_printer(LibHalContext * ctx,char * base,char * hostaddr,char * device,char * community)1674e9cfc9aSjacobs add_network_printer(LibHalContext *ctx, char *base, char *hostaddr,
1684e9cfc9aSjacobs 		char *device, char *community)
1694e9cfc9aSjacobs {
1704e9cfc9aSjacobs 	DBusError error;
1714e9cfc9aSjacobs 	int rc = -1;
1724e9cfc9aSjacobs 	char udi[128];
1734e9cfc9aSjacobs 	char *tmp_udi = NULL;
1744e9cfc9aSjacobs 	static char *parent = NULL;
1754e9cfc9aSjacobs 	char *manufacturer = NULL, *model = NULL, *description = NULL,
1764e9cfc9aSjacobs 	     *uri = NULL, *sn, *serial;
1774e9cfc9aSjacobs 
1784e9cfc9aSjacobs 	sn = serial = pseudo_serialno_from_addr(hostaddr);
1794e9cfc9aSjacobs 
1804e9cfc9aSjacobs 	if (parent == NULL)
1814e9cfc9aSjacobs 		parent = getenv("UDI");
1824e9cfc9aSjacobs 
1834e9cfc9aSjacobs 	dbus_error_init(&error);
1844e9cfc9aSjacobs 
1854e9cfc9aSjacobs 	network_device_name_to_udi(udi, sizeof (udi), base, serial, NULL);
1864e9cfc9aSjacobs 
1874e9cfc9aSjacobs 	if (libhal_device_exists(ctx, udi, &error) == TRUE)
1884e9cfc9aSjacobs 		goto out;
1894e9cfc9aSjacobs 
1904e9cfc9aSjacobs 	if ((tmp_udi = libhal_new_device(ctx, &error)) == NULL)
1914e9cfc9aSjacobs 		goto out;
1924e9cfc9aSjacobs 
1934e9cfc9aSjacobs 	snmp_printer_info(hostaddr, community, &manufacturer, &model,
1944e9cfc9aSjacobs 			&description, &serial, NULL, &uri);
1954e9cfc9aSjacobs 
1964e9cfc9aSjacobs 	libhal_device_set_property_string(ctx, tmp_udi,
1974e9cfc9aSjacobs 			"info.parent", parent, &error);
1984e9cfc9aSjacobs 
1994e9cfc9aSjacobs 	libhal_device_set_property_string(ctx, tmp_udi,
2004e9cfc9aSjacobs 			"info.category", "printer", &error);
2014e9cfc9aSjacobs 
2024e9cfc9aSjacobs 	libhal_device_property_strlist_append(ctx, tmp_udi,
2034e9cfc9aSjacobs 				"info.capabilities", "printer", &error);
2044e9cfc9aSjacobs 	libhal_device_property_strlist_append(ctx, tmp_udi,
2054e9cfc9aSjacobs 				"info.capabilities", "network_device", &error);
2064e9cfc9aSjacobs 
2074e9cfc9aSjacobs 	libhal_device_set_property_string(ctx, tmp_udi,
2084e9cfc9aSjacobs 			"network_device.address", hostaddr, &error);
2094e9cfc9aSjacobs 
2104e9cfc9aSjacobs 	if ((community != NULL) && (strcasecmp(community, "public") != 0))
2114e9cfc9aSjacobs 		libhal_device_set_property_string(ctx, tmp_udi,
2124e9cfc9aSjacobs 			"network_device.snmp_community", community, &error);
2134e9cfc9aSjacobs 
2144e9cfc9aSjacobs 	if ((uri != NULL) || (device != NULL))
2154e9cfc9aSjacobs 		libhal_device_set_property_string(ctx, tmp_udi,
2164e9cfc9aSjacobs 			"printer.device", (uri ? uri : device), &error);
2174e9cfc9aSjacobs 
2184e9cfc9aSjacobs 	if (serial != NULL)
2194e9cfc9aSjacobs 		libhal_device_set_property_string(ctx, tmp_udi,
2204e9cfc9aSjacobs 			"printer.serial", serial, &error);
2214e9cfc9aSjacobs 
2224e9cfc9aSjacobs 	if (manufacturer != NULL)
2234e9cfc9aSjacobs 		libhal_device_set_property_string(ctx, tmp_udi,
2244e9cfc9aSjacobs 			"printer.vendor", manufacturer, &error);
2254e9cfc9aSjacobs 
2264e9cfc9aSjacobs 	if (model != NULL)
2274e9cfc9aSjacobs 		libhal_device_set_property_string(ctx, tmp_udi,
2284e9cfc9aSjacobs 			"printer.product", model, &error);
2294e9cfc9aSjacobs 
2304e9cfc9aSjacobs 	if (description != NULL)
2314e9cfc9aSjacobs 		libhal_device_set_property_string(ctx, tmp_udi,
2324e9cfc9aSjacobs 			"printer.description", description, &error);
2334e9cfc9aSjacobs 
2344e9cfc9aSjacobs 	/* commit the changes to the new UDI */
2354e9cfc9aSjacobs 	rc = libhal_device_commit_to_gdl(ctx, tmp_udi, udi, &error);
2364e9cfc9aSjacobs 
2374e9cfc9aSjacobs out:
2384e9cfc9aSjacobs 	HAL_DEBUG(("result: %s (%s): %s, %s, %s, %s, %s", hostaddr, udi,
2394e9cfc9aSjacobs 		NP(manufacturer), NP(model), NP(description), NP(serial),
2404e9cfc9aSjacobs 		NP(uri)));
2414e9cfc9aSjacobs 
2424e9cfc9aSjacobs 	if (tmp_udi != NULL)
2434e9cfc9aSjacobs 		free(tmp_udi);
2444e9cfc9aSjacobs 	if (manufacturer != NULL)
2454e9cfc9aSjacobs 		free(manufacturer);
2464e9cfc9aSjacobs 	if (model != NULL)
2474e9cfc9aSjacobs 		free(model);
2484e9cfc9aSjacobs 	if (description != NULL)
2494e9cfc9aSjacobs 		free(description);
2504e9cfc9aSjacobs 	if (uri != NULL)
2514e9cfc9aSjacobs 		free(uri);
2524e9cfc9aSjacobs 	if (sn != NULL)
2534e9cfc9aSjacobs 		free(sn);
2544e9cfc9aSjacobs 
2554e9cfc9aSjacobs 	if (dbus_error_is_set(&error)) {
2564e9cfc9aSjacobs 		HAL_WARNING(("%s: %s", error.name, error.message));
2574e9cfc9aSjacobs 		dbus_error_free(&error);
2584e9cfc9aSjacobs 	}
2594e9cfc9aSjacobs 
2604e9cfc9aSjacobs 	HAL_DEBUG(("add: %s (%s)", hostaddr, udi));
2614e9cfc9aSjacobs 
2624e9cfc9aSjacobs 	return (rc);
2634e9cfc9aSjacobs }
2644e9cfc9aSjacobs 
2654e9cfc9aSjacobs static int
number_of_interfaces(int s)2664e9cfc9aSjacobs number_of_interfaces(int s)
2674e9cfc9aSjacobs {
2684e9cfc9aSjacobs 	int rc = -1;
2694e9cfc9aSjacobs 	struct lifnum n;
2704e9cfc9aSjacobs 
2714e9cfc9aSjacobs 	memset(&n, 0 , sizeof (n));
272*18c4e255SLin Guo - Sun Microsystems 	n.lifn_family = AF_INET;
2734e9cfc9aSjacobs 	if (ioctl(s, SIOCGLIFNUM, (char *)&n) == 0)
2744e9cfc9aSjacobs 		rc = n.lifn_count;
2754e9cfc9aSjacobs 
2764e9cfc9aSjacobs 	return (rc);
2774e9cfc9aSjacobs }
2784e9cfc9aSjacobs 
2794e9cfc9aSjacobs static char *
broadcast_address(int s,char * ifname)2804e9cfc9aSjacobs broadcast_address(int s, char *ifname)
2814e9cfc9aSjacobs {
2824e9cfc9aSjacobs 	char *result = NULL;
2834e9cfc9aSjacobs 	struct lifreq r;
2844e9cfc9aSjacobs 
2854e9cfc9aSjacobs 	memset(&r, 0, sizeof (r));
286*18c4e255SLin Guo - Sun Microsystems 	strlcpy(r.lifr_name, ifname, sizeof (r.lifr_name));
287*18c4e255SLin Guo - Sun Microsystems 	if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&r) < 0) {
288*18c4e255SLin Guo - Sun Microsystems 		HAL_DEBUG(("broadcast_address: ioctl(SIOCGLIFFLAGS) failed."));
289*18c4e255SLin Guo - Sun Microsystems 		return (NULL);
290*18c4e255SLin Guo - Sun Microsystems 	}
291*18c4e255SLin Guo - Sun Microsystems 	if ((r.lifr_flags & (IFF_UP | IFF_LOOPBACK)) != IFF_UP) {
292*18c4e255SLin Guo - Sun Microsystems 		return (NULL);
293*18c4e255SLin Guo - Sun Microsystems 	}
294*18c4e255SLin Guo - Sun Microsystems 	if (ioctl(s, SIOCGLIFBRDADDR, (char *)&r) >= 0) {
295*18c4e255SLin Guo - Sun Microsystems 		char buf[INET_ADDRSTRLEN];
2964e9cfc9aSjacobs 		struct sockaddr_in *s =
2974e9cfc9aSjacobs 		    (struct sockaddr_in *)&r.lifr_broadaddr;
298*18c4e255SLin Guo - Sun Microsystems 		result = (char *)inet_ntop(AF_INET,
299*18c4e255SLin Guo - Sun Microsystems 		    &s->sin_addr, buf, sizeof (buf));
3004e9cfc9aSjacobs 		if (result != NULL)
3014e9cfc9aSjacobs 			result = strdup(result);
3024e9cfc9aSjacobs 	}
3034e9cfc9aSjacobs 
3044e9cfc9aSjacobs 	return (result);
3054e9cfc9aSjacobs }
3064e9cfc9aSjacobs 
3074e9cfc9aSjacobs GList *
broadcast_addresses()3084e9cfc9aSjacobs broadcast_addresses()
3094e9cfc9aSjacobs {
3104e9cfc9aSjacobs 	GList *result = NULL;
3114e9cfc9aSjacobs 	int s;
3124e9cfc9aSjacobs 	struct lifconf c;
3134e9cfc9aSjacobs 	int count;
3144e9cfc9aSjacobs 
3154e9cfc9aSjacobs 	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
3164e9cfc9aSjacobs 		return (NULL);
3174e9cfc9aSjacobs 
3184e9cfc9aSjacobs 	count = number_of_interfaces(s);
3194e9cfc9aSjacobs 
3204e9cfc9aSjacobs 	memset(&c, 0, sizeof (c));
321*18c4e255SLin Guo - Sun Microsystems 	c.lifc_family = AF_INET;
322*18c4e255SLin Guo - Sun Microsystems 	c.lifc_flags = 0;
3234e9cfc9aSjacobs 	c.lifc_buf = calloc(count, sizeof (struct lifreq));
3244e9cfc9aSjacobs 	c.lifc_len = (count * sizeof (struct lifreq));
3254e9cfc9aSjacobs 
3264e9cfc9aSjacobs 	if (ioctl(s, SIOCGLIFCONF, (char *)&c) == 0) {
3274e9cfc9aSjacobs 		struct lifreq *r = c.lifc_req;
3284e9cfc9aSjacobs 
3294e9cfc9aSjacobs 		for (count = c.lifc_len / sizeof (struct lifreq);
3304e9cfc9aSjacobs 		     count > 0; count--, r++) {
3314e9cfc9aSjacobs 			char *address = broadcast_address(s, r->lifr_name);
3324e9cfc9aSjacobs 
3334e9cfc9aSjacobs 			if (address != NULL) /* add it to the list */
3344e9cfc9aSjacobs 				result = g_list_append(result, address);
3354e9cfc9aSjacobs 		}
3364e9cfc9aSjacobs 	}
3374e9cfc9aSjacobs 	free(c.lifc_buf);
3384e9cfc9aSjacobs 	close(s);
3394e9cfc9aSjacobs 
3404e9cfc9aSjacobs 	return (result);
3414e9cfc9aSjacobs }
342