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 $
29 #include <sys/param.h>
30 #include <sys/socket.h>
31 #include <netinet/in.h>
33 #include <net/if_dl.h>
35 #include <net/if_var.h>
37 #include <net/route.h>
38 #include <netinet/in_systm.h>
39 #include <netinet/in_var.h>
40 #include <netinet/ip.h>
42 #include <netinet6/nd6.h>
51 #include <sys/ioctl.h>
52 #include <sys/sysctl.h>
67 #include "throughput.h"
68 #include "slcompress.h"
69 #include "descriptor.h"
86 #define IN6MASK128 {{{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
87 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }}}
88 static const struct in6_addr in6mask128
= IN6MASK128
;
92 iface_Create(const char *name
)
94 int mib
[6], maxtries
, err
;
95 size_t needed
, namelen
;
96 char *buf
, *ptr
, *end
;
97 struct if_msghdr
*ifm
;
98 struct ifa_msghdr
*ifam
;
99 struct sockaddr_dl
*dl
;
100 struct sockaddr
*sa
[RTAX_MAX
];
102 struct iface_addr
*addr
;
108 mib
[4] = NET_RT_IFLIST
;
114 if (maxtries
-- == 0 || (err
&& err
!= ENOMEM
)) {
115 fprintf(stderr
, "iface_Create: sysctl: %s\n", strerror(err
));
119 if (sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) < 0) {
120 fprintf(stderr
, "iface_Create: sysctl: estimate: %s\n",
125 if ((buf
= (char *)malloc(needed
)) == NULL
) {
126 fprintf(stderr
, "iface_Create: malloc failed: %s\n", strerror(errno
));
130 if (sysctl(mib
, 6, buf
, &needed
, NULL
, 0) < 0) {
135 } while (buf
== NULL
);
140 namelen
= strlen(name
);
142 while (ptr
< end
&& iface
== NULL
) {
143 ifm
= (struct if_msghdr
*)ptr
; /* On if_msghdr */
144 if (ifm
->ifm_type
!= RTM_IFINFO
)
146 dl
= (struct sockaddr_dl
*)(ifm
+ 1); /* Single _dl at end */
147 if (dl
->sdl_nlen
== namelen
&& !strncmp(name
, dl
->sdl_data
, namelen
)) {
148 iface
= (struct iface
*)malloc(sizeof *iface
);
150 fprintf(stderr
, "iface_Create: malloc: %s\n", strerror(errno
));
153 iface
->name
= strdup(name
);
154 iface
->index
= ifm
->ifm_index
;
155 iface
->flags
= ifm
->ifm_flags
;
160 ptr
+= ifm
->ifm_msglen
; /* First ifa_msghdr */
161 for (; ptr
< end
; ptr
+= ifam
->ifam_msglen
) {
162 ifam
= (struct ifa_msghdr
*)ptr
; /* Next if address */
164 if (ifam
->ifam_type
!= RTM_NEWADDR
) /* finished this if */
167 if (iface
!= NULL
&& ifam
->ifam_addrs
& RTA_IFA
) {
168 /* Found a configured interface ! */
169 iface_ParseHdr(ifam
, sa
);
171 if (sa
[RTAX_IFA
] && (sa
[RTAX_IFA
]->sa_family
== AF_INET
173 || sa
[RTAX_IFA
]->sa_family
== AF_INET6
176 /* Record the address */
178 addr
= (struct iface_addr
*)
179 realloc(iface
->addr
, (iface
->addrs
+ 1) * sizeof iface
->addr
[0]);
184 addr
+= iface
->addrs
;
187 ncprange_setsa(&addr
->ifa
, sa
[RTAX_IFA
], sa
[RTAX_NETMASK
]);
189 ncpaddr_setsa(&addr
->peer
, sa
[RTAX_BRD
]);
191 ncpaddr_init(&addr
->peer
);
203 iface_addr_Zap(const char *name
, struct iface_addr
*addr
, int s
)
205 struct ifaliasreq ifra
;
207 struct in6_aliasreq ifra6
;
209 struct sockaddr_in
*me4
, *msk4
, *peer4
;
210 struct sockaddr_storage ssme
, sspeer
, ssmsk
;
213 ncprange_getsa(&addr
->ifa
, &ssme
, &ssmsk
);
214 ncpaddr_getsa(&addr
->peer
, &sspeer
);
217 switch (ncprange_family(&addr
->ifa
)) {
219 memset(&ifra
, '\0', sizeof ifra
);
220 strncpy(ifra
.ifra_name
, name
, sizeof ifra
.ifra_name
- 1);
222 me4
= (struct sockaddr_in
*)&ifra
.ifra_addr
;
223 memcpy(me4
, &ssme
, sizeof *me4
);
225 msk4
= (struct sockaddr_in
*)&ifra
.ifra_mask
;
226 memcpy(msk4
, &ssmsk
, sizeof *msk4
);
228 peer4
= (struct sockaddr_in
*)&ifra
.ifra_broadaddr
;
229 if (ncpaddr_family(&addr
->peer
) == AF_UNSPEC
) {
230 peer4
->sin_family
= AF_INET
;
231 peer4
->sin_len
= sizeof(*peer4
);
232 peer4
->sin_addr
.s_addr
= INADDR_NONE
;
234 memcpy(peer4
, &sspeer
, sizeof *peer4
);
236 res
= ID0ioctl(s
, SIOCDIFADDR
, &ifra
);
237 if (log_IsKept(LogDEBUG
)) {
240 snprintf(buf
, sizeof buf
, "%s", ncprange_ntoa(&addr
->ifa
));
241 log_Printf(LogWARN
, "%s: DIFADDR %s -> %s returns %d\n",
242 ifra
.ifra_name
, buf
, ncpaddr_ntoa(&addr
->peer
), res
);
248 memset(&ifra6
, '\0', sizeof ifra6
);
249 strncpy(ifra6
.ifra_name
, name
, sizeof ifra6
.ifra_name
- 1);
251 memcpy(&ifra6
.ifra_addr
, &ssme
, sizeof ifra6
.ifra_addr
);
252 memcpy(&ifra6
.ifra_prefixmask
, &ssmsk
, sizeof ifra6
.ifra_prefixmask
);
253 ifra6
.ifra_prefixmask
.sin6_family
= AF_UNSPEC
;
254 if (ncpaddr_family(&addr
->peer
) == AF_UNSPEC
)
255 ifra6
.ifra_dstaddr
.sin6_family
= AF_UNSPEC
;
257 memcpy(&ifra6
.ifra_dstaddr
, &sspeer
, sizeof ifra6
.ifra_dstaddr
);
258 ifra6
.ifra_lifetime
.ia6t_vltime
= ND6_INFINITE_LIFETIME
;
259 ifra6
.ifra_lifetime
.ia6t_pltime
= ND6_INFINITE_LIFETIME
;
261 res
= ID0ioctl(s
, SIOCDIFADDR_IN6
, &ifra6
);
270 ncprange_family(&addr
->ifa
) == AF_INET6
? "_IN6" :
274 if (ncpaddr_family(&addr
->peer
) == AF_UNSPEC
)
275 log_Printf(LogWARN
, "iface rm: ioctl(SIOCDIFADDR%s, %s): %s\n",
276 end
, ncprange_ntoa(&addr
->ifa
), strerror(errno
));
278 snprintf(dst
, sizeof dst
, "%s", ncpaddr_ntoa(&addr
->peer
));
279 log_Printf(LogWARN
, "iface rm: ioctl(SIOCDIFADDR%s, %s -> %s): %s\n",
280 end
, ncprange_ntoa(&addr
->ifa
), dst
, strerror(errno
));
288 iface_addr_Add(const char *name
, struct iface_addr
*addr
, int s
)
290 struct ifaliasreq ifra
;
292 struct in6_aliasreq ifra6
;
294 struct sockaddr_in
*me4
, *msk4
, *peer4
;
295 struct sockaddr_storage ssme
, sspeer
, ssmsk
;
298 ncprange_getsa(&addr
->ifa
, &ssme
, &ssmsk
);
299 ncpaddr_getsa(&addr
->peer
, &sspeer
);
302 switch (ncprange_family(&addr
->ifa
)) {
304 memset(&ifra
, '\0', sizeof ifra
);
305 strncpy(ifra
.ifra_name
, name
, sizeof ifra
.ifra_name
- 1);
307 me4
= (struct sockaddr_in
*)&ifra
.ifra_addr
;
308 memcpy(me4
, &ssme
, sizeof *me4
);
310 msk4
= (struct sockaddr_in
*)&ifra
.ifra_mask
;
311 memcpy(msk4
, &ssmsk
, sizeof *msk4
);
313 peer4
= (struct sockaddr_in
*)&ifra
.ifra_broadaddr
;
314 if (ncpaddr_family(&addr
->peer
) == AF_UNSPEC
) {
315 peer4
->sin_family
= AF_INET
;
316 peer4
->sin_len
= sizeof(*peer4
);
317 peer4
->sin_addr
.s_addr
= INADDR_NONE
;
319 memcpy(peer4
, &sspeer
, sizeof *peer4
);
321 res
= ID0ioctl(s
, SIOCAIFADDR
, &ifra
);
322 if (log_IsKept(LogDEBUG
)) {
325 snprintf(buf
, sizeof buf
, "%s", ncprange_ntoa(&addr
->ifa
));
326 log_Printf(LogWARN
, "%s: AIFADDR %s -> %s returns %d\n",
327 ifra
.ifra_name
, buf
, ncpaddr_ntoa(&addr
->peer
), res
);
333 memset(&ifra6
, '\0', sizeof ifra6
);
334 strncpy(ifra6
.ifra_name
, name
, sizeof ifra6
.ifra_name
- 1);
336 memcpy(&ifra6
.ifra_addr
, &ssme
, sizeof ifra6
.ifra_addr
);
337 memcpy(&ifra6
.ifra_prefixmask
, &ssmsk
, sizeof ifra6
.ifra_prefixmask
);
338 if (ncpaddr_family(&addr
->peer
) == AF_UNSPEC
)
339 ifra6
.ifra_dstaddr
.sin6_family
= AF_UNSPEC
;
340 else if (memcmp(&((struct sockaddr_in6
*)&ssmsk
)->sin6_addr
, &in6mask128
,
341 sizeof in6mask128
) == 0)
342 memcpy(&ifra6
.ifra_dstaddr
, &sspeer
, sizeof ifra6
.ifra_dstaddr
);
343 ifra6
.ifra_lifetime
.ia6t_vltime
= ND6_INFINITE_LIFETIME
;
344 ifra6
.ifra_lifetime
.ia6t_pltime
= ND6_INFINITE_LIFETIME
;
346 res
= ID0ioctl(s
, SIOCAIFADDR_IN6
, &ifra6
);
355 ncprange_family(&addr
->ifa
) == AF_INET6
? "_IN6" :
359 if (ncpaddr_family(&addr
->peer
) == AF_UNSPEC
)
360 log_Printf(LogWARN
, "iface add: ioctl(SIOCAIFADDR%s, %s): %s\n",
361 end
, ncprange_ntoa(&addr
->ifa
), strerror(errno
));
363 snprintf(dst
, sizeof dst
, "%s", ncpaddr_ntoa(&addr
->peer
));
364 log_Printf(LogWARN
, "iface add: ioctl(SIOCAIFADDR%s, %s -> %s): %s\n",
365 end
, ncprange_ntoa(&addr
->ifa
), dst
, strerror(errno
));
374 iface_Clear(struct iface
*iface
, struct ncp
*ncp
, int family
, int how
)
376 int af
, inskip
, in6skip
, s4
= -1, s6
= -1, *s
;
380 inskip
= in6skip
= how
== IFACE_CLEAR_ALL
? 0 : 1;
382 for (n
= 0; n
< iface
->addrs
; n
++) {
383 af
= ncprange_family(&iface
->addr
[n
].ifa
);
384 if (family
== 0 || family
== af
) {
385 if (!iface
->addr
[n
].system
&& (how
& IFACE_SYSTEM
))
409 if (*s
== -1 && (*s
= ID0socket(af
, SOCK_DGRAM
, 0)) == -1)
410 log_Printf(LogERROR
, "iface_Clear: socket(): %s\n", strerror(errno
));
411 else if (iface_addr_Zap(iface
->name
, iface
->addr
+ n
, *s
)) {
412 ncp_IfaceAddrDeleted(ncp
, iface
->addr
+ n
);
413 bcopy(iface
->addr
+ n
+ 1, iface
->addr
+ n
,
414 (iface
->addrs
- n
- 1) * sizeof *iface
->addr
);
421 /* Don't bother realloc()ing - we have little to gain */
431 iface_Add(struct iface
*iface
, struct ncp
*ncp
, const struct ncprange
*ifa
,
432 const struct ncpaddr
*peer
, int how
)
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
;
522 if ((s
= ID0socket(ncpaddr_family(del
), SOCK_DGRAM
, 0)) == -1) {
523 log_Printf(LogERROR
, "iface_Delete: socket(): %s\n", strerror(errno
));
527 for (n
= res
= 0; n
< iface
->addrs
; n
++) {
528 ncprange_getaddr(&iface
->addr
[n
].ifa
, &found
);
529 if (ncpaddr_equal(&found
, del
)) {
530 if (iface_addr_Zap(iface
->name
, iface
->addr
+ n
, s
)) {
531 ncp_IfaceAddrDeleted(ncp
, iface
->addr
+ n
);
532 bcopy(iface
->addr
+ n
+ 1, iface
->addr
+ n
,
533 (iface
->addrs
- n
- 1) * sizeof *iface
->addr
);
546 #define IFACE_ADDFLAGS 1
547 #define IFACE_DELFLAGS 2
550 iface_ChangeFlags(const char *ifname
, int flags
, int how
)
555 s
= ID0socket(PF_INET
, SOCK_DGRAM
, 0);
557 log_Printf(LogERROR
, "iface_ChangeFlags: socket: %s\n", strerror(errno
));
561 memset(&ifrq
, '\0', sizeof ifrq
);
562 strncpy(ifrq
.ifr_name
, ifname
, sizeof ifrq
.ifr_name
- 1);
563 ifrq
.ifr_name
[sizeof ifrq
.ifr_name
- 1] = '\0';
564 if (ID0ioctl(s
, SIOCGIFFLAGS
, &ifrq
) < 0) {
565 log_Printf(LogERROR
, "iface_ChangeFlags: ioctl(SIOCGIFFLAGS): %s\n",
571 if (how
== IFACE_ADDFLAGS
)
572 ifrq
.ifr_flags
|= flags
;
574 ifrq
.ifr_flags
&= ~flags
;
576 if (ID0ioctl(s
, SIOCSIFFLAGS
, &ifrq
) < 0) {
577 log_Printf(LogERROR
, "iface_ChangeFlags: ioctl(SIOCSIFFLAGS): %s\n",
584 return 1; /* Success */
588 iface_SetFlags(const char *ifname
, int flags
)
590 return iface_ChangeFlags(ifname
, flags
, IFACE_ADDFLAGS
);
594 iface_ClearFlags(const char *ifname
, int flags
)
596 return iface_ChangeFlags(ifname
, flags
, IFACE_DELFLAGS
);
600 iface_Destroy(struct iface
*iface
)
603 * iface_Clear(iface, IFACE_CLEAR_ALL) must be called manually
604 * if that's what the user wants. It's better to leave the interface
605 * allocated so that existing connections can continue to work.
615 #define if_entry(x) { IFF_##x, #x }
625 if_entry(POINTOPOINT
),
640 iface_Show(struct cmdargs
const *arg
)
642 struct ncpaddr ncpaddr
;
643 struct iface
*iface
= arg
->bundle
->iface
, *current
;
651 mask
.s_addr
= 0; /* avoid gcc warnings */
653 current
= iface_Create(iface
->name
);
654 flags
= iface
->flags
= current
->flags
;
655 iface_Destroy(current
);
657 prompt_Printf(arg
->prompt
, "%s (idx %d) <", iface
->name
, iface
->index
);
658 for (f
= 0; f
< NELEM(if_flags
); f
++)
659 if ((if_flags
[f
].flag
& flags
)) {
660 prompt_Printf(arg
->prompt
, "%s%s", flags
== iface
->flags
? "" : ",",
662 flags
&= ~if_flags
[f
].flag
;
667 prompt_Printf(arg
->prompt
, "%s0x%x", flags
== iface
->flags
? "" : ",",
671 prompt_Printf(arg
->prompt
, "> mtu %lu has %d address%s:\n", iface
->mtu
,
672 iface
->addrs
, iface
->addrs
== 1 ? "" : "es");
674 for (f
= 0; f
< iface
->addrs
; f
++) {
675 ncprange_getaddr(&iface
->addr
[f
].ifa
, &ncpaddr
);
676 switch (ncprange_family(&iface
->addr
[f
].ifa
)) {
678 prompt_Printf(arg
->prompt
, " inet %s --> ", ncpaddr_ntoa(&ncpaddr
));
679 if (ncpaddr_family(&iface
->addr
[f
].peer
) == AF_UNSPEC
)
680 prompt_Printf(arg
->prompt
, "255.255.255.255");
682 prompt_Printf(arg
->prompt
, "%s", ncpaddr_ntoa(&iface
->addr
[f
].peer
));
683 ncprange_getip4mask(&iface
->addr
[f
].ifa
, &mask
);
684 prompt_Printf(arg
->prompt
, " netmask 0x%08lx", (long)ntohl(mask
.s_addr
));
689 prompt_Printf(arg
->prompt
, " inet6 %s", ncpaddr_ntoa(&ncpaddr
));
690 if (ncpaddr_family(&iface
->addr
[f
].peer
) != AF_UNSPEC
)
691 prompt_Printf(arg
->prompt
, " --> %s",
692 ncpaddr_ntoa(&iface
->addr
[f
].peer
));
693 ncprange_getwidth(&iface
->addr
[f
].ifa
, &width
);
694 if (ncpaddr_family(&iface
->addr
[f
].peer
) == AF_UNSPEC
)
695 prompt_Printf(arg
->prompt
, " prefixlen %d", width
);
696 if ((scopeid
= ncprange_scopeid(&iface
->addr
[f
].ifa
)) != -1)
697 prompt_Printf(arg
->prompt
, " scopeid 0x%x", (unsigned)scopeid
);
701 prompt_Printf(arg
->prompt
, "\n");
708 iface_ParseHdr(struct ifa_msghdr
*ifam
, struct sockaddr
*sa
[RTAX_MAX
])
713 wp
= (char *)(ifam
+ 1);
715 for (rtax
= 0; rtax
< RTAX_MAX
; rtax
++)
716 if (ifam
->ifam_addrs
& (1 << rtax
)) {
717 sa
[rtax
] = (struct sockaddr
*)wp
;
718 wp
+= RT_ROUNDUP(sa
[rtax
]->sa_len
);