]> git.proxmox.com Git - mirror_frr.git/blame - zebra/ioctl_solaris.c
zebra: add 'is broadcast' accessor for interface data
[mirror_frr.git] / zebra / ioctl_solaris.c
CommitLineData
8842468c 1/*
2 * Common ioctl functions for Solaris.
3 * Copyright (C) 1997, 98 Kunihiro Ishiguro
4 *
5 * This file is part of GNU Zebra.
6 *
7 * GNU Zebra is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2, or (at your option) any
10 * later version.
11 *
12 * GNU Zebra is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
896014f4
DL
17 * You should have received a copy of the GNU General Public License along
18 * with this program; see the file COPYING; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
8842468c 20 */
21
22#include <zebra.h>
23
ddfeb486
DL
24#ifdef SUNOS_5
25
8842468c 26#include "linklist.h"
27#include "if.h"
28#include "prefix.h"
29#include "ioctl.h"
30#include "log.h"
48a46fa0 31#include "privs.h"
82283592 32#include "vty.h"
4db21619 33#include "vrf.h"
174482ef 34#include "lib_errors.h"
8842468c 35
36#include "zebra/rib.h"
37#include "zebra/rt.h"
5c78b3d0 38#include "zebra/interface.h"
8d610213 39#include "zebra/ioctl_solaris.h"
364fed6b 40#include "zebra/zebra_errors.h"
8842468c 41
48a46fa0 42extern struct zebra_privs_t zserv_privs;
8842468c 43
44/* clear and set interface name string */
d62a17ae 45void lifreq_set_name(struct lifreq *lifreq, const char *ifname)
8842468c 46{
138a4965 47 strlcpy(lifreq->lifr_name, ifname, sizeof(lifreq->lifr_name));
8842468c 48}
49
d7c0a89a 50int vrf_if_ioctl(unsigned long request, caddr_t buffer, vrf_id_t vrf_id)
4db21619
PG
51{
52 return if_ioctl(request, buffer);
53}
54
8842468c 55/* call ioctl system call */
d7c0a89a 56int if_ioctl(unsigned long request, caddr_t buffer)
8842468c 57{
d62a17ae 58 int sock;
59 int ret;
60 int err;
61
01b9e3fd
DL
62 frr_elevate_privs(&zserv_privs) {
63
64 sock = socket(AF_INET, SOCK_DGRAM, 0);
65 if (sock < 0) {
66 zlog_err("Cannot create UDP socket: %s",
67 safe_strerror(errno));
68 exit(1);
69 }
d62a17ae 70
01b9e3fd
DL
71 if ((ret = ioctl(sock, request, buffer)) < 0)
72 err = errno;
d62a17ae 73
01b9e3fd 74 }
d62a17ae 75
76 close(sock);
77
78 if (ret < 0) {
79 errno = err;
80 return ret;
81 }
82 return 0;
8842468c 83}
84
5b73a671 85
d7c0a89a 86int if_ioctl_ipv6(unsigned long request, caddr_t buffer)
8842468c 87{
d62a17ae 88 int sock;
89 int ret;
90 int err;
91
01b9e3fd
DL
92 frr_elevate_privs(&zserv_privs) {
93
94 sock = socket(AF_INET6, SOCK_DGRAM, 0);
95 if (sock < 0) {
96 zlog_err("Cannot create IPv6 datagram socket: %s",
97 safe_strerror(errno));
98 exit(1);
99 }
d62a17ae 100
01b9e3fd
DL
101 if ((ret = ioctl(sock, request, buffer)) < 0)
102 err = errno;
d62a17ae 103
01b9e3fd 104 }
d62a17ae 105
106 close(sock);
107
108 if (ret < 0) {
109 errno = err;
110 return ret;
111 }
112
113 return 0;
8842468c 114}
8842468c 115
116/*
117 * get interface metric
118 * -- if value is not avaliable set -1
119 */
d62a17ae 120void if_get_metric(struct interface *ifp)
8842468c 121{
d62a17ae 122 struct lifreq lifreq;
123 int ret;
8842468c 124
d62a17ae 125 lifreq_set_name(&lifreq, ifp->name);
8842468c 126
d62a17ae 127 if (ifp->flags & IFF_IPV4)
128 ret = AF_IOCTL(AF_INET, SIOCGLIFMETRIC, (caddr_t)&lifreq);
5b73a671 129#ifdef SOLARIS_IPV6
d62a17ae 130 else if (ifp->flags & IFF_IPV6)
131 ret = AF_IOCTL(AF_INET6, SIOCGLIFMETRIC, (caddr_t)&lifreq);
5b73a671 132#endif /* SOLARIS_IPV6 */
d62a17ae 133 else
134 ret = -1;
8842468c 135
d62a17ae 136 if (ret < 0)
137 return;
8842468c 138
d62a17ae 139 ifp->metric = lifreq.lifr_metric;
140
141 if (ifp->metric == 0)
142 ifp->metric = 1;
8842468c 143}
144
145/* get interface MTU */
d62a17ae 146void if_get_mtu(struct interface *ifp)
8842468c 147{
d62a17ae 148 struct lifreq lifreq;
149 int ret;
d7c0a89a 150 uint8_t changed = 0;
d62a17ae 151
152 if (ifp->flags & IFF_IPV4) {
153 lifreq_set_name(&lifreq, ifp->name);
154 ret = AF_IOCTL(AF_INET, SIOCGLIFMTU, (caddr_t)&lifreq);
155 if (ret < 0) {
156 zlog_info(
157 "Can't lookup mtu on %s by ioctl(SIOCGLIFMTU)",
158 ifp->name);
159 ifp->mtu = -1;
160 } else {
161 ifp->mtu = lifreq.lifr_metric;
162 changed = 1;
163 }
164 }
165
166 if (ifp->flags & IFF_IPV6) {
167 memset(&lifreq, 0, sizeof(lifreq));
168 lifreq_set_name(&lifreq, ifp->name);
169
170 ret = AF_IOCTL(AF_INET6, SIOCGLIFMTU, (caddr_t)&lifreq);
171 if (ret < 0) {
172 zlog_info(
173 "Can't lookup mtu6 on %s by ioctl(SIOCGIFMTU)",
174 ifp->name);
175 ifp->mtu6 = -1;
176 } else {
177 ifp->mtu6 = lifreq.lifr_metric;
178 changed = 1;
179 }
180 }
181
182 if (changed)
183 zebra_interface_up_update(ifp);
8842468c 184}
185
64168803
MS
186/*
187 * Stub for new dataplane interface-address modification path.
188 */
189enum zebra_dplane_result kernel_address_update_ctx(struct zebra_dplane_ctx *ctx)
190{
191 return ZEBRA_DPLANE_REQUEST_FAILURE;
192}
193
8842468c 194/* Set up interface's address, netmask (and broadcast? ).
195 Solaris uses ifname:number semantics to set IP address aliases. */
d62a17ae 196int if_set_prefix(struct interface *ifp, struct connected *ifc)
8842468c 197{
d62a17ae 198 int ret;
199 struct ifreq ifreq;
200 struct sockaddr_in addr;
201 struct sockaddr_in broad;
202 struct sockaddr_in mask;
203 struct prefix_ipv4 ifaddr;
204 struct prefix_ipv4 *p;
8842468c 205
d62a17ae 206 p = (struct prefix_ipv4 *)ifc->address;
8842468c 207
d62a17ae 208 ifaddr = *p;
8842468c 209
138a4965 210 strlcpy(ifreq.ifr_name, ifp->name, sizeof(ifreq.ifr_name));
8842468c 211
d62a17ae 212 addr.sin_addr = p->prefix;
213 addr.sin_family = p->family;
214 memcpy(&ifreq.ifr_addr, &addr, sizeof(struct sockaddr_in));
8842468c 215
d62a17ae 216 ret = if_ioctl(SIOCSIFADDR, (caddr_t)&ifreq);
8842468c 217
d62a17ae 218 if (ret < 0)
219 return ret;
8842468c 220
d62a17ae 221 /* We need mask for make broadcast addr. */
222 masklen2ip(p->prefixlen, &mask.sin_addr);
8842468c 223
d62a17ae 224 if (if_is_broadcast(ifp)) {
225 apply_mask_ipv4(&ifaddr);
226 addr.sin_addr = ifaddr.prefix;
8842468c 227
d62a17ae 228 broad.sin_addr.s_addr =
229 (addr.sin_addr.s_addr | ~mask.sin_addr.s_addr);
230 broad.sin_family = p->family;
8842468c 231
d62a17ae 232 memcpy(&ifreq.ifr_broadaddr, &broad,
233 sizeof(struct sockaddr_in));
234 ret = if_ioctl(SIOCSIFBRDADDR, (caddr_t)&ifreq);
235 if (ret < 0)
236 return ret;
237 }
8842468c 238
d62a17ae 239 mask.sin_family = p->family;
8842468c 240#ifdef SUNOS_5
d62a17ae 241 memcpy(&mask, &ifreq.ifr_addr, sizeof(mask));
8842468c 242#else
d62a17ae 243 memcpy(&ifreq.ifr_netmask, &mask, sizeof(struct sockaddr_in));
48a46fa0 244#endif /* SUNOS_5 */
d62a17ae 245 ret = if_ioctl(SIOCSIFNETMASK, (caddr_t)&ifreq);
8842468c 246
d62a17ae 247 return ((ret < 0) ? ret : 0);
8842468c 248}
249
250/* Set up interface's address, netmask (and broadcast).
251 Solaris uses ifname:number semantics to set IP address aliases. */
d62a17ae 252int if_unset_prefix(struct interface *ifp, struct connected *ifc)
8842468c 253{
d62a17ae 254 int ret;
255 struct ifreq ifreq;
256 struct sockaddr_in addr;
257 struct prefix_ipv4 *p;
258
259 p = (struct prefix_ipv4 *)ifc->address;
8842468c 260
138a4965 261 strlcpy(ifreq.ifr_name, ifp->name, sizeof(ifreq.ifr_name));
8842468c 262
d62a17ae 263 memset(&addr, 0, sizeof(struct sockaddr_in));
264 addr.sin_family = p->family;
265 memcpy(&ifreq.ifr_addr, &addr, sizeof(struct sockaddr_in));
8842468c 266
d62a17ae 267 ret = if_ioctl(SIOCSIFADDR, (caddr_t)&ifreq);
8842468c 268
d62a17ae 269 if (ret < 0)
270 return ret;
8842468c 271
d62a17ae 272 return 0;
8842468c 273}
274
5c78b3d0 275/* Get just the flags for the given name.
276 * Used by the normal 'if_get_flags' function, as well
277 * as the bootup interface-list code, which has to peek at per-address
278 * flags in order to figure out which ones should be ignored..
0752ef0b 279 */
d62a17ae 280int if_get_flags_direct(const char *ifname, uint64_t *flags, unsigned int af)
0752ef0b 281{
d62a17ae 282 struct lifreq lifreq;
283 int ret;
284
285 lifreq_set_name(&lifreq, ifname);
286
287 ret = AF_IOCTL(af, SIOCGLIFFLAGS, (caddr_t)&lifreq);
288
289 if (ret)
290 zlog_debug("%s: ifname %s, error %s (%d)", __func__, ifname,
291 safe_strerror(errno), errno);
292
293 *flags = lifreq.lifr_flags;
294
295 return ret;
0752ef0b 296}
297
8842468c 298/* get interface flags */
d62a17ae 299void if_get_flags(struct interface *ifp)
8842468c 300{
d62a17ae 301 int ret4 = 0, ret6 = 0;
302 uint64_t newflags = 0;
303 uint64_t tmpflags;
304
305 if (ifp->flags & IFF_IPV4) {
306 ret4 = if_get_flags_direct(ifp->name, &tmpflags, AF_INET);
307
308 if (!ret4)
309 newflags |= tmpflags;
310 else if (errno == ENXIO) {
311 /* it's gone */
312 UNSET_FLAG(ifp->flags, IFF_UP);
313 if_flags_update(ifp, ifp->flags);
314 }
315 }
316
317 if (ifp->flags & IFF_IPV6) {
318 ret6 = if_get_flags_direct(ifp->name, &tmpflags, AF_INET6);
319
320 if (!ret6)
321 newflags |= tmpflags;
322 else if (errno == ENXIO) {
323 /* it's gone */
324 UNSET_FLAG(ifp->flags, IFF_UP);
325 if_flags_update(ifp, ifp->flags);
326 }
327 }
328
329 /* only update flags if one of above succeeded */
330 if (!(ret4 && ret6))
331 if_flags_update(ifp, newflags);
8842468c 332}
333
334/* Set interface flags */
d62a17ae 335int if_set_flags(struct interface *ifp, uint64_t flags)
8842468c 336{
d62a17ae 337 int ret;
338 struct lifreq lifreq;
339
340 lifreq_set_name(&lifreq, ifp->name);
341
342 lifreq.lifr_flags = ifp->flags;
343 lifreq.lifr_flags |= flags;
344
345 if (ifp->flags & IFF_IPV4)
346 ret = AF_IOCTL(AF_INET, SIOCSLIFFLAGS, (caddr_t)&lifreq);
347 else if (ifp->flags & IFF_IPV6)
348 ret = AF_IOCTL(AF_INET6, SIOCSLIFFLAGS, (caddr_t)&lifreq);
349 else
350 ret = -1;
351
352 if (ret < 0)
353 zlog_info("can't set interface flags on %s: %s", ifp->name,
354 safe_strerror(errno));
355 else
356 ret = 0;
357
358 return ret;
8842468c 359}
360
361/* Unset interface's flag. */
d62a17ae 362int if_unset_flags(struct interface *ifp, uint64_t flags)
8842468c 363{
d62a17ae 364 int ret;
365 struct lifreq lifreq;
366
367 lifreq_set_name(&lifreq, ifp->name);
368
369 lifreq.lifr_flags = ifp->flags;
370 lifreq.lifr_flags &= ~flags;
371
372 if (ifp->flags & IFF_IPV4)
373 ret = AF_IOCTL(AF_INET, SIOCSLIFFLAGS, (caddr_t)&lifreq);
374 else if (ifp->flags & IFF_IPV6)
375 ret = AF_IOCTL(AF_INET6, SIOCSLIFFLAGS, (caddr_t)&lifreq);
376 else
377 ret = -1;
378
379 if (ret < 0)
380 zlog_info("can't unset interface flags");
381 else
382 ret = 0;
383
384 return ret;
8842468c 385}
386
8842468c 387/* Interface's address add/delete functions. */
d62a17ae 388int if_prefix_add_ipv6(struct interface *ifp, struct connected *ifc)
8842468c 389{
d62a17ae 390 char addrbuf[PREFIX_STRLEN];
8842468c 391
450971aa 392 flog_warn(EC_LIB_DEVELOPMENT, "Can't set %s on interface %s",
d62a17ae 393 prefix2str(ifc->address, addrbuf, sizeof(addrbuf)),
394 ifp->name);
8842468c 395
d62a17ae 396 return 0;
8842468c 397}
398
d62a17ae 399int if_prefix_delete_ipv6(struct interface *ifp, struct connected *ifc)
8842468c 400{
d62a17ae 401 char addrbuf[PREFIX_STRLEN];
8842468c 402
450971aa 403 flog_warn(EC_LIB_DEVELOPMENT, "Can't delete %s on interface %s",
d62a17ae 404 prefix2str(ifc->address, addrbuf, sizeof(addrbuf)),
405 ifp->name);
8842468c 406
d62a17ae 407 return 0;
8842468c 408}
ddfeb486
DL
409
410#endif /* SUNOS_5 */