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