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