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