]> git.ipfire.org Git - thirdparty/lldpd.git/blob - src/daemon/interfaces-solaris.c
0f9f5e5380102195170ac130eb24d0d9df12132e
[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,
33 struct interfaces_device_list *interfaces,
34 struct interfaces_address_list *addresses,
35 struct lifreq *lifr) {
36 int flags = 0;
37 int index = 0;
38 struct interfaces_address *address = NULL;
39 struct interfaces_device *device = NULL;
40
41 sa_family_t lifr_af = lifr->lifr_addr.ss_family;
42 struct lifreq lifrl = { .lifr_name = {} };
43 strlcpy(lifrl.lifr_name, lifr->lifr_name, sizeof(lifrl.lifr_name));
44
45 /* Flags */
46 if (ioctl(cfg->g_sock, SIOCGLIFFLAGS, (caddr_t)&lifrl) < 0) {
47 log_warn("interfaces", "unable to get flags for %s",
48 lifrl.lifr_name);
49 return;
50 }
51 flags = lifrl.lifr_flags;
52
53 /* Index */
54 if (ioctl(cfg->g_sock, SIOCGLIFINDEX, (caddr_t)&lifrl) < 0) {
55 log_warn("interfaces", "unable to get index for %s",
56 lifrl.lifr_name);
57 return;
58 }
59 index = lifrl.lifr_index;
60
61 /* Record the address */
62 if ((address = malloc(sizeof(struct interfaces_address))) == NULL) {
63 log_warn("interfaces",
64 "not enough memory for a new IP address on %s",
65 lifrl.lifr_name);
66 return;
67 }
68 address->flags = flags;
69 address->index = index;
70 memcpy(&address->address,
71 &lifr->lifr_addr,
72 (lifr_af == AF_INET)?
73 sizeof(struct sockaddr_in):
74 sizeof(struct sockaddr_in6));
75 TAILQ_INSERT_TAIL(addresses, address, next);
76
77 /* Hardware address */
78 if (ioctl(cfg->g_sock, SIOCGLIFHWADDR, (caddr_t)&lifrl) < 0) {
79 log_debug("interfaces", "unable to get hardware address for %s",
80 lifrl.lifr_name);
81 return;
82 }
83 struct sockaddr_dl *saddrdl = (struct sockaddr_dl*)&lifrl.lifr_addr;
84 if (saddrdl->sdl_type != 4) {
85 log_debug("interfaces", "skip %s: not an ethernet device (%d)",
86 lifrl.lifr_name, saddrdl->sdl_type);
87 return;
88 }
89
90 /* Handle the interface */
91 if ((device = calloc(1, sizeof(struct interfaces_device))) == NULL) {
92 log_warn("interfaces", "unable to allocate memory for %s",
93 lifrl.lifr_name);
94 return;
95 }
96
97 device->name = strdup(lifrl.lifr_name);
98 device->flags = flags;
99 device->index = index;
100 device->type = IFACE_PHYSICAL_T;
101 device->address = malloc(ETHER_ADDR_LEN);
102 if (device->address)
103 memcpy(device->address, LLADDR(saddrdl), ETHER_ADDR_LEN);
104
105 /* MTU */
106 if (ioctl(cfg->g_sock, SIOCGLIFMTU, (caddr_t)&lifrl) < 0) {
107 log_debug("interfaces", "unable to get MTU for %s",
108 lifrl.lifr_name);
109 } else device->mtu = lifrl.lifr_mtu;
110
111 TAILQ_INSERT_TAIL(interfaces, device, next);
112 }
113
114 extern struct lldpd_ops bpf_ops;
115 void
116 interfaces_update(struct lldpd *cfg) {
117 struct lldpd_hardware *hardware;
118 caddr_t buffer = NULL;
119 struct interfaces_device_list *interfaces;
120 struct interfaces_address_list *addresses;
121 interfaces = malloc(sizeof(struct interfaces_device_list));
122 addresses = malloc(sizeof(struct interfaces_address_list));
123 if (interfaces == NULL || addresses == NULL) {
124 log_warnx("interfaces", "unable to allocate memory");
125 goto end;
126 }
127 TAILQ_INIT(interfaces);
128 TAILQ_INIT(addresses);
129
130 struct lifnum lifn = {
131 .lifn_family = AF_UNSPEC,
132 .lifn_flags = LIFC_ENABLED
133 };
134 if (ioctl(cfg->g_sock, SIOCGLIFNUM, &lifn) < 0) {
135 log_warn("interfaces", "unable to get the number of interfaces");
136 goto end;
137 }
138
139 size_t bufsize = lifn.lifn_count * sizeof(struct lifreq);
140 if ((buffer = malloc(bufsize)) == NULL) {
141 log_warn("interfaces", "unable to allocate buffer to get interfaces");
142 goto end;
143 }
144
145 struct lifconf lifc = {
146 .lifc_family = AF_UNSPEC,
147 .lifc_flags = LIFC_ENABLED,
148 .lifc_len = bufsize,
149 .lifc_buf = buffer
150 };
151 if (ioctl(cfg->g_sock, SIOCGLIFCONF, (char *)&lifc) < 0) {
152 log_warn("interfaces", "unable to get the network interfaces");
153 goto end;
154 }
155
156 int num = lifc.lifc_len / sizeof (struct lifreq);
157 if (num > lifn.lifn_count) num = lifn.lifn_count;
158 log_debug("interfaces", "got %d interfaces", num);
159
160 struct lifreq *lifrp = (struct lifreq *)buffer;
161 for (int n = 0; n < num; n++, lifrp++)
162 ifsolaris_extract(cfg, interfaces, addresses, lifrp);
163
164 interfaces_helper_whitelist(cfg, interfaces);
165 interfaces_helper_physical(cfg, interfaces,
166 &bpf_ops, ifbpf_phys_init);
167 interfaces_helper_mgmt(cfg, addresses);
168 interfaces_helper_chassis(cfg, interfaces);
169
170 /* Mac/PHY */
171 TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
172 if (!hardware->h_flags) continue;
173 /* TODO: mac/phy for Solaris */
174 interfaces_helper_promisc(cfg, hardware);
175 }
176
177 end:
178 free(buffer);
179 interfaces_free_devices(interfaces);
180 interfaces_free_addresses(addresses);
181 }
182
183 void
184 interfaces_cleanup(struct lldpd *cfg)
185 {
186 }