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