]> git.ipfire.org Git - thirdparty/lldpd.git/blob - src/daemon/interfaces-solaris.c
build: run cross-platforms test on ubuntu-latest
[thirdparty/lldpd.git] / src / daemon / interfaces-solaris.c
1 /* -*- mode: c; c-file-style: "openbsd" -*- */
2 /*
3 * Copyright (c) 2013 Vincent Bernat <bernat@luffy.cx>
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #include "lldpd.h"
19
20 #include <unistd.h>
21 #include <sys/sockio.h>
22 #include <net/if_types.h>
23
24 /* Solaris comes with libdladm which seems to be handy to get all the necessary
25 * information. Unfortunately, this library needs a special device file and a
26 * Unix socket to a daemon. This is a bit difficult to use it in a
27 * privilege-separated daemon. Therefore, we keep using ioctl(). This should
28 * also improve compatibility with older versions of Solaris.
29 */
30
31 static void
32 ifsolaris_extract(struct lldpd *cfg, struct interfaces_device_list *interfaces,
33 struct interfaces_address_list *addresses, struct lifreq *lifr)
34 {
35 int flags = 0;
36 int index = 0;
37 struct interfaces_address *address = NULL;
38 struct interfaces_device *device = NULL;
39
40 sa_family_t lifr_af = lifr->lifr_addr.ss_family;
41 struct lifreq lifrl = { .lifr_name = {} };
42 strlcpy(lifrl.lifr_name, lifr->lifr_name, sizeof(lifrl.lifr_name));
43
44 /* Flags */
45 if (ioctl(cfg->g_sock, SIOCGLIFFLAGS, (caddr_t)&lifrl) < 0) {
46 log_warn("interfaces", "unable to get flags for %s", lifrl.lifr_name);
47 return;
48 }
49 flags = lifrl.lifr_flags;
50
51 /* Index */
52 if (ioctl(cfg->g_sock, SIOCGLIFINDEX, (caddr_t)&lifrl) < 0) {
53 log_warn("interfaces", "unable to get index for %s", lifrl.lifr_name);
54 return;
55 }
56 index = lifrl.lifr_index;
57
58 /* Record the address */
59 if ((address = malloc(sizeof(struct interfaces_address))) == NULL) {
60 log_warn("interfaces", "not enough memory for a new IP address on %s",
61 lifrl.lifr_name);
62 return;
63 }
64 address->flags = flags;
65 address->index = index;
66 memcpy(&address->address, &lifr->lifr_addr,
67 (lifr_af == AF_INET) ? sizeof(struct sockaddr_in) :
68 sizeof(struct sockaddr_in6));
69 TAILQ_INSERT_TAIL(addresses, address, next);
70
71 /* Hardware address */
72 if (ioctl(cfg->g_sock, SIOCGLIFHWADDR, (caddr_t)&lifrl) < 0) {
73 log_debug("interfaces", "unable to get hardware address for %s",
74 lifrl.lifr_name);
75 return;
76 }
77 struct sockaddr_dl *saddrdl = (struct sockaddr_dl *)&lifrl.lifr_addr;
78 if (saddrdl->sdl_type != 4) {
79 log_debug("interfaces", "skip %s: not an ethernet device (%d)",
80 lifrl.lifr_name, saddrdl->sdl_type);
81 return;
82 }
83
84 /* Handle the interface */
85 if ((device = calloc(1, sizeof(struct interfaces_device))) == NULL) {
86 log_warn("interfaces", "unable to allocate memory for %s",
87 lifrl.lifr_name);
88 return;
89 }
90
91 device->name = strdup(lifrl.lifr_name);
92 device->flags = flags;
93 device->index = index;
94 device->type = IFACE_PHYSICAL_T;
95 device->address = malloc(ETHER_ADDR_LEN);
96 if (device->address) memcpy(device->address, LLADDR(saddrdl), ETHER_ADDR_LEN);
97
98 /* MTU */
99 if (ioctl(cfg->g_sock, SIOCGLIFMTU, (caddr_t)&lifrl) < 0) {
100 log_debug("interfaces", "unable to get MTU for %s", lifrl.lifr_name);
101 } else
102 device->mtu = lifrl.lifr_mtu;
103
104 TAILQ_INSERT_TAIL(interfaces, device, next);
105 }
106
107 extern struct lldpd_ops bpf_ops;
108 void
109 interfaces_update(struct lldpd *cfg)
110 {
111 struct lldpd_hardware *hardware;
112 caddr_t buffer = NULL;
113 struct interfaces_device_list *interfaces;
114 struct interfaces_address_list *addresses;
115 interfaces = malloc(sizeof(struct interfaces_device_list));
116 addresses = malloc(sizeof(struct interfaces_address_list));
117 if (interfaces == NULL || addresses == NULL) {
118 log_warnx("interfaces", "unable to allocate memory");
119 goto end;
120 }
121 TAILQ_INIT(interfaces);
122 TAILQ_INIT(addresses);
123
124 struct lifnum lifn = { .lifn_family = AF_UNSPEC, .lifn_flags = LIFC_ENABLED };
125 if (ioctl(cfg->g_sock, SIOCGLIFNUM, &lifn) < 0) {
126 log_warn("interfaces", "unable to get the number of interfaces");
127 goto end;
128 }
129
130 size_t bufsize = lifn.lifn_count * sizeof(struct lifreq);
131 if ((buffer = malloc(bufsize)) == NULL) {
132 log_warn("interfaces", "unable to allocate buffer to get interfaces");
133 goto end;
134 }
135
136 struct lifconf lifc = { .lifc_family = AF_UNSPEC,
137 .lifc_flags = LIFC_ENABLED,
138 .lifc_len = bufsize,
139 .lifc_buf = buffer };
140 if (ioctl(cfg->g_sock, SIOCGLIFCONF, (char *)&lifc) < 0) {
141 log_warn("interfaces", "unable to get the network interfaces");
142 goto end;
143 }
144
145 int num = lifc.lifc_len / sizeof(struct lifreq);
146 if (num > lifn.lifn_count) num = lifn.lifn_count;
147 log_debug("interfaces", "got %d interfaces", num);
148
149 struct lifreq *lifrp = (struct lifreq *)buffer;
150 for (int n = 0; n < num; n++, lifrp++)
151 ifsolaris_extract(cfg, interfaces, addresses, lifrp);
152
153 interfaces_helper_allowlist(cfg, interfaces);
154 interfaces_helper_physical(cfg, interfaces, &bpf_ops, ifbpf_phys_init);
155 interfaces_helper_mgmt(cfg, addresses, interfaces);
156 interfaces_helper_chassis(cfg, interfaces);
157
158 /* Mac/PHY */
159 TAILQ_FOREACH (hardware, &cfg->g_hardware, h_entries) {
160 if (!hardware->h_flags) continue;
161 /* TODO: mac/phy for Solaris */
162 interfaces_helper_promisc(cfg, hardware);
163 }
164
165 end:
166 free(buffer);
167 interfaces_free_devices(interfaces);
168 interfaces_free_addresses(addresses);
169 }
170
171 void
172 interfaces_cleanup(struct lldpd *cfg)
173 {
174 }