1*5307Sjacobs /* 2*5307Sjacobs * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 3*5307Sjacobs * Use is subject to license terms. 4*5307Sjacobs * 5*5307Sjacobs * Licensed under the Academic Free License version 2.1 6*5307Sjacobs */ 7*5307Sjacobs 8*5307Sjacobs #pragma ident "%Z%%M% %I% %E% SMI" 9*5307Sjacobs 10*5307Sjacobs #include <stdio.h> 11*5307Sjacobs #include <stdlib.h> 12*5307Sjacobs #include <unistd.h> 13*5307Sjacobs #include <signal.h> 14*5307Sjacobs #include <string.h> 15*5307Sjacobs #include <sys/types.h> 16*5307Sjacobs #include <sys/socket.h> 17*5307Sjacobs #include <sys/ioctl.h> 18*5307Sjacobs #include <sys/sockio.h> 19*5307Sjacobs #include <net/if.h> 20*5307Sjacobs #include <net/if_arp.h> 21*5307Sjacobs #include <netinet/in.h> 22*5307Sjacobs #include <arpa/inet.h> 23*5307Sjacobs #include <netdb.h> 24*5307Sjacobs 25*5307Sjacobs #include <libhal.h> 26*5307Sjacobs #include <logger.h> 27*5307Sjacobs 28*5307Sjacobs #include <glib.h> 29*5307Sjacobs 30*5307Sjacobs #include "network-discovery.h" 31*5307Sjacobs #define NP(x) (x?x:"NULL") 32*5307Sjacobs 33*5307Sjacobs extern int snmp_printer_info(char *hostname, char *community, 34*5307Sjacobs char **manufacturer, char **model, char **description, 35*5307Sjacobs char **serial_no, char ***command_set, char **uri); 36*5307Sjacobs 37*5307Sjacobs void 38*5307Sjacobs network_device_name_to_udi(char *udi, size_t size, ...) 39*5307Sjacobs { 40*5307Sjacobs va_list ap; 41*5307Sjacobs char *element; 42*5307Sjacobs int i; 43*5307Sjacobs 44*5307Sjacobs udi[0] = '\0'; 45*5307Sjacobs va_start(ap, size); 46*5307Sjacobs while ((element = va_arg(ap, char *)) != NULL) { 47*5307Sjacobs if (element[0] != '/') 48*5307Sjacobs strlcat(udi, "/", size); 49*5307Sjacobs strlcat(udi, element, size); 50*5307Sjacobs } 51*5307Sjacobs va_end(ap); 52*5307Sjacobs 53*5307Sjacobs for (i = 0; udi[i] != NULL; i++) 54*5307Sjacobs if (udi[i] == '.') 55*5307Sjacobs udi[i] = '_'; 56*5307Sjacobs } 57*5307Sjacobs 58*5307Sjacobs static void nop(int sig) {} 59*5307Sjacobs 60*5307Sjacobs static int 61*5307Sjacobs test_socket_access(struct in6_addr *addr, int port) 62*5307Sjacobs { 63*5307Sjacobs int sd, rc; 64*5307Sjacobs struct sockaddr_in6 sin6; 65*5307Sjacobs void (*hndlr)(int); 66*5307Sjacobs 67*5307Sjacobs memset(&sin6, 0, sizeof (sin6)); 68*5307Sjacobs sin6.sin6_family = AF_INET6; 69*5307Sjacobs memcpy(&sin6.sin6_addr, addr, sizeof (*addr)); 70*5307Sjacobs sin6.sin6_port = htons(port); 71*5307Sjacobs 72*5307Sjacobs sd = socket(AF_INET6, SOCK_STREAM, 0); 73*5307Sjacobs hndlr = signal(SIGALRM, nop); 74*5307Sjacobs alarm(1); 75*5307Sjacobs rc = connect(sd, (struct sockaddr *)&sin6, sizeof (sin6)); 76*5307Sjacobs alarm(0); 77*5307Sjacobs if (hndlr != NULL) 78*5307Sjacobs signal(SIGALRM, hndlr); 79*5307Sjacobs close(sd); 80*5307Sjacobs 81*5307Sjacobs return ((rc < 0) ? 1 : 0); 82*5307Sjacobs } 83*5307Sjacobs 84*5307Sjacobs int 85*5307Sjacobs is_listening(char *hostname, int port) 86*5307Sjacobs { 87*5307Sjacobs char *uri = NULL, addr_string[INET6_ADDRSTRLEN]; 88*5307Sjacobs struct in6_addr ipv6addr[1]; 89*5307Sjacobs int errnum; 90*5307Sjacobs struct hostent *hp; 91*5307Sjacobs 92*5307Sjacobs hp = getipnodebyname(hostname, AF_INET6, 93*5307Sjacobs AI_ALL | AI_ADDRCONFIG | AI_V4MAPPED, &errnum); 94*5307Sjacobs if (hp != NULL) { 95*5307Sjacobs (void) memcpy(&ipv6addr, hp->h_addr_list[0], hp->h_length); 96*5307Sjacobs } else 97*5307Sjacobs return (-1); 98*5307Sjacobs 99*5307Sjacobs return (test_socket_access(ipv6addr, port)); 100*5307Sjacobs } 101*5307Sjacobs 102*5307Sjacobs static char * 103*5307Sjacobs addr_to_string(char *prefix, uchar_t *mac, int mac_len, char *buf, int buf_len) 104*5307Sjacobs { 105*5307Sjacobs int i, n = 0; 106*5307Sjacobs 107*5307Sjacobs buf[0] = '\0'; 108*5307Sjacobs if (prefix != NULL) 109*5307Sjacobs n = sprintf(buf, prefix); 110*5307Sjacobs for (i = 0; ((i < (mac_len)) && (n < buf_len)); i++) 111*5307Sjacobs n += sprintf(buf + n, "%2.2X", *mac++); 112*5307Sjacobs 113*5307Sjacobs return (buf); 114*5307Sjacobs } 115*5307Sjacobs 116*5307Sjacobs static char * 117*5307Sjacobs pseudo_serialno_from_addr(char *name) 118*5307Sjacobs { 119*5307Sjacobs int sd, rc, errnum; 120*5307Sjacobs char buf[128]; 121*5307Sjacobs struct hostent *hp; 122*5307Sjacobs struct xarpreq ar; 123*5307Sjacobs 124*5307Sjacobs if (name == NULL) 125*5307Sjacobs return (NULL); 126*5307Sjacobs 127*5307Sjacobs memset(&ar, 0, sizeof (ar)); 128*5307Sjacobs 129*5307Sjacobs hp = getipnodebyname(name, AF_INET6, AI_ADDRCONFIG, &errnum); 130*5307Sjacobs if (hp != NULL) { 131*5307Sjacobs struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ar.xarp_pa; 132*5307Sjacobs 133*5307Sjacobs sin6->sin6_family = AF_INET6; 134*5307Sjacobs (void) memcpy(&sin6->sin6_addr, hp->h_addr_list[0], 135*5307Sjacobs hp->h_length); 136*5307Sjacobs } else { 137*5307Sjacobs struct sockaddr_in *sin = (struct sockaddr_in *)&ar.xarp_pa; 138*5307Sjacobs 139*5307Sjacobs sin->sin_family = AF_INET; 140*5307Sjacobs sin->sin_addr.s_addr = inet_addr(name); 141*5307Sjacobs } 142*5307Sjacobs 143*5307Sjacobs sd = socket(AF_INET, SOCK_DGRAM, 0); 144*5307Sjacobs 145*5307Sjacobs ar.xarp_ha.sdl_family = AF_LINK; 146*5307Sjacobs rc = ioctl(sd, SIOCGXARP, (caddr_t)&ar); 147*5307Sjacobs 148*5307Sjacobs close(sd); 149*5307Sjacobs 150*5307Sjacobs if (ar.xarp_flags & ATF_COM) { /* use the MAC address */ 151*5307Sjacobs uchar_t *ea = (uchar_t *)LLADDR(&ar.xarp_ha); 152*5307Sjacobs 153*5307Sjacobs addr_to_string("LLADDR-", ea, ar.xarp_ha.sdl_alen, 154*5307Sjacobs buf, sizeof (buf)); 155*5307Sjacobs 156*5307Sjacobs } else if (hp != NULL) { /* use the IPv6 address */ 157*5307Sjacobs addr_to_string("IPV6ADDR-", (uchar_t *)&hp->h_addr_list[0], 158*5307Sjacobs hp->h_length, buf, sizeof (buf)); 159*5307Sjacobs } else { /* use the IPv4 address */ 160*5307Sjacobs struct sockaddr_in *sin = (struct sockaddr_in *)&ar.xarp_pa; 161*5307Sjacobs 162*5307Sjacobs addr_to_string("IPV4ADDR-", (uchar_t *)&sin->sin_addr.s_addr, 4, 163*5307Sjacobs buf, sizeof (buf)); 164*5307Sjacobs } 165*5307Sjacobs 166*5307Sjacobs return (strdup(buf)); 167*5307Sjacobs } 168*5307Sjacobs 169*5307Sjacobs int 170*5307Sjacobs add_network_printer(LibHalContext *ctx, char *base, char *hostaddr, 171*5307Sjacobs char *device, char *community) 172*5307Sjacobs { 173*5307Sjacobs DBusError error; 174*5307Sjacobs int rc = -1; 175*5307Sjacobs char udi[128]; 176*5307Sjacobs char *tmp_udi = NULL; 177*5307Sjacobs static char *parent = NULL; 178*5307Sjacobs char *manufacturer = NULL, *model = NULL, *description = NULL, 179*5307Sjacobs *uri = NULL, *sn, *serial; 180*5307Sjacobs 181*5307Sjacobs sn = serial = pseudo_serialno_from_addr(hostaddr); 182*5307Sjacobs 183*5307Sjacobs if (parent == NULL) 184*5307Sjacobs parent = getenv("UDI"); 185*5307Sjacobs 186*5307Sjacobs dbus_error_init(&error); 187*5307Sjacobs 188*5307Sjacobs network_device_name_to_udi(udi, sizeof (udi), base, serial, NULL); 189*5307Sjacobs 190*5307Sjacobs if (libhal_device_exists(ctx, udi, &error) == TRUE) 191*5307Sjacobs goto out; 192*5307Sjacobs 193*5307Sjacobs if ((tmp_udi = libhal_new_device(ctx, &error)) == NULL) 194*5307Sjacobs goto out; 195*5307Sjacobs 196*5307Sjacobs snmp_printer_info(hostaddr, community, &manufacturer, &model, 197*5307Sjacobs &description, &serial, NULL, &uri); 198*5307Sjacobs 199*5307Sjacobs libhal_device_set_property_string(ctx, tmp_udi, 200*5307Sjacobs "info.parent", parent, &error); 201*5307Sjacobs 202*5307Sjacobs libhal_device_set_property_string(ctx, tmp_udi, 203*5307Sjacobs "info.category", "printer", &error); 204*5307Sjacobs 205*5307Sjacobs libhal_device_property_strlist_append(ctx, tmp_udi, 206*5307Sjacobs "info.capabilities", "printer", &error); 207*5307Sjacobs libhal_device_property_strlist_append(ctx, tmp_udi, 208*5307Sjacobs "info.capabilities", "network_device", &error); 209*5307Sjacobs 210*5307Sjacobs libhal_device_set_property_string(ctx, tmp_udi, 211*5307Sjacobs "network_device.address", hostaddr, &error); 212*5307Sjacobs 213*5307Sjacobs if ((community != NULL) && (strcasecmp(community, "public") != 0)) 214*5307Sjacobs libhal_device_set_property_string(ctx, tmp_udi, 215*5307Sjacobs "network_device.snmp_community", community, &error); 216*5307Sjacobs 217*5307Sjacobs if ((uri != NULL) || (device != NULL)) 218*5307Sjacobs libhal_device_set_property_string(ctx, tmp_udi, 219*5307Sjacobs "printer.device", (uri ? uri : device), &error); 220*5307Sjacobs 221*5307Sjacobs if (serial != NULL) 222*5307Sjacobs libhal_device_set_property_string(ctx, tmp_udi, 223*5307Sjacobs "printer.serial", serial, &error); 224*5307Sjacobs 225*5307Sjacobs if (manufacturer != NULL) 226*5307Sjacobs libhal_device_set_property_string(ctx, tmp_udi, 227*5307Sjacobs "printer.vendor", manufacturer, &error); 228*5307Sjacobs 229*5307Sjacobs if (model != NULL) 230*5307Sjacobs libhal_device_set_property_string(ctx, tmp_udi, 231*5307Sjacobs "printer.product", model, &error); 232*5307Sjacobs 233*5307Sjacobs if (description != NULL) 234*5307Sjacobs libhal_device_set_property_string(ctx, tmp_udi, 235*5307Sjacobs "printer.description", description, &error); 236*5307Sjacobs 237*5307Sjacobs /* commit the changes to the new UDI */ 238*5307Sjacobs rc = libhal_device_commit_to_gdl(ctx, tmp_udi, udi, &error); 239*5307Sjacobs 240*5307Sjacobs out: 241*5307Sjacobs HAL_DEBUG(("result: %s (%s): %s, %s, %s, %s, %s", hostaddr, udi, 242*5307Sjacobs NP(manufacturer), NP(model), NP(description), NP(serial), 243*5307Sjacobs NP(uri))); 244*5307Sjacobs 245*5307Sjacobs if (tmp_udi != NULL) 246*5307Sjacobs free(tmp_udi); 247*5307Sjacobs if (manufacturer != NULL) 248*5307Sjacobs free(manufacturer); 249*5307Sjacobs if (model != NULL) 250*5307Sjacobs free(model); 251*5307Sjacobs if (description != NULL) 252*5307Sjacobs free(description); 253*5307Sjacobs if (uri != NULL) 254*5307Sjacobs free(uri); 255*5307Sjacobs if (sn != NULL) 256*5307Sjacobs free(sn); 257*5307Sjacobs 258*5307Sjacobs if (dbus_error_is_set(&error)) { 259*5307Sjacobs HAL_WARNING(("%s: %s", error.name, error.message)); 260*5307Sjacobs dbus_error_free(&error); 261*5307Sjacobs } 262*5307Sjacobs 263*5307Sjacobs HAL_DEBUG(("add: %s (%s)", hostaddr, udi)); 264*5307Sjacobs 265*5307Sjacobs return (rc); 266*5307Sjacobs } 267*5307Sjacobs 268*5307Sjacobs static int 269*5307Sjacobs number_of_interfaces(int s) 270*5307Sjacobs { 271*5307Sjacobs int rc = -1; 272*5307Sjacobs struct lifnum n; 273*5307Sjacobs 274*5307Sjacobs memset(&n, 0 , sizeof (n)); 275*5307Sjacobs n.lifn_family = AF_UNSPEC; 276*5307Sjacobs if (ioctl(s, SIOCGLIFNUM, (char *)&n) == 0) 277*5307Sjacobs rc = n.lifn_count; 278*5307Sjacobs 279*5307Sjacobs return (rc); 280*5307Sjacobs } 281*5307Sjacobs 282*5307Sjacobs static char * 283*5307Sjacobs broadcast_address(int s, char *ifname) 284*5307Sjacobs { 285*5307Sjacobs char *result = NULL; 286*5307Sjacobs struct lifreq r; 287*5307Sjacobs 288*5307Sjacobs memset(&r, 0, sizeof (r)); 289*5307Sjacobs strncpy((char *)&r.lifr_name, ifname, sizeof (r.lifr_name)); 290*5307Sjacobs if (ioctl(s, SIOCGLIFBRDADDR, (char *)&r) == 0) { 291*5307Sjacobs char buf[INET6_ADDRSTRLEN]; 292*5307Sjacobs 293*5307Sjacobs switch (r.lifr_broadaddr.ss_family) { 294*5307Sjacobs case AF_INET: { 295*5307Sjacobs struct sockaddr_in *s = 296*5307Sjacobs (struct sockaddr_in *)&r.lifr_broadaddr; 297*5307Sjacobs result = (char *)inet_ntop(AF_INET, &s->sin_addr, 298*5307Sjacobs buf, sizeof (buf)); 299*5307Sjacobs } 300*5307Sjacobs break; 301*5307Sjacobs case AF_INET6: { 302*5307Sjacobs struct sockaddr_in6 *s = 303*5307Sjacobs (struct sockaddr_in6 *)&r.lifr_broadaddr; 304*5307Sjacobs result = (char *)inet_ntop(AF_INET6, &s->sin6_addr, 305*5307Sjacobs buf, sizeof (buf)); 306*5307Sjacobs } 307*5307Sjacobs break; 308*5307Sjacobs } 309*5307Sjacobs 310*5307Sjacobs if (result != NULL) 311*5307Sjacobs result = strdup(result); 312*5307Sjacobs } 313*5307Sjacobs 314*5307Sjacobs return (result); 315*5307Sjacobs } 316*5307Sjacobs 317*5307Sjacobs GList * 318*5307Sjacobs broadcast_addresses() 319*5307Sjacobs { 320*5307Sjacobs GList *result = NULL; 321*5307Sjacobs int s; 322*5307Sjacobs struct lifconf c; 323*5307Sjacobs int count; 324*5307Sjacobs 325*5307Sjacobs if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 326*5307Sjacobs return (NULL); 327*5307Sjacobs 328*5307Sjacobs count = number_of_interfaces(s); 329*5307Sjacobs 330*5307Sjacobs memset(&c, 0, sizeof (c)); 331*5307Sjacobs c.lifc_family = AF_UNSPEC; 332*5307Sjacobs c.lifc_flags = IFF_BROADCAST; 333*5307Sjacobs c.lifc_buf = calloc(count, sizeof (struct lifreq)); 334*5307Sjacobs c.lifc_len = (count * sizeof (struct lifreq)); 335*5307Sjacobs 336*5307Sjacobs if (ioctl(s, SIOCGLIFCONF, (char *)&c) == 0) { 337*5307Sjacobs struct lifreq *r = c.lifc_req; 338*5307Sjacobs 339*5307Sjacobs for (count = c.lifc_len / sizeof (struct lifreq); 340*5307Sjacobs count > 0; count--, r++) { 341*5307Sjacobs char *address = broadcast_address(s, r->lifr_name); 342*5307Sjacobs 343*5307Sjacobs if (address != NULL) /* add it to the list */ 344*5307Sjacobs result = g_list_append(result, address); 345*5307Sjacobs } 346*5307Sjacobs } 347*5307Sjacobs free(c.lifc_buf); 348*5307Sjacobs close(s); 349*5307Sjacobs 350*5307Sjacobs return (result); 351*5307Sjacobs } 352