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