summaryrefslogtreecommitdiffstats
path: root/sys/net/if.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/net/if.c')
-rw-r--r--sys/net/if.c139
1 files changed, 115 insertions, 24 deletions
diff --git a/sys/net/if.c b/sys/net/if.c
index 37d3008..7c560bc 100644
--- a/sys/net/if.c
+++ b/sys/net/if.c
@@ -35,6 +35,7 @@
*/
#include "opt_compat.h"
+#include "opt_inet.h"
#include <sys/param.h>
#include <sys/malloc.h>
@@ -53,6 +54,11 @@
#include <net/if_dl.h>
#include <net/radix.h>
+#ifdef INET6
+/*XXX*/
+#include <netinet/in.h>
+#endif
+
/*
* System initialization
*/
@@ -71,6 +77,14 @@ MALLOC_DEFINE(M_IFMADDR, "ether_multi", "link-level multicast address");
int ifqmaxlen = IFQ_MAXLEN;
struct ifnethead ifnet; /* depend on static init XXX */
+#ifdef INET6
+/*
+ * XXX: declare here to avoid to include many inet6 related files..
+ * should be more generalized?
+ */
+extern void nd6_setmtu __P((struct ifnet *));
+#endif
+
/*
* Network interface utility routines.
*
@@ -98,6 +112,7 @@ ifinit(dummy)
int if_index = 0;
struct ifaddr **ifnet_addrs;
+struct ifnet **ifindex2ifnet = NULL;
/*
@@ -131,19 +146,32 @@ if_attach(ifp)
* this unlikely case.
*/
TAILQ_INIT(&ifp->if_addrhead);
+ TAILQ_INIT(&ifp->if_prefixhead);
LIST_INIT(&ifp->if_multiaddrs);
getmicrotime(&ifp->if_lastchange);
if (ifnet_addrs == 0 || if_index >= if_indexlim) {
unsigned n = (if_indexlim <<= 1) * sizeof(ifa);
- struct ifaddr **q = (struct ifaddr **)
- malloc(n, M_IFADDR, M_WAITOK);
- bzero((caddr_t)q, n);
+ caddr_t q = malloc(n, M_IFADDR, M_WAITOK);
+ bzero(q, n);
if (ifnet_addrs) {
bcopy((caddr_t)ifnet_addrs, (caddr_t)q, n/2);
free((caddr_t)ifnet_addrs, M_IFADDR);
}
- ifnet_addrs = q;
+ ifnet_addrs = (struct ifaddr **)q;
+
+ /* grow ifindex2ifnet */
+ n = if_indexlim * sizeof(struct ifnet *);
+ q = malloc(n, M_IFADDR, M_WAITOK);
+ bzero(q, n);
+ if (ifindex2ifnet) {
+ bcopy((caddr_t)ifindex2ifnet, q, n/2);
+ free((caddr_t)ifindex2ifnet, M_IFADDR);
+ }
+ ifindex2ifnet = (struct ifnet **)q;
}
+
+ ifindex2ifnet[if_index] = ifp;
+
/*
* create a Link Level name for this device
*/
@@ -207,7 +235,7 @@ if_detach(ifp)
ifa = TAILQ_FIRST(&ifp->if_addrhead)) {
TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link);
IFAFREE(ifa);
- }
+ }
TAILQ_REMOVE(&ifnet, ifp, if_link);
}
@@ -226,13 +254,15 @@ ifa_ifwithaddr(addr)
#define equal(a1, a2) \
(bcmp((caddr_t)(a1), (caddr_t)(a2), ((struct sockaddr *)(a1))->sa_len) == 0)
for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next)
- for (ifa = ifp->if_addrhead.tqh_first; ifa;
+ for (ifa = ifp->if_addrhead.tqh_first; ifa;
ifa = ifa->ifa_link.tqe_next) {
if (ifa->ifa_addr->sa_family != addr->sa_family)
continue;
if (equal(addr, ifa->ifa_addr))
return (ifa);
if ((ifp->if_flags & IFF_BROADCAST) && ifa->ifa_broadaddr &&
+ /* IP6 doesn't have broadcast */
+ ifa->ifa_broadaddr->sa_len != 0 &&
equal(ifa->ifa_broadaddr, addr))
return (ifa);
}
@@ -251,7 +281,7 @@ ifa_ifwithdstaddr(addr)
for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next)
if (ifp->if_flags & IFF_POINTOPOINT)
- for (ifa = ifp->if_addrhead.tqh_first; ifa;
+ for (ifa = ifp->if_addrhead.tqh_first; ifa;
ifa = ifa->ifa_link.tqe_next) {
if (ifa->ifa_addr->sa_family != addr->sa_family)
continue;
@@ -285,7 +315,7 @@ ifa_ifwithnet(addr)
return (ifnet_addrs[sdl->sdl_index - 1]);
}
- /*
+ /*
* Scan though each interface, looking for ones that have
* addresses in this address family.
*/
@@ -296,13 +326,17 @@ ifa_ifwithnet(addr)
if (ifa->ifa_addr->sa_family != af)
next: continue;
- if (ifp->if_flags & IFF_POINTOPOINT) {
+ if (
+#ifdef INET6 /* XXX: for maching gif tunnel dst as routing entry gateway */
+ addr->sa_family != AF_INET6 &&
+#endif
+ ifp->if_flags & IFF_POINTOPOINT) {
/*
- * This is a bit broken as it doesn't
- * take into account that the remote end may
+ * This is a bit broken as it doesn't
+ * take into account that the remote end may
* be a single node in the network we are
* looking for.
- * The trouble is that we don't know the
+ * The trouble is that we don't know the
* netmask for the remote end.
*/
if (ifa->ifa_dstaddr != 0
@@ -372,7 +406,7 @@ ifaof_ifpforaddr(addr, ifp)
if (af >= AF_MAX)
return (0);
- for (ifa = ifp->if_addrhead.tqh_first; ifa;
+ for (ifa = ifp->if_addrhead.tqh_first; ifa;
ifa = ifa->ifa_link.tqe_next) {
if (ifa->ifa_addr->sa_family != af)
continue;
@@ -471,6 +505,9 @@ if_route(ifp, flag, fam)
if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family))
pfctlinput(PRC_IFUP, ifa->ifa_addr);
rt_ifmsg(ifp);
+#ifdef INET6
+ in6_if_up(ifp);
+#endif
}
/*
@@ -559,9 +596,9 @@ ifunit(name)
/*
* Look for a non numeric part
*/
- end = name + IFNAMSIZ;
+ end = name + IFNAMSIZ;
cp2 = namebuf;
- cp = name;
+ cp = name;
while ((cp < end) && (c = *cp)) {
if (c >= '0' && c <= '9')
break;
@@ -576,7 +613,7 @@ ifunit(name)
*/
len = cp - name + 1;
for (unit = 0;
- ((c = *cp) >= '0') && (c <= '9') && (unit < 1000000); cp++ )
+ ((c = *cp) >= '0') && (c <= '9') && (unit < 1000000); cp++ )
unit = (unit * 10) + (c - '0');
if (*cp != '\0')
return 0; /* no trailing garbage allowed */
@@ -592,6 +629,35 @@ ifunit(name)
return (ifp);
}
+
+/*
+ * Map interface name in a sockaddr_dl to
+ * interface structure pointer.
+ */
+struct ifnet *
+if_withname(sa)
+ struct sockaddr *sa;
+{
+ char ifname[IFNAMSIZ+1];
+ struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
+
+ if ( (sa->sa_family != AF_LINK) || (sdl->sdl_nlen == 0) ||
+ (sdl->sdl_nlen > IFNAMSIZ) )
+ return NULL;
+
+ /*
+ * ifunit wants a null-terminated name. It may not be null-terminated
+ * in the sockaddr. We don't want to change the caller's sockaddr,
+ * and there might not be room to put the trailing null anyway, so we
+ * make a local copy that we know we can null terminate safely.
+ */
+
+ bcopy(sdl->sdl_data, ifname, sdl->sdl_nlen);
+ ifname[sdl->sdl_nlen] = '\0';
+ return ifunit(ifname);
+}
+
+
/*
* Interface ioctls.
*/
@@ -606,6 +672,7 @@ ifioctl(so, cmd, data, p)
register struct ifreq *ifr;
struct ifstat *ifs;
int error;
+ short oif_flags;
switch (cmd) {
@@ -680,6 +747,9 @@ ifioctl(so, cmd, data, p)
return(error);
case SIOCSIFMTU:
+ {
+ u_long oldmtu = ifp->if_mtu;
+
error = suser(p);
if (error)
return (error);
@@ -690,7 +760,16 @@ ifioctl(so, cmd, data, p)
error = (*ifp->if_ioctl)(ifp, cmd, data);
if (error == 0)
getmicrotime(&ifp->if_lastchange);
- return(error);
+ /*
+ * If the link MTU changed, do network layer specific procedure.
+ */
+ if (ifp->if_mtu != oldmtu) {
+#ifdef INET6
+ nd6_setmtu(ifp);
+#endif
+ }
+ return (error);
+ }
case SIOCADDMULTI:
case SIOCDELMULTI:
@@ -739,10 +818,11 @@ ifioctl(so, cmd, data, p)
return ((*ifp->if_ioctl)(ifp, cmd, data));
default:
+ oif_flags = ifp->if_flags;
if (so->so_proto == 0)
return (EOPNOTSUPP);
#ifndef COMPAT_43
- return ((*so->so_proto->pr_usrreqs->pru_control)(so, cmd,
+ error = ((*so->so_proto->pr_usrreqs->pru_control)(so, cmd,
data,
ifp, p));
#else
@@ -793,11 +873,22 @@ ifioctl(so, cmd, data, p)
case OSIOCGIFBRDADDR:
case OSIOCGIFNETMASK:
*(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family;
- }
- return (error);
+ }
}
+#endif /* COMPAT_43 */
+
+ if ((oif_flags ^ ifp->if_flags) & IFF_UP) {
+#ifdef INET6
+ if (ifp->if_flags & IFF_UP) {
+ int s = splimp();
+ in6_if_up(ifp);
+ splx(s);
+ }
#endif
+ }
+ return (error);
+
}
return (0);
}
@@ -960,7 +1051,7 @@ if_allmulti(ifp, onswitch)
/*
* Add a multicast listenership to the interface in question.
- * The link layer provides a routine which converts
+ * The link layer provides a routine which converts
*/
int
if_addmulti(ifp, sa, retifma)
@@ -976,7 +1067,7 @@ if_addmulti(ifp, sa, retifma)
* If the matching multicast address already exists
* then don't add a new one, just add a reference
*/
- for (ifma = ifp->if_multiaddrs.lh_first; ifma;
+ for (ifma = ifp->if_multiaddrs.lh_first; ifma;
ifma = ifma->ifma_link.le_next) {
if (equal(sa, ifma->ifma_addr)) {
ifma->ifma_refcount++;
@@ -1063,7 +1154,7 @@ if_delmulti(ifp, sa)
struct ifmultiaddr *ifma;
int s;
- for (ifma = ifp->if_multiaddrs.lh_first; ifma;
+ for (ifma = ifp->if_multiaddrs.lh_first; ifma;
ifma = ifma->ifma_link.le_next)
if (equal(sa, ifma->ifma_addr))
break;
@@ -1096,7 +1187,7 @@ if_delmulti(ifp, sa)
* in the record for the link-layer address. (So we don't complain
* in that case.)
*/
- for (ifma = ifp->if_multiaddrs.lh_first; ifma;
+ for (ifma = ifp->if_multiaddrs.lh_first; ifma;
ifma = ifma->ifma_link.le_next)
if (equal(sa, ifma->ifma_addr))
break;
OpenPOWER on IntegriCloud