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