]> git.proxmox.com Git - mirror_frr.git/blame - zebra/ioctl.c
Merge pull request #10447 from ton31337/fix/json_with_whitespaces
[mirror_frr.git] / zebra / ioctl.c
CommitLineData
718e3744 1/*
2 * Common ioctl functions.
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
718e3744 20 */
21
22#include <zebra.h>
23
24#include "linklist.h"
25#include "if.h"
26#include "prefix.h"
27#include "ioctl.h"
28#include "log.h"
edd7c245 29#include "privs.h"
174482ef 30#include "lib_errors.h"
718e3744 31
5e6a74d8 32#include "vty.h"
718e3744 33#include "zebra/rib.h"
34#include "zebra/rt.h"
5c78b3d0 35#include "zebra/interface.h"
364fed6b 36#include "zebra/zebra_errors.h"
0f1f6ce4 37#include "zebra/debug.h"
718e3744 38
55edb0d4
AS
39#ifdef HAVE_BSD_LINK_DETECT
40#include <net/if_media.h>
41#endif /* HAVE_BSD_LINK_DETECT*/
42
edd7c245 43extern struct zebra_privs_t zserv_privs;
44
718e3744 45/* clear and set interface name string */
d62a17ae 46void ifreq_set_name(struct ifreq *ifreq, struct interface *ifp)
718e3744 47{
0af35d90 48 strlcpy(ifreq->ifr_name, ifp->name, sizeof(ifreq->ifr_name));
718e3744 49}
50
51/* call ioctl system call */
d7c0a89a 52int if_ioctl(unsigned long request, caddr_t buffer)
718e3744 53{
d62a17ae 54 int sock;
55 int ret;
56 int err = 0;
57
0cf6db21 58 frr_with_privs(&zserv_privs) {
01b9e3fd
DL
59 sock = socket(AF_INET, SOCK_DGRAM, 0);
60 if (sock < 0) {
61 zlog_err("Cannot create UDP socket: %s",
62 safe_strerror(errno));
63 exit(1);
64 }
65 if ((ret = ioctl(sock, request, buffer)) < 0)
66 err = errno;
d62a17ae 67 }
d62a17ae 68 close(sock);
69
70 if (ret < 0) {
71 errno = err;
72 return ret;
73 }
74 return 0;
718e3744 75}
76
4db21619 77/* call ioctl system call */
d7c0a89a 78int vrf_if_ioctl(unsigned long request, caddr_t buffer, vrf_id_t vrf_id)
4db21619
PG
79{
80 int sock;
81 int ret;
82 int err = 0;
83
0cf6db21 84 frr_with_privs(&zserv_privs) {
01b9e3fd
DL
85 sock = vrf_socket(AF_INET, SOCK_DGRAM, 0, vrf_id, NULL);
86 if (sock < 0) {
87 zlog_err("Cannot create UDP socket: %s",
88 safe_strerror(errno));
89 exit(1);
90 }
91 ret = vrf_ioctl(vrf_id, sock, request, buffer);
92 if (ret < 0)
93 err = errno;
4db21619 94 }
4db21619
PG
95 close(sock);
96
97 if (ret < 0) {
98 errno = err;
99 return ret;
100 }
101 return 0;
102}
103
e86b71f1 104#ifndef HAVE_NETLINK
d7c0a89a 105static int if_ioctl_ipv6(unsigned long request, caddr_t buffer)
718e3744 106{
d62a17ae 107 int sock;
108 int ret;
109 int err = 0;
110
0cf6db21 111 frr_with_privs(&zserv_privs) {
01b9e3fd
DL
112 sock = socket(AF_INET6, SOCK_DGRAM, 0);
113 if (sock < 0) {
114 zlog_err("Cannot create IPv6 datagram socket: %s",
115 safe_strerror(errno));
116 exit(1);
117 }
d62a17ae 118
01b9e3fd
DL
119 if ((ret = ioctl(sock, request, buffer)) < 0)
120 err = errno;
121 }
d62a17ae 122 close(sock);
123
124 if (ret < 0) {
125 errno = err;
126 return ret;
127 }
128 return 0;
718e3744 129}
e86b71f1 130#endif /* ! HAVE_NETLINK */
718e3744 131
132/*
133 * get interface metric
134 * -- if value is not avaliable set -1
135 */
d62a17ae 136void if_get_metric(struct interface *ifp)
718e3744 137{
138#ifdef SIOCGIFMETRIC
d62a17ae 139 struct ifreq ifreq;
718e3744 140
d62a17ae 141 ifreq_set_name(&ifreq, ifp);
718e3744 142
096f7609 143 if (vrf_if_ioctl(SIOCGIFMETRIC, (caddr_t)&ifreq, ifp->vrf->vrf_id) < 0)
d62a17ae 144 return;
145 ifp->metric = ifreq.ifr_metric;
146 if (ifp->metric == 0)
147 ifp->metric = 1;
148#else /* SIOCGIFMETRIC */
149 ifp->metric = -1;
718e3744 150#endif /* SIOCGIFMETRIC */
151}
152
153/* get interface MTU */
d62a17ae 154void if_get_mtu(struct interface *ifp)
718e3744 155{
d62a17ae 156 struct ifreq ifreq;
718e3744 157
d62a17ae 158 ifreq_set_name(&ifreq, ifp);
718e3744 159
160#if defined(SIOCGIFMTU)
096f7609 161 if (vrf_if_ioctl(SIOCGIFMTU, (caddr_t)&ifreq, ifp->vrf->vrf_id) < 0) {
d62a17ae 162 zlog_info("Can't lookup mtu by ioctl(SIOCGIFMTU)");
163 ifp->mtu6 = ifp->mtu = -1;
164 return;
165 }
718e3744 166
d62a17ae 167 ifp->mtu6 = ifp->mtu = ifreq.ifr_mtu;
718e3744 168
d62a17ae 169 /* propogate */
170 zebra_interface_up_update(ifp);
f5e004f7 171
718e3744 172#else
d62a17ae 173 zlog_info("Can't lookup mtu on this system");
174 ifp->mtu6 = ifp->mtu = -1;
718e3744 175#endif
176}
177
64168803 178/*
0f1f6ce4
MS
179 * Handler for interface address programming via the zebra dplane,
180 * for non-netlink platforms. This handler dispatches to per-platform
181 * helpers, based on the operation requested.
64168803
MS
182 */
183#ifndef HAVE_NETLINK
184
0f1f6ce4
MS
185/* Prototypes: these are placed in this block so that they're only seen
186 * on non-netlink platforms.
187 */
188static int if_set_prefix_ctx(const struct zebra_dplane_ctx *ctx);
189static int if_unset_prefix_ctx(const struct zebra_dplane_ctx *ctx);
190static int if_set_prefix6_ctx(const struct zebra_dplane_ctx *ctx);
191static int if_unset_prefix6_ctx(const struct zebra_dplane_ctx *ctx);
192
64168803
MS
193enum zebra_dplane_result kernel_address_update_ctx(
194 struct zebra_dplane_ctx *ctx)
195{
0f1f6ce4
MS
196 int ret = -1;
197 const struct prefix *p;
198
199 p = dplane_ctx_get_intf_addr(ctx);
200
201 if (dplane_ctx_get_op(ctx) == DPLANE_OP_ADDR_INSTALL) {
202 if (p->family == AF_INET)
203 ret = if_set_prefix_ctx(ctx);
204 else
205 ret = if_set_prefix6_ctx(ctx);
206 } else if (dplane_ctx_get_op(ctx) == DPLANE_OP_ADDR_UNINSTALL) {
207 if (p->family == AF_INET)
208 ret = if_unset_prefix_ctx(ctx);
209 else
210 ret = if_unset_prefix6_ctx(ctx);
211 } else {
212 if (IS_ZEBRA_DEBUG_DPLANE)
213 zlog_debug("Invalid op in interface-addr install");
214 }
215
216 return (ret == 0 ?
217 ZEBRA_DPLANE_REQUEST_SUCCESS : ZEBRA_DPLANE_REQUEST_FAILURE);
64168803
MS
218}
219
220#endif /* !HAVE_NETLINK */
221
718e3744 222#ifdef HAVE_NETLINK
0f1f6ce4
MS
223
224/* TODO -- remove; no use of these apis with netlink any longer */
225
226#else /* ! HAVE_NETLINK */
227#ifdef HAVE_STRUCT_IFALIASREQ
228
229/*
230 * Helper for interface-addr install, non-netlink
231 */
232static int if_set_prefix_ctx(const struct zebra_dplane_ctx *ctx)
718e3744 233{
0f1f6ce4
MS
234 int ret;
235 struct ifaliasreq addreq;
236 struct sockaddr_in addr, mask, peer;
237 struct prefix_ipv4 *p;
238
239 p = (struct prefix_ipv4 *)dplane_ctx_get_intf_addr(ctx);
240
241 memset(&addreq, 0, sizeof(addreq));
fcb072cd 242 strlcpy((char *)&addreq.ifra_name, dplane_ctx_get_ifname(ctx),
0f1f6ce4
MS
243 sizeof(addreq.ifra_name));
244
245 memset(&addr, 0, sizeof(struct sockaddr_in));
246 addr.sin_addr = p->prefix;
247 addr.sin_family = p->family;
248#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
249 addr.sin_len = sizeof(struct sockaddr_in);
250#endif
251 memcpy(&addreq.ifra_addr, &addr, sizeof(struct sockaddr_in));
252
253 if (dplane_ctx_intf_is_connected(ctx)) {
254 p = (struct prefix_ipv4 *)dplane_ctx_get_intf_dest(ctx);
255 memset(&mask, 0, sizeof(struct sockaddr_in));
256 peer.sin_addr = p->prefix;
257 peer.sin_family = p->family;
258#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
259 peer.sin_len = sizeof(struct sockaddr_in);
260#endif
261 memcpy(&addreq.ifra_broadaddr, &peer,
262 sizeof(struct sockaddr_in));
263 }
264
265 memset(&mask, 0, sizeof(struct sockaddr_in));
266 masklen2ip(p->prefixlen, &mask.sin_addr);
267 mask.sin_family = p->family;
268#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
269 mask.sin_len = sizeof(struct sockaddr_in);
270#endif
271 memcpy(&addreq.ifra_mask, &mask, sizeof(struct sockaddr_in));
272
273 ret = if_ioctl(SIOCAIFADDR, (caddr_t)&addreq);
274 if (ret < 0)
275 return ret;
276 return 0;
277
718e3744 278}
279
0f1f6ce4
MS
280/*
281 * Helper for interface-addr un-install, non-netlink
282 */
283static int if_unset_prefix_ctx(const struct zebra_dplane_ctx *ctx)
718e3744 284{
0f1f6ce4
MS
285 int ret;
286 struct ifaliasreq addreq;
287 struct sockaddr_in addr, mask, peer;
288 struct prefix_ipv4 *p;
289
290 p = (struct prefix_ipv4 *)dplane_ctx_get_intf_addr(ctx);
291
292 memset(&addreq, 0, sizeof(addreq));
fcb072cd 293 strlcpy((char *)&addreq.ifra_name, dplane_ctx_get_ifname(ctx),
0f1f6ce4
MS
294 sizeof(addreq.ifra_name));
295
296 memset(&addr, 0, sizeof(struct sockaddr_in));
297 addr.sin_addr = p->prefix;
298 addr.sin_family = p->family;
299#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
300 addr.sin_len = sizeof(struct sockaddr_in);
301#endif
302 memcpy(&addreq.ifra_addr, &addr, sizeof(struct sockaddr_in));
303
304 if (dplane_ctx_intf_is_connected(ctx)) {
305 p = (struct prefix_ipv4 *)dplane_ctx_get_intf_dest(ctx);
306 memset(&mask, 0, sizeof(struct sockaddr_in));
307 peer.sin_addr = p->prefix;
308 peer.sin_family = p->family;
309#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
310 peer.sin_len = sizeof(struct sockaddr_in);
311#endif
312 memcpy(&addreq.ifra_broadaddr, &peer,
313 sizeof(struct sockaddr_in));
314 }
315
316 memset(&mask, 0, sizeof(struct sockaddr_in));
317 masklen2ip(p->prefixlen, &mask.sin_addr);
318 mask.sin_family = p->family;
319#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
320 mask.sin_len = sizeof(struct sockaddr_in);
321#endif
322 memcpy(&addreq.ifra_mask, &mask, sizeof(struct sockaddr_in));
323
324 ret = if_ioctl(SIOCDIFADDR, (caddr_t)&addreq);
325 if (ret < 0)
326 return ret;
327 return 0;
718e3744 328}
718e3744 329#else
330/* Set up interface's address, netmask (and broadcas? ). Linux or
331 Solaris uses ifname:number semantics to set IP address aliases. */
39fa2825 332int if_set_prefix_ctx(const struct zebra_dplane_ctx *ctx)
718e3744 333{
d62a17ae 334 int ret;
335 struct ifreq ifreq;
336 struct sockaddr_in addr;
337 struct sockaddr_in broad;
338 struct sockaddr_in mask;
339 struct prefix_ipv4 ifaddr;
340 struct prefix_ipv4 *p;
341
39fa2825 342 p = (struct prefix_ipv4 *)dplane_ctx_get_intf_addr(ctx);
d62a17ae 343
344 ifaddr = *p;
345
39fa2825
MS
346 strlcpy(ifreq.ifr_name, dplane_ctx_get_ifname(ctx),
347 sizeof(ifreq.ifr_name));
d62a17ae 348
349 addr.sin_addr = p->prefix;
350 addr.sin_family = p->family;
351 memcpy(&ifreq.ifr_addr, &addr, sizeof(struct sockaddr_in));
352 ret = if_ioctl(SIOCSIFADDR, (caddr_t)&ifreq);
353 if (ret < 0)
354 return ret;
355
356 /* We need mask for make broadcast addr. */
357 masklen2ip(p->prefixlen, &mask.sin_addr);
358
39fa2825 359 if (dplane_ctx_intf_is_broadcast(ctx)) {
d62a17ae 360 apply_mask_ipv4(&ifaddr);
361 addr.sin_addr = ifaddr.prefix;
362
363 broad.sin_addr.s_addr =
364 (addr.sin_addr.s_addr | ~mask.sin_addr.s_addr);
365 broad.sin_family = p->family;
366
367 memcpy(&ifreq.ifr_broadaddr, &broad,
368 sizeof(struct sockaddr_in));
369 ret = if_ioctl(SIOCSIFBRDADDR, (caddr_t)&ifreq);
370 if (ret < 0)
371 return ret;
372 }
373
374 mask.sin_family = p->family;
39fa2825 375 memcpy(&ifreq.ifr_addr, &mask, sizeof(struct sockaddr_in));
d62a17ae 376 ret = if_ioctl(SIOCSIFNETMASK, (caddr_t)&ifreq);
377 if (ret < 0)
378 return ret;
718e3744 379
d62a17ae 380 return 0;
718e3744 381}
382
383/* Set up interface's address, netmask (and broadcas? ). Linux or
384 Solaris uses ifname:number semantics to set IP address aliases. */
39fa2825 385int if_unset_prefix_ctx(const struct zebra_dplane_ctx *ctx)
718e3744 386{
d62a17ae 387 int ret;
388 struct ifreq ifreq;
389 struct sockaddr_in addr;
390 struct prefix_ipv4 *p;
718e3744 391
39fa2825 392 p = (struct prefix_ipv4 *)dplane_ctx_get_intf_addr(ctx);
718e3744 393
39fa2825
MS
394 strlcpy(ifreq.ifr_name, dplane_ctx_get_ifname(ctx),
395 sizeof(ifreq.ifr_name));
718e3744 396
d62a17ae 397 memset(&addr, 0, sizeof(struct sockaddr_in));
398 addr.sin_family = p->family;
399 memcpy(&ifreq.ifr_addr, &addr, sizeof(struct sockaddr_in));
400 ret = if_ioctl(SIOCSIFADDR, (caddr_t)&ifreq);
401 if (ret < 0)
402 return ret;
718e3744 403
d62a17ae 404 return 0;
718e3744 405}
6f0e3f6e 406#endif /* HAVE_STRUCT_IFALIASREQ */
718e3744 407#endif /* HAVE_NETLINK */
408
409/* get interface flags */
d62a17ae 410void if_get_flags(struct interface *ifp)
718e3744 411{
d62a17ae 412 int ret;
16dca7ce
B
413 struct ifreq ifreqflags;
414 struct ifreq ifreqdata;
718e3744 415
16dca7ce
B
416 ifreq_set_name(&ifreqflags, ifp);
417 ifreq_set_name(&ifreqdata, ifp);
718e3744 418
16dca7ce
B
419 ret = vrf_if_ioctl(SIOCGIFFLAGS, (caddr_t)&ifreqflags,
420 ifp->vrf->vrf_id);
d62a17ae 421 if (ret < 0) {
450971aa 422 flog_err_sys(EC_LIB_SYSTEM_CALL,
98f3df55
RM
423 "vrf_if_ioctl(SIOCGIFFLAGS %s) failed: %s",
424 ifp->name, safe_strerror(errno));
d62a17ae 425 return;
426 }
0b3f3d47 427
98f3df55
RM
428 if (!CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION))
429 goto out;
430
431 /* Per-default, IFF_RUNNING is held high, unless link-detect
432 * says otherwise - we abuse IFF_RUNNING inside zebra as a
433 * link-state flag, following practice on Linux and Solaris
434 * kernels
435 */
436
437#ifdef SIOCGIFDATA
438 /*
439 * BSD gets link state from ifi_link_link in struct if_data.
440 * All BSD's have this in getifaddrs(3) ifa_data for AF_LINK
441 * addresses. We can also access it via SIOCGIFDATA.
442 */
443
444#ifdef __NetBSD__
445 struct ifdatareq ifdr = {.ifdr_data.ifi_link_state = 0};
446 struct if_data *ifdata = &ifdr.ifdr_data;
447
448 strlcpy(ifdr.ifdr_name, ifp->name, sizeof(ifdr.ifdr_name));
096f7609 449 ret = vrf_if_ioctl(SIOCGIFDATA, (caddr_t)&ifdr, ifp->vrf->vrf_id);
98f3df55
RM
450#else
451 struct if_data ifd = {.ifi_link_state = 0};
452 struct if_data *ifdata = &ifd;
453
16dca7ce
B
454 ifreqdata.ifr_data = (caddr_t)ifdata;
455 ret = vrf_if_ioctl(SIOCGIFDATA, (caddr_t)&ifreqdata, ifp->vrf->vrf_id);
98f3df55
RM
456#endif
457
458 if (ret == -1)
459 /* Very unlikely. Did the interface disappear? */
460 flog_err_sys(EC_LIB_SYSTEM_CALL,
461 "if_ioctl(SIOCGIFDATA %s) failed: %s", ifp->name,
462 safe_strerror(errno));
463 else {
464 if (ifdata->ifi_link_state >= LINK_STATE_UP)
16dca7ce 465 SET_FLAG(ifreqflags.ifr_flags, IFF_RUNNING);
98f3df55
RM
466 else if (ifdata->ifi_link_state == LINK_STATE_UNKNOWN)
467 /* BSD traditionally treats UNKNOWN as UP */
16dca7ce 468 SET_FLAG(ifreqflags.ifr_flags, IFF_RUNNING);
98f3df55 469 else
16dca7ce 470 UNSET_FLAG(ifreqflags.ifr_flags, IFF_RUNNING);
98f3df55
RM
471 }
472
473#elif defined(HAVE_BSD_LINK_DETECT)
474 /*
475 * This is only needed for FreeBSD older than FreeBSD-13.
476 * Valid and active media generally means the link state is
477 * up, but this is not always the case.
478 * For example, some BSD's with a net80211 interface in MONITOR
479 * mode will treat the media as valid and active but the
480 * link state is down - because we cannot send anything.
481 * Also, virtual interfaces such as PPP, VLAN, etc generally
482 * don't support media at all, so the ioctl will just fail.
d62a17ae 483 */
98f3df55 484 struct ifmediareq ifmr = {.ifm_status = 0};
d62a17ae 485
98f3df55 486 strlcpy(ifmr.ifm_name, ifp->name, sizeof(ifmr.ifm_name));
d62a17ae 487
98f3df55
RM
488 if (if_ioctl(SIOCGIFMEDIA, (caddr_t)&ifmr) == -1) {
489 if (errno != EINVAL)
450971aa 490 flog_err_sys(EC_LIB_SYSTEM_CALL,
98f3df55
RM
491 "if_ioctl(SIOCGIFMEDIA %s) failed: %s",
492 ifp->name, safe_strerror(errno));
493 } else if (ifmr.ifm_status & IFM_AVALID) { /* media state is valid */
494 if (ifmr.ifm_status & IFM_ACTIVE) /* media is active */
16dca7ce 495 SET_FLAG(ifreqflags.ifr_flags, IFF_RUNNING);
98f3df55 496 else
16dca7ce 497 UNSET_FLAG(ifreqflags.ifr_flags, IFF_RUNNING);
d62a17ae 498 }
c543a173 499#endif /* HAVE_BSD_LINK_DETECT */
718e3744 500
98f3df55 501out:
16dca7ce 502 if_flags_update(ifp, (ifreqflags.ifr_flags & 0x0000ffff));
718e3744 503}
504
505/* Set interface flags */
d62a17ae 506int if_set_flags(struct interface *ifp, uint64_t flags)
718e3744 507{
d62a17ae 508 int ret;
509 struct ifreq ifreq;
718e3744 510
d62a17ae 511 memset(&ifreq, 0, sizeof(struct ifreq));
512 ifreq_set_name(&ifreq, ifp);
718e3744 513
d62a17ae 514 ifreq.ifr_flags = ifp->flags;
515 ifreq.ifr_flags |= flags;
718e3744 516
096f7609 517 ret = vrf_if_ioctl(SIOCSIFFLAGS, (caddr_t)&ifreq, ifp->vrf->vrf_id);
718e3744 518
d62a17ae 519 if (ret < 0) {
520 zlog_info("can't set interface flags");
521 return ret;
522 }
523 return 0;
718e3744 524}
525
526/* Unset interface's flag. */
d62a17ae 527int if_unset_flags(struct interface *ifp, uint64_t flags)
718e3744 528{
d62a17ae 529 int ret;
530 struct ifreq ifreq;
718e3744 531
d62a17ae 532 memset(&ifreq, 0, sizeof(struct ifreq));
533 ifreq_set_name(&ifreq, ifp);
718e3744 534
d62a17ae 535 ifreq.ifr_flags = ifp->flags;
536 ifreq.ifr_flags &= ~flags;
718e3744 537
096f7609 538 ret = vrf_if_ioctl(SIOCSIFFLAGS, (caddr_t)&ifreq, ifp->vrf->vrf_id);
718e3744 539
d62a17ae 540 if (ret < 0) {
541 zlog_info("can't unset interface flags");
542 return ret;
543 }
544 return 0;
718e3744 545}
546
39fa2825 547#ifndef LINUX_IPV6 /* Netlink has its own code */
718e3744 548
6f0e3f6e 549#ifdef HAVE_STRUCT_IN6_ALIASREQ
718e3744 550#ifndef ND6_INFINITE_LIFETIME
551#define ND6_INFINITE_LIFETIME 0xffffffffL
552#endif /* ND6_INFINITE_LIFETIME */
0f1f6ce4
MS
553
554/*
555 * Helper for interface-addr install, non-netlink
556 */
557static int if_set_prefix6_ctx(const struct zebra_dplane_ctx *ctx)
558{
559 int ret;
560 struct in6_aliasreq addreq;
561 struct sockaddr_in6 addr;
562 struct sockaddr_in6 mask;
563 struct prefix_ipv6 *p;
564
565 p = (struct prefix_ipv6 *)dplane_ctx_get_intf_addr(ctx);
566
567 memset(&addreq, 0, sizeof(addreq));
39fa2825 568 strlcpy((char *)&addreq.ifra_name,
0f1f6ce4
MS
569 dplane_ctx_get_ifname(ctx), sizeof(addreq.ifra_name));
570
571 memset(&addr, 0, sizeof(struct sockaddr_in6));
572 addr.sin6_addr = p->prefix;
573 addr.sin6_family = p->family;
574#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
575 addr.sin6_len = sizeof(struct sockaddr_in6);
576#endif
577 memcpy(&addreq.ifra_addr, &addr, sizeof(struct sockaddr_in6));
578
579 memset(&mask, 0, sizeof(struct sockaddr_in6));
580 masklen2ip6(p->prefixlen, &mask.sin6_addr);
581 mask.sin6_family = p->family;
582#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
583 mask.sin6_len = sizeof(struct sockaddr_in6);
584#endif
585 memcpy(&addreq.ifra_prefixmask, &mask, sizeof(struct sockaddr_in6));
586
587 addreq.ifra_lifetime.ia6t_vltime = 0xffffffff;
588 addreq.ifra_lifetime.ia6t_pltime = 0xffffffff;
589
590#ifdef HAVE_STRUCT_IF6_ALIASREQ_IFRA_LIFETIME
591 addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
592 addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
593#endif
594
595 ret = if_ioctl_ipv6(SIOCAIFADDR_IN6, (caddr_t)&addreq);
596 if (ret < 0)
597 return ret;
598 return 0;
599}
600
601/*
602 * Helper for interface-addr un-install, non-netlink
603 */
604static int if_unset_prefix6_ctx(const struct zebra_dplane_ctx *ctx)
605{
606 int ret;
607 struct in6_aliasreq addreq;
608 struct sockaddr_in6 addr;
609 struct sockaddr_in6 mask;
610 struct prefix_ipv6 *p;
611
612 p = (struct prefix_ipv6 *)dplane_ctx_get_intf_addr(ctx);
613
614 memset(&addreq, 0, sizeof(addreq));
39fa2825 615 strlcpy((char *)&addreq.ifra_name,
0f1f6ce4
MS
616 dplane_ctx_get_ifname(ctx), sizeof(addreq.ifra_name));
617
618 memset(&addr, 0, sizeof(struct sockaddr_in6));
619 addr.sin6_addr = p->prefix;
620 addr.sin6_family = p->family;
621#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
622 addr.sin6_len = sizeof(struct sockaddr_in6);
623#endif
624 memcpy(&addreq.ifra_addr, &addr, sizeof(struct sockaddr_in6));
625
626 memset(&mask, 0, sizeof(struct sockaddr_in6));
627 masklen2ip6(p->prefixlen, &mask.sin6_addr);
628 mask.sin6_family = p->family;
629#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
630 mask.sin6_len = sizeof(struct sockaddr_in6);
631#endif
632 memcpy(&addreq.ifra_prefixmask, &mask, sizeof(struct sockaddr_in6));
633
6f0e3f6e 634#ifdef HAVE_STRUCT_IF6_ALIASREQ_IFRA_LIFETIME
d62a17ae 635 addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
636 addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
726f9b2b 637#endif
718e3744 638
d62a17ae 639 ret = if_ioctl_ipv6(SIOCDIFADDR_IN6, (caddr_t)&addreq);
640 if (ret < 0)
641 return ret;
642 return 0;
718e3744 643}
644#else
39fa2825
MS
645/* The old, pre-dataplane code here just returned, so we're retaining that
646 * choice.
647 */
648static int if_set_prefix6_ctx(const struct zebra_dplane_ctx *ctx)
718e3744 649{
d62a17ae 650 return 0;
718e3744 651}
652
39fa2825 653static int if_unset_prefix6_ctx(const struct zebra_dplane_ctx *ctx)
718e3744 654{
d62a17ae 655 return 0;
718e3744 656}
6f0e3f6e 657#endif /* HAVE_STRUCT_IN6_ALIASREQ */
718e3744 658
659#endif /* LINUX_IPV6 */