2 * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * $FreeBSD: src/usr.sbin/ppp/iface.c,v 1.13.2.9 2003/04/29 16:04:41 ume Exp $
27 * $DragonFly: src/usr.sbin/ppp/iface.c,v 1.3 2004/02/03 07:11:47 dillon Exp $
30 #include <sys/param.h>
31 #include <sys/socket.h>
32 #include <netinet/in.h>
34 #include <net/if_dl.h>
36 #include <net/if_var.h>
38 #include <net/route.h>
39 #include <netinet/in_systm.h>
40 #include <netinet/in_var.h>
41 #include <netinet/ip.h>
43 #include <netinet6/nd6.h>
52 #include <sys/ioctl.h>
53 #include <sys/sysctl.h>
68 #include "throughput.h"
69 #include "slcompress.h"
70 #include "descriptor.h"
87 #define IN6MASK128 {{{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
88 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }}}
89 static const struct in6_addr in6mask128
= IN6MASK128
;
93 iface_Create(const char *name
)
95 int mib
[6], maxtries
, err
;
96 size_t needed
, namelen
;
97 char *buf
, *ptr
, *end
;
98 struct if_msghdr
*ifm
;
99 struct ifa_msghdr
*ifam
;
100 struct sockaddr_dl
*dl
;
101 struct sockaddr
*sa
[RTAX_MAX
];
103 struct iface_addr
*addr
;
109 mib
[4] = NET_RT_IFLIST
;
115 if (maxtries
-- == 0 || (err
&& err
!= ENOMEM
)) {
116 fprintf(stderr
, "iface_Create: sysctl: %s\n", strerror(err
));
120 if (sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) < 0) {
121 fprintf(stderr
, "iface_Create: sysctl: estimate: %s\n",
126 if ((buf
= (char *)malloc(needed
)) == NULL
) {
127 fprintf(stderr
, "iface_Create: malloc failed: %s\n", strerror(errno
));
131 if (sysctl(mib
, 6, buf
, &needed
, NULL
, 0) < 0) {
136 } while (buf
== NULL
);
141 namelen
= strlen(name
);
143 while (ptr
< end
&& iface
== NULL
) {
144 ifm
= (struct if_msghdr
*)ptr
; /* On if_msghdr */
145 if (ifm
->ifm_type
!= RTM_IFINFO
)
147 dl
= (struct sockaddr_dl
*)(ifm
+ 1); /* Single _dl at end */
148 if (dl
->sdl_nlen
== namelen
&& !strncmp(name
, dl
->sdl_data
, namelen
)) {
149 iface
= (struct iface
*)malloc(sizeof *iface
);
151 fprintf(stderr
, "iface_Create: malloc: %s\n", strerror(errno
));
154 iface
->name
= strdup(name
);
155 iface
->index
= ifm
->ifm_index
;
156 iface
->flags
= ifm
->ifm_flags
;
161 ptr
+= ifm
->ifm_msglen
; /* First ifa_msghdr */
162 for (; ptr
< end
; ptr
+= ifam
->ifam_msglen
) {
163 ifam
= (struct ifa_msghdr
*)ptr
; /* Next if address */
165 if (ifam
->ifam_type
!= RTM_NEWADDR
) /* finished this if */
168 if (iface
!= NULL
&& ifam
->ifam_addrs
& RTA_IFA
) {
169 /* Found a configured interface ! */
170 iface_ParseHdr(ifam
, sa
);
172 if (sa
[RTAX_IFA
] && (sa
[RTAX_IFA
]->sa_family
== AF_INET
174 || sa
[RTAX_IFA
]->sa_family
== AF_INET6
177 /* Record the address */
179 addr
= (struct iface_addr
*)
180 realloc(iface
->addr
, (iface
->addrs
+ 1) * sizeof iface
->addr
[0]);
185 addr
+= iface
->addrs
;
188 ncprange_setsa(&addr
->ifa
, sa
[RTAX_IFA
], sa
[RTAX_NETMASK
]);
190 ncpaddr_setsa(&addr
->peer
, sa
[RTAX_BRD
]);
192 ncpaddr_init(&addr
->peer
);
204 iface_addr_Zap(const char *name
, struct iface_addr
*addr
, int s
)
206 struct ifaliasreq ifra
;
208 struct in6_aliasreq ifra6
;
210 struct sockaddr_in
*me4
, *msk4
, *peer4
;
211 struct sockaddr_storage ssme
, sspeer
, ssmsk
;
214 ncprange_getsa(&addr
->ifa
, &ssme
, &ssmsk
);
215 ncpaddr_getsa(&addr
->peer
, &sspeer
);
218 switch (ncprange_family(&addr
->ifa
)) {
220 memset(&ifra
, '\0', sizeof ifra
);
221 strncpy(ifra
.ifra_name
, name
, sizeof ifra
.ifra_name
- 1);
223 me4
= (struct sockaddr_in
*)&ifra
.ifra_addr
;
224 memcpy(me4
, &ssme
, sizeof *me4
);
226 msk4
= (struct sockaddr_in
*)&ifra
.ifra_mask
;
227 memcpy(msk4
, &ssmsk
, sizeof *msk4
);
229 peer4
= (struct sockaddr_in
*)&ifra
.ifra_broadaddr
;
230 if (ncpaddr_family(&addr
->peer
) == AF_UNSPEC
) {
231 peer4
->sin_family
= AF_INET
;
232 peer4
->sin_len
= sizeof(*peer4
);
233 peer4
->sin_addr
.s_addr
= INADDR_NONE
;
235 memcpy(peer4
, &sspeer
, sizeof *peer4
);
237 res
= ID0ioctl(s
, SIOCDIFADDR
, &ifra
);
238 if (log_IsKept(LogDEBUG
)) {
241 snprintf(buf
, sizeof buf
, "%s", ncprange_ntoa(&addr
->ifa
));
242 log_Printf(LogWARN
, "%s: DIFADDR %s -> %s returns %d\n",
243 ifra
.ifra_name
, buf
, ncpaddr_ntoa(&addr
->peer
), res
);
249 memset(&ifra6
, '\0', sizeof ifra6
);
250 strncpy(ifra6
.ifra_name
, name
, sizeof ifra6
.ifra_name
- 1);
252 memcpy(&ifra6
.ifra_addr
, &ssme
, sizeof ifra6
.ifra_addr
);
253 memcpy(&ifra6
.ifra_prefixmask
, &ssmsk
, sizeof ifra6
.ifra_prefixmask
);
254 ifra6
.ifra_prefixmask
.sin6_family
= AF_UNSPEC
;
255 if (ncpaddr_family(&addr
->peer
) == AF_UNSPEC
)
256 ifra6
.ifra_dstaddr
.sin6_family
= AF_UNSPEC
;
258 memcpy(&ifra6
.ifra_dstaddr
, &sspeer
, sizeof ifra6
.ifra_dstaddr
);
259 ifra6
.ifra_lifetime
.ia6t_vltime
= ND6_INFINITE_LIFETIME
;
260 ifra6
.ifra_lifetime
.ia6t_pltime
= ND6_INFINITE_LIFETIME
;
262 res
= ID0ioctl(s
, SIOCDIFADDR_IN6
, &ifra6
);
271 ncprange_family(&addr
->ifa
) == AF_INET6
? "_IN6" :
275 if (ncpaddr_family(&addr
->peer
) == AF_UNSPEC
)
276 log_Printf(LogWARN
, "iface rm: ioctl(SIOCDIFADDR%s, %s): %s\n",
277 end
, ncprange_ntoa(&addr
->ifa
), strerror(errno
));
279 snprintf(dst
, sizeof dst
, "%s", ncpaddr_ntoa(&addr
->peer
));
280 log_Printf(LogWARN
, "iface rm: ioctl(SIOCDIFADDR%s, %s -> %s): %s\n",
281 end
, ncprange_ntoa(&addr
->ifa
), dst
, strerror(errno
));
289 iface_addr_Add(const char *name
, struct iface_addr
*addr
, int s
)
291 struct ifaliasreq ifra
;
293 struct in6_aliasreq ifra6
;
295 struct sockaddr_in
*me4
, *msk4
, *peer4
;
296 struct sockaddr_storage ssme
, sspeer
, ssmsk
;
299 ncprange_getsa(&addr
->ifa
, &ssme
, &ssmsk
);
300 ncpaddr_getsa(&addr
->peer
, &sspeer
);
303 switch (ncprange_family(&addr
->ifa
)) {
305 memset(&ifra
, '\0', sizeof ifra
);
306 strncpy(ifra
.ifra_name
, name
, sizeof ifra
.ifra_name
- 1);
308 me4
= (struct sockaddr_in
*)&ifra
.ifra_addr
;
309 memcpy(me4
, &ssme
, sizeof *me4
);
311 msk4
= (struct sockaddr_in
*)&ifra
.ifra_mask
;
312 memcpy(msk4
, &ssmsk
, sizeof *msk4
);
314 peer4
= (struct sockaddr_in
*)&ifra
.ifra_broadaddr
;
315 if (ncpaddr_family(&addr
->peer
) == AF_UNSPEC
) {
316 peer4
->sin_family
= AF_INET
;
317 peer4
->sin_len
= sizeof(*peer4
);
318 peer4
->sin_addr
.s_addr
= INADDR_NONE
;
320 memcpy(peer4
, &sspeer
, sizeof *peer4
);
322 res
= ID0ioctl(s
, SIOCAIFADDR
, &ifra
);
323 if (log_IsKept(LogDEBUG
)) {
326 snprintf(buf
, sizeof buf
, "%s", ncprange_ntoa(&addr
->ifa
));
327 log_Printf(LogWARN
, "%s: AIFADDR %s -> %s returns %d\n",
328 ifra
.ifra_name
, buf
, ncpaddr_ntoa(&addr
->peer
), res
);
334 memset(&ifra6
, '\0', sizeof ifra6
);
335 strncpy(ifra6
.ifra_name
, name
, sizeof ifra6
.ifra_name
- 1);
337 memcpy(&ifra6
.ifra_addr
, &ssme
, sizeof ifra6
.ifra_addr
);
338 memcpy(&ifra6
.ifra_prefixmask
, &ssmsk
, sizeof ifra6
.ifra_prefixmask
);
339 if (ncpaddr_family(&addr
->peer
) == AF_UNSPEC
)
340 ifra6
.ifra_dstaddr
.sin6_family
= AF_UNSPEC
;
341 else if (memcmp(&((struct sockaddr_in6
*)&ssmsk
)->sin6_addr
, &in6mask128
,
342 sizeof in6mask128
) == 0)
343 memcpy(&ifra6
.ifra_dstaddr
, &sspeer
, sizeof ifra6
.ifra_dstaddr
);
344 ifra6
.ifra_lifetime
.ia6t_vltime
= ND6_INFINITE_LIFETIME
;
345 ifra6
.ifra_lifetime
.ia6t_pltime
= ND6_INFINITE_LIFETIME
;
347 res
= ID0ioctl(s
, SIOCAIFADDR_IN6
, &ifra6
);
356 ncprange_family(&addr
->ifa
) == AF_INET6
? "_IN6" :
360 if (ncpaddr_family(&addr
->peer
) == AF_UNSPEC
)
361 log_Printf(LogWARN
, "iface add: ioctl(SIOCAIFADDR%s, %s): %s\n",
362 end
, ncprange_ntoa(&addr
->ifa
), strerror(errno
));
364 snprintf(dst
, sizeof dst
, "%s", ncpaddr_ntoa(&addr
->peer
));
365 log_Printf(LogWARN
, "iface add: ioctl(SIOCAIFADDR%s, %s -> %s): %s\n",
366 end
, ncprange_ntoa(&addr
->ifa
), dst
, strerror(errno
));
375 iface_Clear(struct iface
*iface
, struct ncp
*ncp
, int family
, int how
)
377 int addrs
, af
, inskip
, in6skip
, n
, s4
= -1, s6
= -1, *s
;
380 inskip
= in6skip
= how
== IFACE_CLEAR_ALL
? 0 : 1;
383 for (n
= 0; n
< iface
->addrs
; n
++) {
384 af
= ncprange_family(&iface
->addr
[n
].ifa
);
385 if (family
== 0 || family
== af
) {
386 if (!iface
->addr
[n
].system
&& (how
& IFACE_SYSTEM
))
410 if (*s
== -1 && (*s
= ID0socket(af
, SOCK_DGRAM
, 0)) == -1)
411 log_Printf(LogERROR
, "iface_Clear: socket(): %s\n", strerror(errno
));
412 else if (iface_addr_Zap(iface
->name
, iface
->addr
+ n
, *s
)) {
413 ncp_IfaceAddrDeleted(ncp
, iface
->addr
+ n
);
414 bcopy(iface
->addr
+ n
+ 1, iface
->addr
+ n
,
415 (iface
->addrs
- n
- 1) * sizeof *iface
->addr
);
422 /* Don't bother realloc()ing - we have little to gain */
432 iface_Add(struct iface
*iface
, struct ncp
*ncp
, const struct ncprange
*ifa
,
433 const struct ncpaddr
*peer
, int how
)
435 int af
, n
, removed
, s
;
436 struct ncpaddr ncplocal
;
437 struct iface_addr
*addr
, newaddr
;
439 af
= ncprange_family(ifa
);
440 if ((s
= ID0socket(af
, SOCK_DGRAM
, 0)) == -1) {
441 log_Printf(LogERROR
, "iface_Add: socket(): %s\n", strerror(errno
));
444 ncprange_getaddr(ifa
, &ncplocal
);
446 for (n
= 0; n
< iface
->addrs
; n
++) {
447 if (ncprange_contains(&iface
->addr
[n
].ifa
, &ncplocal
) ||
448 ncpaddr_equal(&iface
->addr
[n
].peer
, peer
)) {
449 /* Replace this sockaddr */
450 if (!(how
& IFACE_FORCE_ADD
)) {
452 return 0; /* errno = EEXIST; */
455 if (ncprange_equal(&iface
->addr
[n
].ifa
, ifa
) &&
456 ncpaddr_equal(&iface
->addr
[n
].peer
, peer
)) {
458 return 1; /* Already there */
461 removed
= iface_addr_Zap(iface
->name
, iface
->addr
+ n
, s
);
463 ncp_IfaceAddrDeleted(ncp
, iface
->addr
+ n
);
464 ncprange_copy(&iface
->addr
[n
].ifa
, ifa
);
465 ncpaddr_copy(&iface
->addr
[n
].peer
, peer
);
466 if (!iface_addr_Add(iface
->name
, iface
->addr
+ n
, s
)) {
468 bcopy(iface
->addr
+ n
+ 1, iface
->addr
+ n
,
469 (iface
->addrs
- n
- 1) * sizeof *iface
->addr
);
477 ncp_IfaceAddrAdded(ncp
, iface
->addr
+ n
);
482 addr
= (struct iface_addr
*)realloc
483 (iface
->addr
, (iface
->addrs
+ 1) * sizeof iface
->addr
[0]);
485 log_Printf(LogERROR
, "iface_inAdd: realloc: %s\n", strerror(errno
));
491 ncprange_copy(&newaddr
.ifa
, ifa
);
492 ncpaddr_copy(&newaddr
.peer
, peer
);
493 newaddr
.system
= !!(how
& IFACE_SYSTEM
);
494 if (!iface_addr_Add(iface
->name
, &newaddr
, s
)) {
499 if (how
& IFACE_ADD_FIRST
) {
500 /* Stuff it at the start of our list */
502 bcopy(iface
->addr
, iface
->addr
+ 1, iface
->addrs
* sizeof *iface
->addr
);
507 memcpy(iface
->addr
+ n
, &newaddr
, sizeof(*iface
->addr
));
510 ncp_IfaceAddrAdded(ncp
, iface
->addr
+ n
);
516 iface_Delete(struct iface
*iface
, struct ncp
*ncp
, const struct ncpaddr
*del
)
518 struct ncpaddr found
;
521 if ((s
= ID0socket(ncpaddr_family(del
), SOCK_DGRAM
, 0)) == -1) {
522 log_Printf(LogERROR
, "iface_Delete: socket(): %s\n", strerror(errno
));
526 for (n
= res
= 0; n
< iface
->addrs
; n
++) {
527 ncprange_getaddr(&iface
->addr
[n
].ifa
, &found
);
528 if (ncpaddr_equal(&found
, del
)) {
529 if (iface_addr_Zap(iface
->name
, iface
->addr
+ n
, s
)) {
530 ncp_IfaceAddrDeleted(ncp
, iface
->addr
+ n
);
531 bcopy(iface
->addr
+ n
+ 1, iface
->addr
+ n
,
532 (iface
->addrs
- n
- 1) * sizeof *iface
->addr
);
545 #define IFACE_ADDFLAGS 1
546 #define IFACE_DELFLAGS 2
549 iface_ChangeFlags(const char *ifname
, int flags
, int how
)
554 s
= ID0socket(PF_INET
, SOCK_DGRAM
, 0);
556 log_Printf(LogERROR
, "iface_ChangeFlags: socket: %s\n", strerror(errno
));
560 memset(&ifrq
, '\0', sizeof ifrq
);
561 strncpy(ifrq
.ifr_name
, ifname
, sizeof ifrq
.ifr_name
- 1);
562 ifrq
.ifr_name
[sizeof ifrq
.ifr_name
- 1] = '\0';
563 if (ID0ioctl(s
, SIOCGIFFLAGS
, &ifrq
) < 0) {
564 log_Printf(LogERROR
, "iface_ChangeFlags: ioctl(SIOCGIFFLAGS): %s\n",
570 if (how
== IFACE_ADDFLAGS
)
571 ifrq
.ifr_flags
|= flags
;
573 ifrq
.ifr_flags
&= ~flags
;
575 if (ID0ioctl(s
, SIOCSIFFLAGS
, &ifrq
) < 0) {
576 log_Printf(LogERROR
, "iface_ChangeFlags: ioctl(SIOCSIFFLAGS): %s\n",
583 return 1; /* Success */
587 iface_SetFlags(const char *ifname
, int flags
)
589 return iface_ChangeFlags(ifname
, flags
, IFACE_ADDFLAGS
);
593 iface_ClearFlags(const char *ifname
, int flags
)
595 return iface_ChangeFlags(ifname
, flags
, IFACE_DELFLAGS
);
599 iface_Destroy(struct iface
*iface
)
602 * iface_Clear(iface, IFACE_CLEAR_ALL) must be called manually
603 * if that's what the user wants. It's better to leave the interface
604 * allocated so that existing connections can continue to work.
614 #define if_entry(x) { IFF_##x, #x }
624 if_entry(POINTOPOINT
),
639 iface_Show(struct cmdargs
const *arg
)
641 struct ncpaddr ncpaddr
;
642 struct iface
*iface
= arg
->bundle
->iface
, *current
;
649 current
= iface_Create(iface
->name
);
650 flags
= iface
->flags
= current
->flags
;
651 iface_Destroy(current
);
653 prompt_Printf(arg
->prompt
, "%s (idx %d) <", iface
->name
, iface
->index
);
654 for (f
= 0; f
< sizeof if_flags
/ sizeof if_flags
[0]; f
++)
655 if ((if_flags
[f
].flag
& flags
)) {
656 prompt_Printf(arg
->prompt
, "%s%s", flags
== iface
->flags
? "" : ",",
658 flags
&= ~if_flags
[f
].flag
;
663 prompt_Printf(arg
->prompt
, "%s0x%x", flags
== iface
->flags
? "" : ",",
667 prompt_Printf(arg
->prompt
, "> mtu %d has %d address%s:\n", iface
->mtu
,
668 iface
->addrs
, iface
->addrs
== 1 ? "" : "es");
670 for (f
= 0; f
< iface
->addrs
; f
++) {
671 ncprange_getaddr(&iface
->addr
[f
].ifa
, &ncpaddr
);
672 switch (ncprange_family(&iface
->addr
[f
].ifa
)) {
674 prompt_Printf(arg
->prompt
, " inet %s --> ", ncpaddr_ntoa(&ncpaddr
));
675 if (ncpaddr_family(&iface
->addr
[f
].peer
) == AF_UNSPEC
)
676 prompt_Printf(arg
->prompt
, "255.255.255.255");
678 prompt_Printf(arg
->prompt
, "%s", ncpaddr_ntoa(&iface
->addr
[f
].peer
));
679 ncprange_getip4mask(&iface
->addr
[f
].ifa
, &mask
);
680 prompt_Printf(arg
->prompt
, " netmask 0x%08lx", (long)ntohl(mask
.s_addr
));
685 prompt_Printf(arg
->prompt
, " inet6 %s", ncpaddr_ntoa(&ncpaddr
));
686 if (ncpaddr_family(&iface
->addr
[f
].peer
) != AF_UNSPEC
)
687 prompt_Printf(arg
->prompt
, " --> %s",
688 ncpaddr_ntoa(&iface
->addr
[f
].peer
));
689 ncprange_getwidth(&iface
->addr
[f
].ifa
, &width
);
690 if (ncpaddr_family(&iface
->addr
[f
].peer
) == AF_UNSPEC
)
691 prompt_Printf(arg
->prompt
, " prefixlen %d", width
);
692 if ((scopeid
= ncprange_scopeid(&iface
->addr
[f
].ifa
)) != -1)
693 prompt_Printf(arg
->prompt
, " scopeid 0x%x", (unsigned)scopeid
);
697 prompt_Printf(arg
->prompt
, "\n");
704 iface_ParseHdr(struct ifa_msghdr
*ifam
, struct sockaddr
*sa
[RTAX_MAX
])
709 wp
= (char *)(ifam
+ 1);
711 for (rtax
= 0; rtax
< RTAX_MAX
; rtax
++)
712 if (ifam
->ifam_addrs
& (1 << rtax
)) {
713 sa
[rtax
] = (struct sockaddr
*)wp
;
714 wp
+= ROUNDUP(sa
[rtax
]->sa_len
);