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