xref: /onnv-gate/usr/src/cmd/hal/addons/network-devices/common.c (revision 12395:50bdcae3feb5)
15307Sjacobs /*
2*12395SLin.Guo@Sun.COM  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
35307Sjacobs  *
45307Sjacobs  * Licensed under the Academic Free License version 2.1
55307Sjacobs  */
65307Sjacobs 
75307Sjacobs #include <stdio.h>
85307Sjacobs #include <stdlib.h>
95307Sjacobs #include <unistd.h>
105307Sjacobs #include <signal.h>
115307Sjacobs #include <string.h>
125307Sjacobs #include <sys/types.h>
135307Sjacobs #include <sys/socket.h>
145307Sjacobs #include <sys/ioctl.h>
155307Sjacobs #include <sys/sockio.h>
165307Sjacobs #include <net/if.h>
175307Sjacobs #include <net/if_arp.h>
185307Sjacobs #include <netinet/in.h>
195307Sjacobs #include <arpa/inet.h>
205307Sjacobs #include <netdb.h>
215307Sjacobs 
225307Sjacobs #include <libhal.h>
235307Sjacobs #include <logger.h>
245307Sjacobs 
255307Sjacobs #include <glib.h>
265307Sjacobs 
275307Sjacobs #include "network-discovery.h"
285307Sjacobs #define	NP(x)	(x?x:"NULL")
295307Sjacobs 
305307Sjacobs extern int snmp_printer_info(char *hostname, char *community,
315307Sjacobs 		char **manufacturer, char **model, char **description,
325307Sjacobs 		char **serial_no, char ***command_set, char **uri);
335307Sjacobs 
345307Sjacobs void
network_device_name_to_udi(char * udi,size_t size,...)355307Sjacobs network_device_name_to_udi(char *udi, size_t size, ...)
365307Sjacobs {
375307Sjacobs 	va_list ap;
385307Sjacobs 	char *element;
395307Sjacobs 	int i;
405307Sjacobs 
415307Sjacobs 	udi[0] = '\0';
425307Sjacobs 	va_start(ap, size);
435307Sjacobs 	while ((element = va_arg(ap, char *)) != NULL) {
445307Sjacobs 		if (element[0] != '/')
455307Sjacobs 			strlcat(udi, "/", size);
465307Sjacobs 		strlcat(udi, element, size);
475307Sjacobs 	}
485307Sjacobs 	va_end(ap);
495307Sjacobs 
505307Sjacobs 	for (i = 0; udi[i] != NULL; i++)
515307Sjacobs 		if (udi[i] == '.')
525307Sjacobs 			udi[i] = '_';
535307Sjacobs }
545307Sjacobs 
nop(int sig)555307Sjacobs static void nop(int sig) {}
565307Sjacobs 
575307Sjacobs static int
test_socket_access(struct in6_addr * addr,int port)585307Sjacobs test_socket_access(struct in6_addr *addr, int port)
595307Sjacobs {
605307Sjacobs 	int sd, rc;
615307Sjacobs 	struct sockaddr_in6 sin6;
625307Sjacobs 	void (*hndlr)(int);
635307Sjacobs 
645307Sjacobs 	memset(&sin6, 0, sizeof (sin6));
655307Sjacobs 	sin6.sin6_family = AF_INET6;
665307Sjacobs 	memcpy(&sin6.sin6_addr, addr, sizeof (*addr));
675307Sjacobs 	sin6.sin6_port = htons(port);
685307Sjacobs 
695307Sjacobs 	sd = socket(AF_INET6, SOCK_STREAM, 0);
705307Sjacobs 	hndlr = signal(SIGALRM, nop);
715307Sjacobs 	alarm(1);
725307Sjacobs 	rc = connect(sd, (struct sockaddr *)&sin6, sizeof (sin6));
735307Sjacobs 	alarm(0);
745307Sjacobs 	if (hndlr != NULL)
755307Sjacobs 		signal(SIGALRM, hndlr);
765307Sjacobs 	close(sd);
775307Sjacobs 
785307Sjacobs 	return ((rc < 0) ? 1 : 0);
795307Sjacobs }
805307Sjacobs 
815307Sjacobs int
is_listening(char * hostname,int port)825307Sjacobs is_listening(char *hostname, int port)
835307Sjacobs {
845307Sjacobs 	char *uri = NULL, addr_string[INET6_ADDRSTRLEN];
855307Sjacobs 	struct in6_addr ipv6addr[1];
865307Sjacobs 	int errnum;
875307Sjacobs 	struct hostent *hp;
885307Sjacobs 
895307Sjacobs 	hp = getipnodebyname(hostname, AF_INET6,
905307Sjacobs 			AI_ALL | AI_ADDRCONFIG | AI_V4MAPPED, &errnum);
915307Sjacobs 	if (hp != NULL) {
925307Sjacobs 		(void) memcpy(&ipv6addr, hp->h_addr_list[0], hp->h_length);
935307Sjacobs 	} else
945307Sjacobs 		return (-1);
955307Sjacobs 
965307Sjacobs 	return (test_socket_access(ipv6addr, port));
975307Sjacobs }
985307Sjacobs 
995307Sjacobs static char *
addr_to_string(char * prefix,uchar_t * mac,int mac_len,char * buf,int buf_len)1005307Sjacobs addr_to_string(char *prefix, uchar_t *mac, int mac_len, char *buf, int buf_len)
1015307Sjacobs {
1025307Sjacobs 	int i, n = 0;
1035307Sjacobs 
1045307Sjacobs 	buf[0] = '\0';
1055307Sjacobs 	if (prefix != NULL)
1065307Sjacobs 		n = sprintf(buf, prefix);
1075307Sjacobs 	for (i = 0; ((i < (mac_len)) && (n < buf_len)); i++)
1085307Sjacobs 		n += sprintf(buf + n, "%2.2X", *mac++);
1095307Sjacobs 
1105307Sjacobs 	return (buf);
1115307Sjacobs }
1125307Sjacobs 
1135307Sjacobs static char *
pseudo_serialno_from_addr(char * name)1145307Sjacobs pseudo_serialno_from_addr(char *name)
1155307Sjacobs {
1165307Sjacobs 	int sd, rc, errnum;
1175307Sjacobs 	char buf[128];
1185307Sjacobs 	struct hostent *hp;
1195307Sjacobs 	struct xarpreq ar;
1205307Sjacobs 
1215307Sjacobs 	if (name == NULL)
1225307Sjacobs 		return (NULL);
1235307Sjacobs 
1245307Sjacobs 	memset(&ar, 0, sizeof (ar));
1255307Sjacobs 
1265307Sjacobs 	hp = getipnodebyname(name, AF_INET6, AI_ADDRCONFIG, &errnum);
1275307Sjacobs 	if (hp != NULL) {
1285307Sjacobs 		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ar.xarp_pa;
1295307Sjacobs 
1305307Sjacobs 		sin6->sin6_family = AF_INET6;
1315307Sjacobs 		(void) memcpy(&sin6->sin6_addr, hp->h_addr_list[0],
1325307Sjacobs 				hp->h_length);
1335307Sjacobs 	} else {
1345307Sjacobs 		struct sockaddr_in *sin = (struct sockaddr_in *)&ar.xarp_pa;
1355307Sjacobs 
1365307Sjacobs 		sin->sin_family = AF_INET;
1375307Sjacobs 		sin->sin_addr.s_addr = inet_addr(name);
1385307Sjacobs 	}
1395307Sjacobs 
1405307Sjacobs 	sd = socket(AF_INET, SOCK_DGRAM, 0);
1415307Sjacobs 
1425307Sjacobs 	ar.xarp_ha.sdl_family = AF_LINK;
1435307Sjacobs 	rc = ioctl(sd, SIOCGXARP, (caddr_t)&ar);
1445307Sjacobs 
1455307Sjacobs 	close(sd);
1465307Sjacobs 
1475307Sjacobs 	if (ar.xarp_flags & ATF_COM) {  /* use the MAC address */
1485307Sjacobs 		uchar_t *ea = (uchar_t *)LLADDR(&ar.xarp_ha);
1495307Sjacobs 
1505307Sjacobs 		addr_to_string("LLADDR-", ea, ar.xarp_ha.sdl_alen,
1515307Sjacobs 					buf, sizeof (buf));
1525307Sjacobs 
1535307Sjacobs 	} else if (hp != NULL) {	  /* use the IPv6 address */
1545307Sjacobs 		addr_to_string("IPV6ADDR-", (uchar_t *)&hp->h_addr_list[0],
1555307Sjacobs 					hp->h_length, buf, sizeof (buf));
1565307Sjacobs 	} else {			  /* use the IPv4 address */
1575307Sjacobs 		struct sockaddr_in *sin = (struct sockaddr_in *)&ar.xarp_pa;
1585307Sjacobs 
1595307Sjacobs 		addr_to_string("IPV4ADDR-", (uchar_t *)&sin->sin_addr.s_addr, 4,
1605307Sjacobs 					buf, sizeof (buf));
1615307Sjacobs 	}
1625307Sjacobs 
1635307Sjacobs 	return (strdup(buf));
1645307Sjacobs }
1655307Sjacobs 
1665307Sjacobs int
add_network_printer(LibHalContext * ctx,char * base,char * hostaddr,char * device,char * community)1675307Sjacobs add_network_printer(LibHalContext *ctx, char *base, char *hostaddr,
1685307Sjacobs 		char *device, char *community)
1695307Sjacobs {
1705307Sjacobs 	DBusError error;
1715307Sjacobs 	int rc = -1;
1725307Sjacobs 	char udi[128];
1735307Sjacobs 	char *tmp_udi = NULL;
1745307Sjacobs 	static char *parent = NULL;
1755307Sjacobs 	char *manufacturer = NULL, *model = NULL, *description = NULL,
1765307Sjacobs 	     *uri = NULL, *sn, *serial;
1775307Sjacobs 
1785307Sjacobs 	sn = serial = pseudo_serialno_from_addr(hostaddr);
1795307Sjacobs 
1805307Sjacobs 	if (parent == NULL)
1815307Sjacobs 		parent = getenv("UDI");
1825307Sjacobs 
1835307Sjacobs 	dbus_error_init(&error);
1845307Sjacobs 
1855307Sjacobs 	network_device_name_to_udi(udi, sizeof (udi), base, serial, NULL);
1865307Sjacobs 
1875307Sjacobs 	if (libhal_device_exists(ctx, udi, &error) == TRUE)
1885307Sjacobs 		goto out;
1895307Sjacobs 
1905307Sjacobs 	if ((tmp_udi = libhal_new_device(ctx, &error)) == NULL)
1915307Sjacobs 		goto out;
1925307Sjacobs 
1935307Sjacobs 	snmp_printer_info(hostaddr, community, &manufacturer, &model,
1945307Sjacobs 			&description, &serial, NULL, &uri);
1955307Sjacobs 
1965307Sjacobs 	libhal_device_set_property_string(ctx, tmp_udi,
1975307Sjacobs 			"info.parent", parent, &error);
1985307Sjacobs 
1995307Sjacobs 	libhal_device_set_property_string(ctx, tmp_udi,
2005307Sjacobs 			"info.category", "printer", &error);
2015307Sjacobs 
2025307Sjacobs 	libhal_device_property_strlist_append(ctx, tmp_udi,
2035307Sjacobs 				"info.capabilities", "printer", &error);
2045307Sjacobs 	libhal_device_property_strlist_append(ctx, tmp_udi,
2055307Sjacobs 				"info.capabilities", "network_device", &error);
2065307Sjacobs 
2075307Sjacobs 	libhal_device_set_property_string(ctx, tmp_udi,
2085307Sjacobs 			"network_device.address", hostaddr, &error);
2095307Sjacobs 
2105307Sjacobs 	if ((community != NULL) && (strcasecmp(community, "public") != 0))
2115307Sjacobs 		libhal_device_set_property_string(ctx, tmp_udi,
2125307Sjacobs 			"network_device.snmp_community", community, &error);
2135307Sjacobs 
2145307Sjacobs 	if ((uri != NULL) || (device != NULL))
2155307Sjacobs 		libhal_device_set_property_string(ctx, tmp_udi,
2165307Sjacobs 			"printer.device", (uri ? uri : device), &error);
2175307Sjacobs 
2185307Sjacobs 	if (serial != NULL)
2195307Sjacobs 		libhal_device_set_property_string(ctx, tmp_udi,
2205307Sjacobs 			"printer.serial", serial, &error);
2215307Sjacobs 
2225307Sjacobs 	if (manufacturer != NULL)
2235307Sjacobs 		libhal_device_set_property_string(ctx, tmp_udi,
2245307Sjacobs 			"printer.vendor", manufacturer, &error);
2255307Sjacobs 
2265307Sjacobs 	if (model != NULL)
2275307Sjacobs 		libhal_device_set_property_string(ctx, tmp_udi,
2285307Sjacobs 			"printer.product", model, &error);
2295307Sjacobs 
2305307Sjacobs 	if (description != NULL)
2315307Sjacobs 		libhal_device_set_property_string(ctx, tmp_udi,
2325307Sjacobs 			"printer.description", description, &error);
2335307Sjacobs 
2345307Sjacobs 	/* commit the changes to the new UDI */
2355307Sjacobs 	rc = libhal_device_commit_to_gdl(ctx, tmp_udi, udi, &error);
2365307Sjacobs 
2375307Sjacobs out:
2385307Sjacobs 	HAL_DEBUG(("result: %s (%s): %s, %s, %s, %s, %s", hostaddr, udi,
2395307Sjacobs 		NP(manufacturer), NP(model), NP(description), NP(serial),
2405307Sjacobs 		NP(uri)));
2415307Sjacobs 
2425307Sjacobs 	if (tmp_udi != NULL)
2435307Sjacobs 		free(tmp_udi);
2445307Sjacobs 	if (manufacturer != NULL)
2455307Sjacobs 		free(manufacturer);
2465307Sjacobs 	if (model != NULL)
2475307Sjacobs 		free(model);
2485307Sjacobs 	if (description != NULL)
2495307Sjacobs 		free(description);
2505307Sjacobs 	if (uri != NULL)
2515307Sjacobs 		free(uri);
2525307Sjacobs 	if (sn != NULL)
2535307Sjacobs 		free(sn);
2545307Sjacobs 
2555307Sjacobs 	if (dbus_error_is_set(&error)) {
2565307Sjacobs 		HAL_WARNING(("%s: %s", error.name, error.message));
2575307Sjacobs 		dbus_error_free(&error);
2585307Sjacobs 	}
2595307Sjacobs 
2605307Sjacobs 	HAL_DEBUG(("add: %s (%s)", hostaddr, udi));
2615307Sjacobs 
2625307Sjacobs 	return (rc);
2635307Sjacobs }
2645307Sjacobs 
2655307Sjacobs static int
number_of_interfaces(int s)2665307Sjacobs number_of_interfaces(int s)
2675307Sjacobs {
2685307Sjacobs 	int rc = -1;
2695307Sjacobs 	struct lifnum n;
2705307Sjacobs 
2715307Sjacobs 	memset(&n, 0 , sizeof (n));
272*12395SLin.Guo@Sun.COM 	n.lifn_family = AF_INET;
2735307Sjacobs 	if (ioctl(s, SIOCGLIFNUM, (char *)&n) == 0)
2745307Sjacobs 		rc = n.lifn_count;
2755307Sjacobs 
2765307Sjacobs 	return (rc);
2775307Sjacobs }
2785307Sjacobs 
2795307Sjacobs static char *
broadcast_address(int s,char * ifname)2805307Sjacobs broadcast_address(int s, char *ifname)
2815307Sjacobs {
2825307Sjacobs 	char *result = NULL;
2835307Sjacobs 	struct lifreq r;
2845307Sjacobs 
2855307Sjacobs 	memset(&r, 0, sizeof (r));
286*12395SLin.Guo@Sun.COM 	strlcpy(r.lifr_name, ifname, sizeof (r.lifr_name));
287*12395SLin.Guo@Sun.COM 	if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&r) < 0) {
288*12395SLin.Guo@Sun.COM 		HAL_DEBUG(("broadcast_address: ioctl(SIOCGLIFFLAGS) failed."));
289*12395SLin.Guo@Sun.COM 		return (NULL);
290*12395SLin.Guo@Sun.COM 	}
291*12395SLin.Guo@Sun.COM 	if ((r.lifr_flags & (IFF_UP | IFF_LOOPBACK)) != IFF_UP) {
292*12395SLin.Guo@Sun.COM 		return (NULL);
293*12395SLin.Guo@Sun.COM 	}
294*12395SLin.Guo@Sun.COM 	if (ioctl(s, SIOCGLIFBRDADDR, (char *)&r) >= 0) {
295*12395SLin.Guo@Sun.COM 		char buf[INET_ADDRSTRLEN];
296*12395SLin.Guo@Sun.COM 		struct sockaddr_in *s =
297*12395SLin.Guo@Sun.COM 		    (struct sockaddr_in *)&r.lifr_broadaddr;
298*12395SLin.Guo@Sun.COM 		result = (char *)inet_ntop(AF_INET,
299*12395SLin.Guo@Sun.COM 		    &s->sin_addr, buf, sizeof (buf));
3005307Sjacobs 		if (result != NULL)
3015307Sjacobs 			result = strdup(result);
3025307Sjacobs 	}
3035307Sjacobs 
3045307Sjacobs 	return (result);
3055307Sjacobs }
3065307Sjacobs 
3075307Sjacobs GList *
broadcast_addresses()3085307Sjacobs broadcast_addresses()
3095307Sjacobs {
3105307Sjacobs 	GList *result = NULL;
3115307Sjacobs 	int s;
3125307Sjacobs 	struct lifconf c;
3135307Sjacobs 	int count;
3145307Sjacobs 
3155307Sjacobs 	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
3165307Sjacobs 		return (NULL);
3175307Sjacobs 
3185307Sjacobs 	count = number_of_interfaces(s);
3195307Sjacobs 
3205307Sjacobs 	memset(&c, 0, sizeof (c));
321*12395SLin.Guo@Sun.COM 	c.lifc_family = AF_INET;
322*12395SLin.Guo@Sun.COM 	c.lifc_flags = 0;
3235307Sjacobs 	c.lifc_buf = calloc(count, sizeof (struct lifreq));
3245307Sjacobs 	c.lifc_len = (count * sizeof (struct lifreq));
3255307Sjacobs 
3265307Sjacobs 	if (ioctl(s, SIOCGLIFCONF, (char *)&c) == 0) {
3275307Sjacobs 		struct lifreq *r = c.lifc_req;
3285307Sjacobs 
3295307Sjacobs 		for (count = c.lifc_len / sizeof (struct lifreq);
3305307Sjacobs 		     count > 0; count--, r++) {
3315307Sjacobs 			char *address = broadcast_address(s, r->lifr_name);
3325307Sjacobs 
3335307Sjacobs 			if (address != NULL) /* add it to the list */
3345307Sjacobs 				result = g_list_append(result, address);
3355307Sjacobs 		}
3365307Sjacobs 	}
3375307Sjacobs 	free(c.lifc_buf);
3385307Sjacobs 	close(s);
3395307Sjacobs 
3405307Sjacobs 	return (result);
3415307Sjacobs }
342