]> git.proxmox.com Git - mirror_frr.git/blame - zebra/ioctl_solaris.c
Merge pull request #5805 from donaldsharp/babel_int_return
[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"
0f1f6ce4 41#include "zebra/debug.h"
8842468c 42
48a46fa0 43extern struct zebra_privs_t zserv_privs;
8842468c 44
0f1f6ce4
MS
45/* Prototypes */
46static int if_set_prefix_ctx(const struct zebra_dplane_ctx *ctx);
47static int if_unset_prefix_ctx(const struct zebra_dplane_ctx *ctx);
48static int if_set_prefix6_ctx(const struct zebra_dplane_ctx *ctx);
49static int if_unset_prefix6_ctx(const struct zebra_dplane_ctx *ctx);
50
8842468c 51/* clear and set interface name string */
d62a17ae 52void lifreq_set_name(struct lifreq *lifreq, const char *ifname)
8842468c 53{
138a4965 54 strlcpy(lifreq->lifr_name, ifname, sizeof(lifreq->lifr_name));
8842468c 55}
56
d7c0a89a 57int vrf_if_ioctl(unsigned long request, caddr_t buffer, vrf_id_t vrf_id)
4db21619
PG
58{
59 return if_ioctl(request, buffer);
60}
61
8842468c 62/* call ioctl system call */
d7c0a89a 63int if_ioctl(unsigned long request, caddr_t buffer)
8842468c 64{
d62a17ae 65 int sock;
66 int ret;
67 int err;
68
0cf6db21 69 frr_with_privs(&zserv_privs) {
01b9e3fd
DL
70
71 sock = socket(AF_INET, SOCK_DGRAM, 0);
72 if (sock < 0) {
73 zlog_err("Cannot create UDP socket: %s",
74 safe_strerror(errno));
75 exit(1);
76 }
d62a17ae 77
01b9e3fd
DL
78 if ((ret = ioctl(sock, request, buffer)) < 0)
79 err = errno;
d62a17ae 80
01b9e3fd 81 }
d62a17ae 82
83 close(sock);
84
85 if (ret < 0) {
86 errno = err;
87 return ret;
88 }
89 return 0;
8842468c 90}
91
5b73a671 92
d7c0a89a 93int if_ioctl_ipv6(unsigned long request, caddr_t buffer)
8842468c 94{
d62a17ae 95 int sock;
96 int ret;
97 int err;
98
0cf6db21 99 frr_with_privs(&zserv_privs) {
01b9e3fd
DL
100
101 sock = socket(AF_INET6, SOCK_DGRAM, 0);
102 if (sock < 0) {
103 zlog_err("Cannot create IPv6 datagram socket: %s",
104 safe_strerror(errno));
105 exit(1);
106 }
d62a17ae 107
01b9e3fd
DL
108 if ((ret = ioctl(sock, request, buffer)) < 0)
109 err = errno;
d62a17ae 110
01b9e3fd 111 }
d62a17ae 112
113 close(sock);
114
115 if (ret < 0) {
116 errno = err;
117 return ret;
118 }
119
120 return 0;
8842468c 121}
8842468c 122
123/*
124 * get interface metric
125 * -- if value is not avaliable set -1
126 */
d62a17ae 127void if_get_metric(struct interface *ifp)
8842468c 128{
d62a17ae 129 struct lifreq lifreq;
130 int ret;
8842468c 131
d62a17ae 132 lifreq_set_name(&lifreq, ifp->name);
8842468c 133
d62a17ae 134 if (ifp->flags & IFF_IPV4)
135 ret = AF_IOCTL(AF_INET, SIOCGLIFMETRIC, (caddr_t)&lifreq);
5b73a671 136#ifdef SOLARIS_IPV6
d62a17ae 137 else if (ifp->flags & IFF_IPV6)
138 ret = AF_IOCTL(AF_INET6, SIOCGLIFMETRIC, (caddr_t)&lifreq);
5b73a671 139#endif /* SOLARIS_IPV6 */
d62a17ae 140 else
141 ret = -1;
8842468c 142
d62a17ae 143 if (ret < 0)
144 return;
8842468c 145
d62a17ae 146 ifp->metric = lifreq.lifr_metric;
147
148 if (ifp->metric == 0)
149 ifp->metric = 1;
8842468c 150}
151
152/* get interface MTU */
d62a17ae 153void if_get_mtu(struct interface *ifp)
8842468c 154{
d62a17ae 155 struct lifreq lifreq;
156 int ret;
d7c0a89a 157 uint8_t changed = 0;
d62a17ae 158
159 if (ifp->flags & IFF_IPV4) {
160 lifreq_set_name(&lifreq, ifp->name);
161 ret = AF_IOCTL(AF_INET, SIOCGLIFMTU, (caddr_t)&lifreq);
162 if (ret < 0) {
163 zlog_info(
164 "Can't lookup mtu on %s by ioctl(SIOCGLIFMTU)",
165 ifp->name);
166 ifp->mtu = -1;
167 } else {
168 ifp->mtu = lifreq.lifr_metric;
169 changed = 1;
170 }
171 }
172
173 if (ifp->flags & IFF_IPV6) {
174 memset(&lifreq, 0, sizeof(lifreq));
175 lifreq_set_name(&lifreq, ifp->name);
176
177 ret = AF_IOCTL(AF_INET6, SIOCGLIFMTU, (caddr_t)&lifreq);
178 if (ret < 0) {
179 zlog_info(
180 "Can't lookup mtu6 on %s by ioctl(SIOCGIFMTU)",
181 ifp->name);
182 ifp->mtu6 = -1;
183 } else {
184 ifp->mtu6 = lifreq.lifr_metric;
185 changed = 1;
186 }
187 }
188
189 if (changed)
190 zebra_interface_up_update(ifp);
8842468c 191}
192
64168803 193/*
0f1f6ce4 194 *
64168803 195 */
0f1f6ce4
MS
196enum zebra_dplane_result kernel_address_update_ctx(
197 struct zebra_dplane_ctx *ctx)
64168803 198{
0f1f6ce4
MS
199 int ret = -1;
200 const struct prefix *p;
201
202 p = dplane_ctx_get_intf_addr(ctx);
203
204 if (dplane_ctx_get_op(ctx) == DPLANE_OP_ADDR_INSTALL) {
205 if (p->family == AF_INET)
206 ret = if_set_prefix_ctx(ctx);
207 else
208 ret = if_set_prefix6_ctx(ctx);
209 } else if (dplane_ctx_get_op(ctx) == DPLANE_OP_ADDR_UNINSTALL) {
210 if (p->family == AF_INET)
211 ret = if_unset_prefix_ctx(ctx);
212 else
213 ret = if_unset_prefix6_ctx(ctx);
214 } else {
215 if (IS_ZEBRA_DEBUG_DPLANE)
216 zlog_debug("Invalid op in interface-addr install");
217 }
218
219 return (ret == 0 ?
220 ZEBRA_DPLANE_REQUEST_SUCCESS : ZEBRA_DPLANE_REQUEST_FAILURE);
64168803
MS
221}
222
8842468c 223/* Set up interface's address, netmask (and broadcast? ).
224 Solaris uses ifname:number semantics to set IP address aliases. */
0f1f6ce4 225static int if_set_prefix_ctx(const struct zebra_dplane_ctx *ctx)
8842468c 226{
d62a17ae 227 int ret;
228 struct ifreq ifreq;
0f1f6ce4 229 struct sockaddr_in addr, broad, mask;
d62a17ae 230 struct prefix_ipv4 ifaddr;
231 struct prefix_ipv4 *p;
8842468c 232
0f1f6ce4 233 p = (struct prefix_ipv4 *)dplane_ctx_get_intf_addr(ctx);
8842468c 234
d62a17ae 235 ifaddr = *p;
8842468c 236
0f1f6ce4
MS
237 strlcpy(ifreq.ifr_name, dplane_ctx_get_ifname(ctx),
238 sizeof(ifreq.ifr_name));
8842468c 239
d62a17ae 240 addr.sin_addr = p->prefix;
241 addr.sin_family = p->family;
242 memcpy(&ifreq.ifr_addr, &addr, sizeof(struct sockaddr_in));
8842468c 243
d62a17ae 244 ret = if_ioctl(SIOCSIFADDR, (caddr_t)&ifreq);
8842468c 245
d62a17ae 246 if (ret < 0)
247 return ret;
8842468c 248
d62a17ae 249 /* We need mask for make broadcast addr. */
250 masklen2ip(p->prefixlen, &mask.sin_addr);
8842468c 251
0f1f6ce4 252 if (dplane_ctx_intf_is_broadcast(ctx)) {
d62a17ae 253 apply_mask_ipv4(&ifaddr);
254 addr.sin_addr = ifaddr.prefix;
8842468c 255
d62a17ae 256 broad.sin_addr.s_addr =
257 (addr.sin_addr.s_addr | ~mask.sin_addr.s_addr);
258 broad.sin_family = p->family;
8842468c 259
d62a17ae 260 memcpy(&ifreq.ifr_broadaddr, &broad,
261 sizeof(struct sockaddr_in));
262 ret = if_ioctl(SIOCSIFBRDADDR, (caddr_t)&ifreq);
263 if (ret < 0)
264 return ret;
265 }
8842468c 266
d62a17ae 267 mask.sin_family = p->family;
8842468c 268#ifdef SUNOS_5
d62a17ae 269 memcpy(&mask, &ifreq.ifr_addr, sizeof(mask));
8842468c 270#else
d62a17ae 271 memcpy(&ifreq.ifr_netmask, &mask, sizeof(struct sockaddr_in));
48a46fa0 272#endif /* SUNOS_5 */
d62a17ae 273 ret = if_ioctl(SIOCSIFNETMASK, (caddr_t)&ifreq);
8842468c 274
d62a17ae 275 return ((ret < 0) ? ret : 0);
8842468c 276}
277
278/* Set up interface's address, netmask (and broadcast).
279 Solaris uses ifname:number semantics to set IP address aliases. */
0f1f6ce4 280static int if_unset_prefix_ctx(const struct zebra_dplane_ctx *ctx)
8842468c 281{
d62a17ae 282 int ret;
283 struct ifreq ifreq;
284 struct sockaddr_in addr;
285 struct prefix_ipv4 *p;
286
0f1f6ce4 287 p = (struct prefix_ipv4 *)dplane_ctx_get_intf_addr(ctx);
8842468c 288
fcb072cd 289 strlcpy(ifreq.ifr_name, dplane_ctx_get_ifname(ctx),
0f1f6ce4 290 sizeof(ifreq.ifr_name));
8842468c 291
d62a17ae 292 memset(&addr, 0, sizeof(struct sockaddr_in));
293 addr.sin_family = p->family;
294 memcpy(&ifreq.ifr_addr, &addr, sizeof(struct sockaddr_in));
8842468c 295
d62a17ae 296 ret = if_ioctl(SIOCSIFADDR, (caddr_t)&ifreq);
8842468c 297
d62a17ae 298 if (ret < 0)
299 return ret;
8842468c 300
d62a17ae 301 return 0;
8842468c 302}
303
5c78b3d0 304/* Get just the flags for the given name.
305 * Used by the normal 'if_get_flags' function, as well
306 * as the bootup interface-list code, which has to peek at per-address
307 * flags in order to figure out which ones should be ignored..
0752ef0b 308 */
d62a17ae 309int if_get_flags_direct(const char *ifname, uint64_t *flags, unsigned int af)
0752ef0b 310{
d62a17ae 311 struct lifreq lifreq;
312 int ret;
313
314 lifreq_set_name(&lifreq, ifname);
315
316 ret = AF_IOCTL(af, SIOCGLIFFLAGS, (caddr_t)&lifreq);
317
318 if (ret)
319 zlog_debug("%s: ifname %s, error %s (%d)", __func__, ifname,
320 safe_strerror(errno), errno);
321
322 *flags = lifreq.lifr_flags;
323
324 return ret;
0752ef0b 325}
326
8842468c 327/* get interface flags */
d62a17ae 328void if_get_flags(struct interface *ifp)
8842468c 329{
d62a17ae 330 int ret4 = 0, ret6 = 0;
331 uint64_t newflags = 0;
332 uint64_t tmpflags;
333
334 if (ifp->flags & IFF_IPV4) {
335 ret4 = if_get_flags_direct(ifp->name, &tmpflags, AF_INET);
336
337 if (!ret4)
338 newflags |= tmpflags;
339 else if (errno == ENXIO) {
340 /* it's gone */
341 UNSET_FLAG(ifp->flags, IFF_UP);
342 if_flags_update(ifp, ifp->flags);
343 }
344 }
345
346 if (ifp->flags & IFF_IPV6) {
347 ret6 = if_get_flags_direct(ifp->name, &tmpflags, AF_INET6);
348
349 if (!ret6)
350 newflags |= tmpflags;
351 else if (errno == ENXIO) {
352 /* it's gone */
353 UNSET_FLAG(ifp->flags, IFF_UP);
354 if_flags_update(ifp, ifp->flags);
355 }
356 }
357
358 /* only update flags if one of above succeeded */
359 if (!(ret4 && ret6))
360 if_flags_update(ifp, newflags);
8842468c 361}
362
363/* Set interface flags */
d62a17ae 364int if_set_flags(struct interface *ifp, uint64_t flags)
8842468c 365{
d62a17ae 366 int ret;
367 struct lifreq lifreq;
368
369 lifreq_set_name(&lifreq, ifp->name);
370
371 lifreq.lifr_flags = ifp->flags;
372 lifreq.lifr_flags |= flags;
373
374 if (ifp->flags & IFF_IPV4)
375 ret = AF_IOCTL(AF_INET, SIOCSLIFFLAGS, (caddr_t)&lifreq);
376 else if (ifp->flags & IFF_IPV6)
377 ret = AF_IOCTL(AF_INET6, SIOCSLIFFLAGS, (caddr_t)&lifreq);
378 else
379 ret = -1;
380
381 if (ret < 0)
382 zlog_info("can't set interface flags on %s: %s", ifp->name,
383 safe_strerror(errno));
384 else
385 ret = 0;
386
387 return ret;
8842468c 388}
389
390/* Unset interface's flag. */
d62a17ae 391int if_unset_flags(struct interface *ifp, uint64_t flags)
8842468c 392{
d62a17ae 393 int ret;
394 struct lifreq lifreq;
395
396 lifreq_set_name(&lifreq, ifp->name);
397
398 lifreq.lifr_flags = ifp->flags;
399 lifreq.lifr_flags &= ~flags;
400
401 if (ifp->flags & IFF_IPV4)
402 ret = AF_IOCTL(AF_INET, SIOCSLIFFLAGS, (caddr_t)&lifreq);
403 else if (ifp->flags & IFF_IPV6)
404 ret = AF_IOCTL(AF_INET6, SIOCSLIFFLAGS, (caddr_t)&lifreq);
405 else
406 ret = -1;
407
408 if (ret < 0)
409 zlog_info("can't unset interface flags");
410 else
411 ret = 0;
412
413 return ret;
8842468c 414}
415
8842468c 416/* Interface's address add/delete functions. */
0f1f6ce4 417static int if_set_prefix6_ctx(const struct zebra_dplane_ctx *ctx)
8842468c 418{
d62a17ae 419 char addrbuf[PREFIX_STRLEN];
8842468c 420
0f1f6ce4
MS
421 prefix2str(dplane_ctx_get_intf_addr(ctx), addrbuf, sizeof(addrbuf));
422
450971aa 423 flog_warn(EC_LIB_DEVELOPMENT, "Can't set %s on interface %s",
0f1f6ce4 424 addrbuf, dplane_ctx_get_ifname(ctx));
8842468c 425
d62a17ae 426 return 0;
8842468c 427}
428
0f1f6ce4 429static int if_unset_prefix6_ctx(const struct zebra_dplane_ctx *ctx)
8842468c 430{
d62a17ae 431 char addrbuf[PREFIX_STRLEN];
8842468c 432
0f1f6ce4
MS
433 prefix2str(dplane_ctx_get_intf_addr(ctx), addrbuf, sizeof(addrbuf));
434
450971aa 435 flog_warn(EC_LIB_DEVELOPMENT, "Can't delete %s on interface %s",
0f1f6ce4 436 addrbuf, dplane_ctx_get_ifname(ctx));
8842468c 437
d62a17ae 438 return 0;
8842468c 439}
ddfeb486
DL
440
441#endif /* SUNOS_5 */