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