2 * Copyright 2017 Gary Mills
3 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
5 * Licensed under the Academic Free License version 2.1
13 #include <sys/types.h>
14 #include <sys/socket.h>
15 #include <sys/ioctl.h>
16 #include <sys/sockio.h>
18 #include <net/if_arp.h>
19 #include <netinet/in.h>
20 #include <arpa/inet.h>
28 #include "network-discovery.h"
29 #define NP(x) (x?x:"NULL")
31 extern int snmp_printer_info(char *hostname
, char *community
,
32 char **manufacturer
, char **model
, char **description
,
33 char **serial_no
, char ***command_set
, char **uri
);
36 network_device_name_to_udi(char *udi
, size_t size
, ...)
44 while ((element
= va_arg(ap
, char *)) != NULL
) {
45 if (element
[0] != '/')
46 strlcat(udi
, "/", size
);
47 strlcat(udi
, element
, size
);
51 for (i
= 0; udi
[i
] != '\0'; i
++)
56 static void nop(int sig
) {}
59 test_socket_access(struct in6_addr
*addr
, int port
)
62 struct sockaddr_in6 sin6
;
65 memset(&sin6
, 0, sizeof (sin6
));
66 sin6
.sin6_family
= AF_INET6
;
67 memcpy(&sin6
.sin6_addr
, addr
, sizeof (*addr
));
68 sin6
.sin6_port
= htons(port
);
70 sd
= socket(AF_INET6
, SOCK_STREAM
, 0);
71 hndlr
= signal(SIGALRM
, nop
);
73 rc
= connect(sd
, (struct sockaddr
*)&sin6
, sizeof (sin6
));
76 signal(SIGALRM
, hndlr
);
79 return ((rc
< 0) ? 1 : 0);
83 is_listening(char *hostname
, int port
)
85 char *uri
= NULL
, addr_string
[INET6_ADDRSTRLEN
];
86 struct in6_addr ipv6addr
[1];
90 hp
= getipnodebyname(hostname
, AF_INET6
,
91 AI_ALL
| AI_ADDRCONFIG
| AI_V4MAPPED
, &errnum
);
93 (void) memcpy(&ipv6addr
, hp
->h_addr_list
[0], hp
->h_length
);
97 return (test_socket_access(ipv6addr
, port
));
101 addr_to_string(char *prefix
, uchar_t
*mac
, int mac_len
, char *buf
, int buf_len
)
107 n
= sprintf(buf
, prefix
);
108 for (i
= 0; ((i
< (mac_len
)) && (n
< buf_len
)); i
++)
109 n
+= sprintf(buf
+ n
, "%2.2X", *mac
++);
115 pseudo_serialno_from_addr(char *name
)
125 memset(&ar
, 0, sizeof (ar
));
127 hp
= getipnodebyname(name
, AF_INET6
, AI_ADDRCONFIG
, &errnum
);
129 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)&ar
.xarp_pa
;
131 sin6
->sin6_family
= AF_INET6
;
132 (void) memcpy(&sin6
->sin6_addr
, hp
->h_addr_list
[0],
135 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&ar
.xarp_pa
;
137 sin
->sin_family
= AF_INET
;
138 sin
->sin_addr
.s_addr
= inet_addr(name
);
141 sd
= socket(AF_INET
, SOCK_DGRAM
, 0);
143 ar
.xarp_ha
.sdl_family
= AF_LINK
;
144 (void) ioctl(sd
, SIOCGXARP
, (caddr_t
)&ar
);
148 if (ar
.xarp_flags
& ATF_COM
) { /* use the MAC address */
149 uchar_t
*ea
= (uchar_t
*)LLADDR(&ar
.xarp_ha
);
151 addr_to_string("LLADDR-", ea
, ar
.xarp_ha
.sdl_alen
,
154 } else if (hp
!= NULL
) { /* use the IPv6 address */
155 addr_to_string("IPV6ADDR-", (uchar_t
*)&hp
->h_addr_list
[0],
156 hp
->h_length
, buf
, sizeof (buf
));
157 } else { /* use the IPv4 address */
158 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&ar
.xarp_pa
;
160 addr_to_string("IPV4ADDR-", (uchar_t
*)&sin
->sin_addr
.s_addr
, 4,
164 return (strdup(buf
));
168 add_network_printer(LibHalContext
*ctx
, char *base
, char *hostaddr
,
169 char *device
, char *community
)
174 char *tmp_udi
= NULL
;
175 static char *parent
= NULL
;
176 char *manufacturer
= NULL
, *model
= NULL
, *description
= NULL
,
177 *uri
= NULL
, *sn
, *serial
;
179 sn
= serial
= pseudo_serialno_from_addr(hostaddr
);
182 parent
= getenv("UDI");
184 dbus_error_init(&error
);
186 network_device_name_to_udi(udi
, sizeof (udi
), base
, serial
, NULL
);
188 if (libhal_device_exists(ctx
, udi
, &error
) == TRUE
)
191 if ((tmp_udi
= libhal_new_device(ctx
, &error
)) == NULL
)
194 snmp_printer_info(hostaddr
, community
, &manufacturer
, &model
,
195 &description
, &serial
, NULL
, &uri
);
197 libhal_device_set_property_string(ctx
, tmp_udi
,
198 "info.parent", parent
, &error
);
200 libhal_device_set_property_string(ctx
, tmp_udi
,
201 "info.category", "printer", &error
);
203 libhal_device_property_strlist_append(ctx
, tmp_udi
,
204 "info.capabilities", "printer", &error
);
205 libhal_device_property_strlist_append(ctx
, tmp_udi
,
206 "info.capabilities", "network_device", &error
);
208 libhal_device_set_property_string(ctx
, tmp_udi
,
209 "network_device.address", hostaddr
, &error
);
211 if ((community
!= NULL
) && (strcasecmp(community
, "public") != 0))
212 libhal_device_set_property_string(ctx
, tmp_udi
,
213 "network_device.snmp_community", community
, &error
);
215 if ((uri
!= NULL
) || (device
!= NULL
))
216 libhal_device_set_property_string(ctx
, tmp_udi
,
217 "printer.device", (uri
? uri
: device
), &error
);
220 libhal_device_set_property_string(ctx
, tmp_udi
,
221 "printer.serial", serial
, &error
);
223 if (manufacturer
!= NULL
)
224 libhal_device_set_property_string(ctx
, tmp_udi
,
225 "printer.vendor", manufacturer
, &error
);
228 libhal_device_set_property_string(ctx
, tmp_udi
,
229 "printer.product", model
, &error
);
231 if (description
!= NULL
)
232 libhal_device_set_property_string(ctx
, tmp_udi
,
233 "printer.description", description
, &error
);
235 /* commit the changes to the new UDI */
236 rc
= libhal_device_commit_to_gdl(ctx
, tmp_udi
, udi
, &error
);
239 HAL_DEBUG(("result: %s (%s): %s, %s, %s, %s, %s", hostaddr
, udi
,
240 NP(manufacturer
), NP(model
), NP(description
), NP(serial
),
250 if (dbus_error_is_set(&error
)) {
251 HAL_WARNING(("%s: %s", error
.name
, error
.message
));
252 dbus_error_free(&error
);
255 HAL_DEBUG(("add: %s (%s)", hostaddr
, udi
));
261 number_of_interfaces(int s
)
266 memset(&n
, 0 , sizeof (n
));
267 n
.lifn_family
= AF_INET
;
268 if (ioctl(s
, SIOCGLIFNUM
, (char *)&n
) == 0)
275 broadcast_address(int s
, char *ifname
)
280 memset(&r
, 0, sizeof (r
));
281 strlcpy(r
.lifr_name
, ifname
, sizeof (r
.lifr_name
));
282 if (ioctl(s
, SIOCGLIFFLAGS
, (caddr_t
)&r
) < 0) {
283 HAL_DEBUG(("broadcast_address: ioctl(SIOCGLIFFLAGS) failed."));
286 if ((r
.lifr_flags
& (IFF_UP
| IFF_LOOPBACK
)) != IFF_UP
) {
289 if (ioctl(s
, SIOCGLIFBRDADDR
, (char *)&r
) >= 0) {
290 char buf
[INET_ADDRSTRLEN
];
291 struct sockaddr_in
*s
=
292 (struct sockaddr_in
*)&r
.lifr_broadaddr
;
293 result
= (char *)inet_ntop(AF_INET
,
294 &s
->sin_addr
, buf
, sizeof (buf
));
296 result
= strdup(result
);
303 broadcast_addresses()
305 GList
*result
= NULL
;
310 if ((s
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0)
313 count
= number_of_interfaces(s
);
315 memset(&c
, 0, sizeof (c
));
316 c
.lifc_family
= AF_INET
;
318 c
.lifc_buf
= calloc(count
, sizeof (struct lifreq
));
319 c
.lifc_len
= (count
* sizeof (struct lifreq
));
321 if (ioctl(s
, SIOCGLIFCONF
, (char *)&c
) == 0) {
322 struct lifreq
*r
= c
.lifc_req
;
324 for (count
= c
.lifc_len
/ sizeof (struct lifreq
);
325 count
> 0; count
--, r
++) {
326 char *address
= broadcast_address(s
, r
->lifr_name
);
328 if (address
!= NULL
) /* add it to the list */
329 result
= g_list_append(result
, address
);