]>
Commit | Line | Data |
---|---|---|
8842468c | 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 | * | |
896014f4 DL |
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 | |
8842468c | 20 | */ |
21 | ||
22 | #include <zebra.h> | |
23 | ||
ddfeb486 DL |
24 | #ifdef SUNOS_5 |
25 | ||
8842468c | 26 | #include "linklist.h" |
27 | #include "if.h" | |
28 | #include "prefix.h" | |
29 | #include "ioctl.h" | |
30 | #include "log.h" | |
48a46fa0 | 31 | #include "privs.h" |
82283592 | 32 | #include "vty.h" |
4db21619 | 33 | #include "vrf.h" |
174482ef | 34 | #include "lib_errors.h" |
8842468c | 35 | |
36 | #include "zebra/rib.h" | |
37 | #include "zebra/rt.h" | |
5c78b3d0 | 38 | #include "zebra/interface.h" |
8d610213 | 39 | #include "zebra/ioctl_solaris.h" |
8842468c | 40 | |
48a46fa0 | 41 | extern struct zebra_privs_t zserv_privs; |
8842468c | 42 | |
43 | /* clear and set interface name string */ | |
d62a17ae | 44 | void lifreq_set_name(struct lifreq *lifreq, const char *ifname) |
8842468c | 45 | { |
d62a17ae | 46 | strncpy(lifreq->lifr_name, ifname, IFNAMSIZ); |
8842468c | 47 | } |
48 | ||
d7c0a89a | 49 | int vrf_if_ioctl(unsigned long request, caddr_t buffer, vrf_id_t vrf_id) |
4db21619 PG |
50 | { |
51 | return if_ioctl(request, buffer); | |
52 | } | |
53 | ||
8842468c | 54 | /* call ioctl system call */ |
d7c0a89a | 55 | int if_ioctl(unsigned long request, caddr_t buffer) |
8842468c | 56 | { |
d62a17ae | 57 | int sock; |
58 | int ret; | |
59 | int err; | |
60 | ||
01b9e3fd DL |
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 | } | |
d62a17ae | 69 | |
01b9e3fd DL |
70 | if ((ret = ioctl(sock, request, buffer)) < 0) |
71 | err = errno; | |
d62a17ae | 72 | |
01b9e3fd | 73 | } |
d62a17ae | 74 | |
75 | close(sock); | |
76 | ||
77 | if (ret < 0) { | |
78 | errno = err; | |
79 | return ret; | |
80 | } | |
81 | return 0; | |
8842468c | 82 | } |
83 | ||
5b73a671 | 84 | |
d7c0a89a | 85 | int if_ioctl_ipv6(unsigned long request, caddr_t buffer) |
8842468c | 86 | { |
d62a17ae | 87 | int sock; |
88 | int ret; | |
89 | int err; | |
90 | ||
01b9e3fd DL |
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 | } | |
d62a17ae | 99 | |
01b9e3fd DL |
100 | if ((ret = ioctl(sock, request, buffer)) < 0) |
101 | err = errno; | |
d62a17ae | 102 | |
01b9e3fd | 103 | } |
d62a17ae | 104 | |
105 | close(sock); | |
106 | ||
107 | if (ret < 0) { | |
108 | errno = err; | |
109 | return ret; | |
110 | } | |
111 | ||
112 | return 0; | |
8842468c | 113 | } |
8842468c | 114 | |
115 | /* | |
116 | * get interface metric | |
117 | * -- if value is not avaliable set -1 | |
118 | */ | |
d62a17ae | 119 | void if_get_metric(struct interface *ifp) |
8842468c | 120 | { |
d62a17ae | 121 | struct lifreq lifreq; |
122 | int ret; | |
8842468c | 123 | |
d62a17ae | 124 | lifreq_set_name(&lifreq, ifp->name); |
8842468c | 125 | |
d62a17ae | 126 | if (ifp->flags & IFF_IPV4) |
127 | ret = AF_IOCTL(AF_INET, SIOCGLIFMETRIC, (caddr_t)&lifreq); | |
5b73a671 | 128 | #ifdef SOLARIS_IPV6 |
d62a17ae | 129 | else if (ifp->flags & IFF_IPV6) |
130 | ret = AF_IOCTL(AF_INET6, SIOCGLIFMETRIC, (caddr_t)&lifreq); | |
5b73a671 | 131 | #endif /* SOLARIS_IPV6 */ |
d62a17ae | 132 | else |
133 | ret = -1; | |
8842468c | 134 | |
d62a17ae | 135 | if (ret < 0) |
136 | return; | |
8842468c | 137 | |
d62a17ae | 138 | ifp->metric = lifreq.lifr_metric; |
139 | ||
140 | if (ifp->metric == 0) | |
141 | ifp->metric = 1; | |
8842468c | 142 | } |
143 | ||
144 | /* get interface MTU */ | |
d62a17ae | 145 | void if_get_mtu(struct interface *ifp) |
8842468c | 146 | { |
d62a17ae | 147 | struct lifreq lifreq; |
148 | int ret; | |
d7c0a89a | 149 | uint8_t changed = 0; |
d62a17ae | 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); | |
8842468c | 183 | } |
184 | ||
185 | /* Set up interface's address, netmask (and broadcast? ). | |
186 | Solaris uses ifname:number semantics to set IP address aliases. */ | |
d62a17ae | 187 | int if_set_prefix(struct interface *ifp, struct connected *ifc) |
8842468c | 188 | { |
d62a17ae | 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; | |
8842468c | 196 | |
d62a17ae | 197 | p = (struct prefix_ipv4 *)ifc->address; |
8842468c | 198 | |
d62a17ae | 199 | ifaddr = *p; |
8842468c | 200 | |
d62a17ae | 201 | strncpy(ifreq.ifr_name, ifp->name, IFNAMSIZ); |
8842468c | 202 | |
d62a17ae | 203 | addr.sin_addr = p->prefix; |
204 | addr.sin_family = p->family; | |
205 | memcpy(&ifreq.ifr_addr, &addr, sizeof(struct sockaddr_in)); | |
8842468c | 206 | |
d62a17ae | 207 | ret = if_ioctl(SIOCSIFADDR, (caddr_t)&ifreq); |
8842468c | 208 | |
d62a17ae | 209 | if (ret < 0) |
210 | return ret; | |
8842468c | 211 | |
d62a17ae | 212 | /* We need mask for make broadcast addr. */ |
213 | masklen2ip(p->prefixlen, &mask.sin_addr); | |
8842468c | 214 | |
d62a17ae | 215 | if (if_is_broadcast(ifp)) { |
216 | apply_mask_ipv4(&ifaddr); | |
217 | addr.sin_addr = ifaddr.prefix; | |
8842468c | 218 | |
d62a17ae | 219 | broad.sin_addr.s_addr = |
220 | (addr.sin_addr.s_addr | ~mask.sin_addr.s_addr); | |
221 | broad.sin_family = p->family; | |
8842468c | 222 | |
d62a17ae | 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 | } | |
8842468c | 229 | |
d62a17ae | 230 | mask.sin_family = p->family; |
8842468c | 231 | #ifdef SUNOS_5 |
d62a17ae | 232 | memcpy(&mask, &ifreq.ifr_addr, sizeof(mask)); |
8842468c | 233 | #else |
d62a17ae | 234 | memcpy(&ifreq.ifr_netmask, &mask, sizeof(struct sockaddr_in)); |
48a46fa0 | 235 | #endif /* SUNOS_5 */ |
d62a17ae | 236 | ret = if_ioctl(SIOCSIFNETMASK, (caddr_t)&ifreq); |
8842468c | 237 | |
d62a17ae | 238 | return ((ret < 0) ? ret : 0); |
8842468c | 239 | } |
240 | ||
241 | /* Set up interface's address, netmask (and broadcast). | |
242 | Solaris uses ifname:number semantics to set IP address aliases. */ | |
d62a17ae | 243 | int if_unset_prefix(struct interface *ifp, struct connected *ifc) |
8842468c | 244 | { |
d62a17ae | 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; | |
8842468c | 251 | |
d62a17ae | 252 | strncpy(ifreq.ifr_name, ifp->name, IFNAMSIZ); |
8842468c | 253 | |
d62a17ae | 254 | memset(&addr, 0, sizeof(struct sockaddr_in)); |
255 | addr.sin_family = p->family; | |
256 | memcpy(&ifreq.ifr_addr, &addr, sizeof(struct sockaddr_in)); | |
8842468c | 257 | |
d62a17ae | 258 | ret = if_ioctl(SIOCSIFADDR, (caddr_t)&ifreq); |
8842468c | 259 | |
d62a17ae | 260 | if (ret < 0) |
261 | return ret; | |
8842468c | 262 | |
d62a17ae | 263 | return 0; |
8842468c | 264 | } |
265 | ||
5c78b3d0 | 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.. | |
0752ef0b | 270 | */ |
d62a17ae | 271 | int if_get_flags_direct(const char *ifname, uint64_t *flags, unsigned int af) |
0752ef0b | 272 | { |
d62a17ae | 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; | |
0752ef0b | 287 | } |
288 | ||
8842468c | 289 | /* get interface flags */ |
d62a17ae | 290 | void if_get_flags(struct interface *ifp) |
8842468c | 291 | { |
d62a17ae | 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); | |
8842468c | 323 | } |
324 | ||
325 | /* Set interface flags */ | |
d62a17ae | 326 | int if_set_flags(struct interface *ifp, uint64_t flags) |
8842468c | 327 | { |
d62a17ae | 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; | |
8842468c | 350 | } |
351 | ||
352 | /* Unset interface's flag. */ | |
d62a17ae | 353 | int if_unset_flags(struct interface *ifp, uint64_t flags) |
8842468c | 354 | { |
d62a17ae | 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; | |
8842468c | 376 | } |
377 | ||
8842468c | 378 | /* Interface's address add/delete functions. */ |
d62a17ae | 379 | int if_prefix_add_ipv6(struct interface *ifp, struct connected *ifc) |
8842468c | 380 | { |
d62a17ae | 381 | char addrbuf[PREFIX_STRLEN]; |
8842468c | 382 | |
9df414fe | 383 | flog_warn(LIB_ERR_DEVELOPMENT, "Can't set %s on interface %s", |
d62a17ae | 384 | prefix2str(ifc->address, addrbuf, sizeof(addrbuf)), |
385 | ifp->name); | |
8842468c | 386 | |
d62a17ae | 387 | return 0; |
8842468c | 388 | } |
389 | ||
d62a17ae | 390 | int if_prefix_delete_ipv6(struct interface *ifp, struct connected *ifc) |
8842468c | 391 | { |
d62a17ae | 392 | char addrbuf[PREFIX_STRLEN]; |
8842468c | 393 | |
9df414fe | 394 | flog_warn(LIB_ERR_DEVELOPMENT, "Can't delete %s on interface %s", |
d62a17ae | 395 | prefix2str(ifc->address, addrbuf, sizeof(addrbuf)), |
396 | ifp->name); | |
8842468c | 397 | |
d62a17ae | 398 | return 0; |
8842468c | 399 | } |
ddfeb486 DL |
400 | |
401 | #endif /* SUNOS_5 */ |