Annotation of embedaddon/quagga/zebra/ioctl.c, revision 1.1.1.2
1.1 misho 1: /*
2: * Common ioctl functions.
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: #ifdef HAVE_BSD_LINK_DETECT
37: #include <net/if_media.h>
38: #endif /* HAVE_BSD_LINK_DETECT*/
39:
40: extern struct zebra_privs_t zserv_privs;
41:
42: /* clear and set interface name string */
43: void
44: ifreq_set_name (struct ifreq *ifreq, struct interface *ifp)
45: {
46: strncpy (ifreq->ifr_name, ifp->name, IFNAMSIZ);
47: }
48:
49: /* call ioctl system call */
50: int
51: if_ioctl (u_long request, caddr_t buffer)
52: {
53: int sock;
54: int ret;
1.1.1.2 ! misho 55: int err = 0;
1.1 misho 56:
57: if (zserv_privs.change(ZPRIVS_RAISE))
58: zlog (NULL, LOG_ERR, "Can't raise privileges");
59: sock = socket (AF_INET, SOCK_DGRAM, 0);
60: if (sock < 0)
61: {
62: int save_errno = errno;
63: if (zserv_privs.change(ZPRIVS_LOWER))
64: zlog (NULL, LOG_ERR, "Can't lower privileges");
65: zlog_err("Cannot create UDP socket: %s", safe_strerror(save_errno));
66: exit (1);
67: }
68: if ((ret = ioctl (sock, request, buffer)) < 0)
69: err = errno;
70: if (zserv_privs.change(ZPRIVS_LOWER))
71: zlog (NULL, LOG_ERR, "Can't lower privileges");
72: close (sock);
73:
74: if (ret < 0)
75: {
76: errno = err;
77: return ret;
78: }
79: return 0;
80: }
81:
82: #ifdef HAVE_IPV6
83: static int
84: if_ioctl_ipv6 (u_long request, caddr_t buffer)
85: {
86: int sock;
87: int ret;
1.1.1.2 ! misho 88: int err = 0;
1.1 misho 89:
90: if (zserv_privs.change(ZPRIVS_RAISE))
91: zlog (NULL, LOG_ERR, "Can't raise privileges");
92: sock = socket (AF_INET6, SOCK_DGRAM, 0);
93: if (sock < 0)
94: {
95: int save_errno = errno;
96: if (zserv_privs.change(ZPRIVS_LOWER))
97: zlog (NULL, LOG_ERR, "Can't lower privileges");
98: zlog_err("Cannot create IPv6 datagram socket: %s",
99: safe_strerror(save_errno));
100: exit (1);
101: }
102:
103: if ((ret = ioctl (sock, request, buffer)) < 0)
104: err = errno;
105: if (zserv_privs.change(ZPRIVS_LOWER))
106: zlog (NULL, LOG_ERR, "Can't lower privileges");
107: close (sock);
108:
109: if (ret < 0)
110: {
111: errno = err;
112: return ret;
113: }
114: return 0;
115: }
116: #endif /* HAVE_IPV6 */
117:
118: /*
119: * get interface metric
120: * -- if value is not avaliable set -1
121: */
122: void
123: if_get_metric (struct interface *ifp)
124: {
125: #ifdef SIOCGIFMETRIC
126: struct ifreq ifreq;
127:
128: ifreq_set_name (&ifreq, ifp);
129:
130: if (if_ioctl (SIOCGIFMETRIC, (caddr_t) &ifreq) < 0)
131: return;
132: ifp->metric = ifreq.ifr_metric;
133: if (ifp->metric == 0)
134: ifp->metric = 1;
135: #else /* SIOCGIFMETRIC */
136: ifp->metric = -1;
137: #endif /* SIOCGIFMETRIC */
138: }
139:
140: /* get interface MTU */
141: void
142: if_get_mtu (struct interface *ifp)
143: {
144: struct ifreq ifreq;
145:
146: ifreq_set_name (&ifreq, ifp);
147:
148: #if defined(SIOCGIFMTU)
149: if (if_ioctl (SIOCGIFMTU, (caddr_t) & ifreq) < 0)
150: {
151: zlog_info ("Can't lookup mtu by ioctl(SIOCGIFMTU)");
152: ifp->mtu6 = ifp->mtu = -1;
153: return;
154: }
155:
156: #ifdef SUNOS_5
157: ifp->mtu6 = ifp->mtu = ifreq.ifr_metric;
158: #else
159: ifp->mtu6 = ifp->mtu = ifreq.ifr_mtu;
160: #endif /* SUNOS_5 */
161:
162: /* propogate */
163: zebra_interface_up_update(ifp);
164:
165: #else
166: zlog (NULL, LOG_INFO, "Can't lookup mtu on this system");
167: ifp->mtu6 = ifp->mtu = -1;
168: #endif
169: }
170:
171: #ifdef HAVE_NETLINK
172: /* Interface address setting via netlink interface. */
173: int
174: if_set_prefix (struct interface *ifp, struct connected *ifc)
175: {
176: return kernel_address_add_ipv4 (ifp, ifc);
177: }
178:
179: /* Interface address is removed using netlink interface. */
180: int
181: if_unset_prefix (struct interface *ifp, struct connected *ifc)
182: {
183: return kernel_address_delete_ipv4 (ifp, ifc);
184: }
185: #else /* ! HAVE_NETLINK */
186: #ifdef HAVE_STRUCT_IFALIASREQ
187: /* Set up interface's IP address, netmask (and broadcas? ). *BSD may
188: has ifaliasreq structure. */
189: int
190: if_set_prefix (struct interface *ifp, struct connected *ifc)
191: {
192: int ret;
193: struct ifaliasreq addreq;
194: struct sockaddr_in addr;
195: struct sockaddr_in mask;
196: struct prefix_ipv4 *p;
197:
198: p = (struct prefix_ipv4 *) ifc->address;
199: rib_lookup_and_pushup (p);
200:
201: memset (&addreq, 0, sizeof addreq);
202: strncpy ((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name);
203:
204: memset (&addr, 0, sizeof (struct sockaddr_in));
205: addr.sin_addr = p->prefix;
206: addr.sin_family = p->family;
207: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
208: addr.sin_len = sizeof (struct sockaddr_in);
209: #endif
210: memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in));
211:
212: memset (&mask, 0, sizeof (struct sockaddr_in));
213: masklen2ip (p->prefixlen, &mask.sin_addr);
214: mask.sin_family = p->family;
215: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
216: mask.sin_len = sizeof (struct sockaddr_in);
217: #endif
218: memcpy (&addreq.ifra_mask, &mask, sizeof (struct sockaddr_in));
219:
220: ret = if_ioctl (SIOCAIFADDR, (caddr_t) &addreq);
221: if (ret < 0)
222: return ret;
223: return 0;
224: }
225:
226: /* Set up interface's IP address, netmask (and broadcas? ). *BSD may
227: has ifaliasreq structure. */
228: int
229: if_unset_prefix (struct interface *ifp, struct connected *ifc)
230: {
231: int ret;
232: struct ifaliasreq addreq;
233: struct sockaddr_in addr;
234: struct sockaddr_in mask;
235: struct prefix_ipv4 *p;
236:
237: p = (struct prefix_ipv4 *)ifc->address;
238:
239: memset (&addreq, 0, sizeof addreq);
240: strncpy ((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name);
241:
242: memset (&addr, 0, sizeof (struct sockaddr_in));
243: addr.sin_addr = p->prefix;
244: addr.sin_family = p->family;
245: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
246: addr.sin_len = sizeof (struct sockaddr_in);
247: #endif
248: memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in));
249:
250: memset (&mask, 0, sizeof (struct sockaddr_in));
251: masklen2ip (p->prefixlen, &mask.sin_addr);
252: mask.sin_family = p->family;
253: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
254: mask.sin_len = sizeof (struct sockaddr_in);
255: #endif
256: memcpy (&addreq.ifra_mask, &mask, sizeof (struct sockaddr_in));
257:
258: ret = if_ioctl (SIOCDIFADDR, (caddr_t) &addreq);
259: if (ret < 0)
260: return ret;
261: return 0;
262: }
263: #else
264: /* Set up interface's address, netmask (and broadcas? ). Linux or
265: Solaris uses ifname:number semantics to set IP address aliases. */
266: int
267: if_set_prefix (struct interface *ifp, struct connected *ifc)
268: {
269: int ret;
270: struct ifreq ifreq;
271: struct sockaddr_in addr;
272: struct sockaddr_in broad;
273: struct sockaddr_in mask;
274: struct prefix_ipv4 ifaddr;
275: struct prefix_ipv4 *p;
276:
277: p = (struct prefix_ipv4 *) ifc->address;
278:
279: ifaddr = *p;
280:
281: ifreq_set_name (&ifreq, ifp);
282:
283: addr.sin_addr = p->prefix;
284: addr.sin_family = p->family;
285: memcpy (&ifreq.ifr_addr, &addr, sizeof (struct sockaddr_in));
286: ret = if_ioctl (SIOCSIFADDR, (caddr_t) &ifreq);
287: if (ret < 0)
288: return ret;
289:
290: /* We need mask for make broadcast addr. */
291: masklen2ip (p->prefixlen, &mask.sin_addr);
292:
293: if (if_is_broadcast (ifp))
294: {
295: apply_mask_ipv4 (&ifaddr);
296: addr.sin_addr = ifaddr.prefix;
297:
298: broad.sin_addr.s_addr = (addr.sin_addr.s_addr | ~mask.sin_addr.s_addr);
299: broad.sin_family = p->family;
300:
301: memcpy (&ifreq.ifr_broadaddr, &broad, sizeof (struct sockaddr_in));
302: ret = if_ioctl (SIOCSIFBRDADDR, (caddr_t) &ifreq);
303: if (ret < 0)
304: return ret;
305: }
306:
307: mask.sin_family = p->family;
308: #ifdef SUNOS_5
309: memcpy (&mask, &ifreq.ifr_addr, sizeof (mask));
310: #else
311: memcpy (&ifreq.ifr_netmask, &mask, sizeof (struct sockaddr_in));
312: #endif /* SUNOS5 */
313: ret = if_ioctl (SIOCSIFNETMASK, (caddr_t) &ifreq);
314: if (ret < 0)
315: return ret;
316:
317: return 0;
318: }
319:
320: /* Set up interface's address, netmask (and broadcas? ). Linux or
321: Solaris uses ifname:number semantics to set IP address aliases. */
322: int
323: if_unset_prefix (struct interface *ifp, struct connected *ifc)
324: {
325: int ret;
326: struct ifreq ifreq;
327: struct sockaddr_in addr;
328: struct prefix_ipv4 *p;
329:
330: p = (struct prefix_ipv4 *) ifc->address;
331:
332: ifreq_set_name (&ifreq, ifp);
333:
334: memset (&addr, 0, sizeof (struct sockaddr_in));
335: addr.sin_family = p->family;
336: memcpy (&ifreq.ifr_addr, &addr, sizeof (struct sockaddr_in));
337: ret = if_ioctl (SIOCSIFADDR, (caddr_t) &ifreq);
338: if (ret < 0)
339: return ret;
340:
341: return 0;
342: }
343: #endif /* HAVE_STRUCT_IFALIASREQ */
344: #endif /* HAVE_NETLINK */
345:
346: /* get interface flags */
347: void
348: if_get_flags (struct interface *ifp)
349: {
350: int ret;
351: struct ifreq ifreq;
352: #ifdef HAVE_BSD_LINK_DETECT
353: struct ifmediareq ifmr;
354: #endif /* HAVE_BSD_LINK_DETECT */
355:
356: ifreq_set_name (&ifreq, ifp);
357:
358: ret = if_ioctl (SIOCGIFFLAGS, (caddr_t) &ifreq);
359: if (ret < 0)
360: {
361: zlog_err("if_ioctl(SIOCGIFFLAGS) failed: %s", safe_strerror(errno));
362: return;
363: }
364: #ifdef HAVE_BSD_LINK_DETECT /* Detect BSD link-state at start-up */
365:
366: /* Per-default, IFF_RUNNING is held high, unless link-detect says
367: * otherwise - we abuse IFF_RUNNING inside zebra as a link-state flag,
368: * following practice on Linux and Solaris kernels
369: */
370: SET_FLAG(ifreq.ifr_flags, IFF_RUNNING);
371:
372: if (CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_LINKDETECTION))
373: {
374: (void) memset(&ifmr, 0, sizeof(ifmr));
375: strncpy (ifmr.ifm_name, ifp->name, IFNAMSIZ);
376:
377: /* Seems not all interfaces implement this ioctl */
378: if (if_ioctl(SIOCGIFMEDIA, (caddr_t) &ifmr) < 0)
379: zlog_err("if_ioctl(SIOCGIFMEDIA) failed: %s", safe_strerror(errno));
380: else if (ifmr.ifm_status & IFM_AVALID) /* Link state is valid */
381: {
382: if (ifmr.ifm_status & IFM_ACTIVE)
383: SET_FLAG(ifreq.ifr_flags, IFF_RUNNING);
384: else
385: UNSET_FLAG(ifreq.ifr_flags, IFF_RUNNING);
386: }
387: }
388: #endif /* HAVE_BSD_LINK_DETECT */
389:
390: if_flags_update (ifp, (ifreq.ifr_flags & 0x0000ffff));
391: }
392:
393: /* Set interface flags */
394: int
395: if_set_flags (struct interface *ifp, uint64_t flags)
396: {
397: int ret;
398: struct ifreq ifreq;
399:
400: memset (&ifreq, 0, sizeof(struct ifreq));
401: ifreq_set_name (&ifreq, ifp);
402:
403: ifreq.ifr_flags = ifp->flags;
404: ifreq.ifr_flags |= flags;
405:
406: ret = if_ioctl (SIOCSIFFLAGS, (caddr_t) &ifreq);
407:
408: if (ret < 0)
409: {
410: zlog_info ("can't set interface flags");
411: return ret;
412: }
413: return 0;
414: }
415:
416: /* Unset interface's flag. */
417: int
418: if_unset_flags (struct interface *ifp, uint64_t flags)
419: {
420: int ret;
421: struct ifreq ifreq;
422:
423: memset (&ifreq, 0, sizeof(struct ifreq));
424: ifreq_set_name (&ifreq, ifp);
425:
426: ifreq.ifr_flags = ifp->flags;
427: ifreq.ifr_flags &= ~flags;
428:
429: ret = if_ioctl (SIOCSIFFLAGS, (caddr_t) &ifreq);
430:
431: if (ret < 0)
432: {
433: zlog_info ("can't unset interface flags");
434: return ret;
435: }
436: return 0;
437: }
438:
439: #ifdef HAVE_IPV6
440:
441: #ifdef LINUX_IPV6
442: #ifndef _LINUX_IN6_H
443: /* linux/include/net/ipv6.h */
444: struct in6_ifreq
445: {
446: struct in6_addr ifr6_addr;
447: u_int32_t ifr6_prefixlen;
448: int ifr6_ifindex;
449: };
450: #endif /* _LINUX_IN6_H */
451:
452: /* Interface's address add/delete functions. */
453: int
454: if_prefix_add_ipv6 (struct interface *ifp, struct connected *ifc)
455: {
456: int ret;
457: struct prefix_ipv6 *p;
458: struct in6_ifreq ifreq;
459:
460: p = (struct prefix_ipv6 *) ifc->address;
461:
462: memset (&ifreq, 0, sizeof (struct in6_ifreq));
463:
464: memcpy (&ifreq.ifr6_addr, &p->prefix, sizeof (struct in6_addr));
465: ifreq.ifr6_ifindex = ifp->ifindex;
466: ifreq.ifr6_prefixlen = p->prefixlen;
467:
468: ret = if_ioctl_ipv6 (SIOCSIFADDR, (caddr_t) &ifreq);
469:
470: return ret;
471: }
472:
473: int
474: if_prefix_delete_ipv6 (struct interface *ifp, struct connected *ifc)
475: {
476: int ret;
477: struct prefix_ipv6 *p;
478: struct in6_ifreq ifreq;
479:
480: p = (struct prefix_ipv6 *) ifc->address;
481:
482: memset (&ifreq, 0, sizeof (struct in6_ifreq));
483:
484: memcpy (&ifreq.ifr6_addr, &p->prefix, sizeof (struct in6_addr));
485: ifreq.ifr6_ifindex = ifp->ifindex;
486: ifreq.ifr6_prefixlen = p->prefixlen;
487:
488: ret = if_ioctl_ipv6 (SIOCDIFADDR, (caddr_t) &ifreq);
489:
490: return ret;
491: }
492: #else /* LINUX_IPV6 */
493: #ifdef HAVE_STRUCT_IN6_ALIASREQ
494: #ifndef ND6_INFINITE_LIFETIME
495: #define ND6_INFINITE_LIFETIME 0xffffffffL
496: #endif /* ND6_INFINITE_LIFETIME */
497: int
498: if_prefix_add_ipv6 (struct interface *ifp, struct connected *ifc)
499: {
500: int ret;
501: struct in6_aliasreq addreq;
502: struct sockaddr_in6 addr;
503: struct sockaddr_in6 mask;
504: struct prefix_ipv6 *p;
505:
506: p = (struct prefix_ipv6 * ) ifc->address;
507:
508: memset (&addreq, 0, sizeof addreq);
509: strncpy ((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name);
510:
511: memset (&addr, 0, sizeof (struct sockaddr_in6));
512: addr.sin6_addr = p->prefix;
513: addr.sin6_family = p->family;
514: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
515: addr.sin6_len = sizeof (struct sockaddr_in6);
516: #endif
517: memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in6));
518:
519: memset (&mask, 0, sizeof (struct sockaddr_in6));
520: masklen2ip6 (p->prefixlen, &mask.sin6_addr);
521: mask.sin6_family = p->family;
522: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
523: mask.sin6_len = sizeof (struct sockaddr_in6);
524: #endif
525: memcpy (&addreq.ifra_prefixmask, &mask, sizeof (struct sockaddr_in6));
526:
527: addreq.ifra_lifetime.ia6t_vltime = 0xffffffff;
528: addreq.ifra_lifetime.ia6t_pltime = 0xffffffff;
529:
530: #ifdef HAVE_STRUCT_IF6_ALIASREQ_IFRA_LIFETIME
531: addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
532: addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
533: #endif
534:
535: ret = if_ioctl_ipv6 (SIOCAIFADDR_IN6, (caddr_t) &addreq);
536: if (ret < 0)
537: return ret;
538: return 0;
539: }
540:
541: int
542: if_prefix_delete_ipv6 (struct interface *ifp, struct connected *ifc)
543: {
544: int ret;
545: struct in6_aliasreq addreq;
546: struct sockaddr_in6 addr;
547: struct sockaddr_in6 mask;
548: struct prefix_ipv6 *p;
549:
550: p = (struct prefix_ipv6 *) ifc->address;
551:
552: memset (&addreq, 0, sizeof addreq);
553: strncpy ((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name);
554:
555: memset (&addr, 0, sizeof (struct sockaddr_in6));
556: addr.sin6_addr = p->prefix;
557: addr.sin6_family = p->family;
558: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
559: addr.sin6_len = sizeof (struct sockaddr_in6);
560: #endif
561: memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in6));
562:
563: memset (&mask, 0, sizeof (struct sockaddr_in6));
564: masklen2ip6 (p->prefixlen, &mask.sin6_addr);
565: mask.sin6_family = p->family;
566: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
567: mask.sin6_len = sizeof (struct sockaddr_in6);
568: #endif
569: memcpy (&addreq.ifra_prefixmask, &mask, sizeof (struct sockaddr_in6));
570:
571: #ifdef HAVE_STRUCT_IF6_ALIASREQ_IFRA_LIFETIME
572: addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
573: addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
574: #endif
575:
576: ret = if_ioctl_ipv6 (SIOCDIFADDR_IN6, (caddr_t) &addreq);
577: if (ret < 0)
578: return ret;
579: return 0;
580: }
581: #else
582: int
583: if_prefix_add_ipv6 (struct interface *ifp, struct connected *ifc)
584: {
585: return 0;
586: }
587:
588: int
589: if_prefix_delete_ipv6 (struct interface *ifp, struct connected *ifc)
590: {
591: return 0;
592: }
593: #endif /* HAVE_STRUCT_IN6_ALIASREQ */
594:
595: #endif /* LINUX_IPV6 */
596:
597: #endif /* HAVE_IPV6 */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>