-/* $OpenBSD: if_gre.c,v 1.102 2018/02/16 01:28:07 dlg Exp $ */
+/* $OpenBSD: if_gre.c,v 1.103 2018/02/16 02:41:07 dlg Exp $ */
/* $NetBSD: if_gre.c,v 1.9 1999/10/25 19:18:11 drochner Exp $ */
/*
#include <sys/errno.h>
#include <sys/timeout.h>
#include <sys/queue.h>
+#include <sys/tree.h>
#include <crypto/siphash.h>
};
struct gre_tunnel {
- TAILQ_ENTRY(gre_tunnel) t_entry;
-
uint32_t t_key_mask;
#define GRE_KEY_NONE htonl(0x00000000U)
#define GRE_KEY_ENTROPY htonl(0xffffff00U)
sa_family_t t_af;
};
-TAILQ_HEAD(gre_list, gre_tunnel);
-
static inline int
gre_cmp(const struct gre_tunnel *, const struct gre_tunnel *);
*/
struct gre_softc {
- struct gre_tunnel sc_tunnel; /* must be first */
struct ifnet sc_if;
+ struct gre_tunnel sc_tunnel;
+ TAILQ_ENTRY(gre_softc) sc_entry;
+
struct timeout sc_ka_send;
struct timeout sc_ka_hold;
int sc_ka_recvtm;
};
+TAILQ_HEAD(gre_list, gre_softc);
+
struct gre_keepalive {
uint32_t gk_uptime;
uint32_t gk_random;
struct egre_softc {
struct gre_tunnel sc_tunnel; /* must be first */
+ RBT_ENTRY(egre_softc) sc_entry;
+
struct arpcom sc_ac;
struct ifmedia sc_media;
};
+RBT_HEAD(egre_tree, egre_softc);
+
+RBT_PROTOTYPE(egre_tree, egre_softc, sc_entry, egre_cmp);
+
static int egre_clone_create(struct if_clone *, int);
static int egre_clone_destroy(struct ifnet *);
static int egre_down(struct egre_softc *);
static int egre_input(const struct gre_tunnel *, struct mbuf *, int);
-static struct egre_softc *
- egre_find(const struct gre_tunnel *);
-
struct if_clone egre_cloner =
IF_CLONE_INITIALIZER("egre", egre_clone_create, egre_clone_destroy);
-struct gre_list egre_list = TAILQ_HEAD_INITIALIZER(gre_list);
+struct egre_tree egre_tree = RBT_INITIALIZER();
/*
* It is not easy to calculate the right value for a GRE MTU.
#endif
NET_LOCK();
- TAILQ_INSERT_TAIL(&gre_list, &sc->sc_tunnel, t_entry);
+ TAILQ_INSERT_TAIL(&gre_list, sc, sc_entry);
NET_UNLOCK();
return (0);
if (ISSET(ifp->if_flags, IFF_RUNNING))
gre_down(sc);
- TAILQ_REMOVE(&gre_list, &sc->sc_tunnel, t_entry);
+ TAILQ_REMOVE(&gre_list, sc, sc_entry);
NET_UNLOCK();
if_detach(ifp);
if_attach(ifp);
ether_ifattach(ifp);
- NET_LOCK();
- TAILQ_INSERT_TAIL(&egre_list, &sc->sc_tunnel, t_entry);
- NET_UNLOCK();
-
return (0);
}
NET_LOCK();
if (ISSET(ifp->if_flags, IFF_RUNNING))
egre_down(sc);
-
- TAILQ_REMOVE(&egre_list, &sc->sc_tunnel, t_entry);
NET_UNLOCK();
ifmedia_delete_instance(&sc->sc_media, IFM_INST_ANY);
static struct gre_softc *
gre_find(const struct gre_tunnel *key)
{
- struct gre_tunnel *t;
struct gre_softc *sc;
- TAILQ_FOREACH(t, &gre_list, t_entry) {
- if (gre_cmp(key, t) != 0)
+ TAILQ_FOREACH(sc, &gre_list, sc_entry) {
+ if (gre_cmp(key, &sc->sc_tunnel) != 0)
continue;
- sc = (struct gre_softc *)t;
if (!ISSET(sc->sc_if.if_flags, IFF_RUNNING))
continue;
return (-1);
}
-static struct egre_softc *
-egre_find(const struct gre_tunnel *key)
-{
- struct gre_tunnel *t;
- struct egre_softc *sc;
-
- TAILQ_FOREACH(t, &egre_list, t_entry) {
- if (gre_cmp(key, t) != 0)
- continue;
-
- sc = (struct egre_softc *)t;
- if (!ISSET(sc->sc_ac.ac_if.if_flags, IFF_RUNNING))
- continue;
-
- return (sc);
- }
-
- return (NULL);
-}
-
static int
egre_input(const struct gre_tunnel *key, struct mbuf *m, int hlen)
{
struct mbuf *n;
int off;
- sc = egre_find(key);
+ sc = RBT_FIND(egre_tree, &egre_tree, (const struct egre_softc *)key);
if (sc == NULL)
return (-1);
switch(cmd) {
case SIOCSIFADDR:
- ifp->if_flags |= IFF_UP;
- /* FALLTHROUGH */
+ break;
case SIOCSIFFLAGS:
if (ISSET(ifp->if_flags, IFF_UP)) {
if (!ISSET(ifp->if_flags, IFF_RUNNING))
case SIOCGLIFPHYTTL:
ifr->ifr_ttl = (int)sc->sc_tunnel.t_ttl;
- break;
+ case SIOCSVNETID:
+ case SIOCDVNETID:
+ case SIOCSLIFPHYADDR:
+ case SIOCDIFPHYADDR:
+ case SIOCSLIFPHYRTABLE:
+ if (ISSET(ifp->if_flags, IFF_RUNNING)) {
+ error = EBUSY;
+ break;
+ }
+
+ /* FALLTHROUGH */
default:
error = gre_tunnel_ioctl(ifp, &sc->sc_tunnel, cmd, data);
if (error == ENOTTY)
static int
gre_up(struct gre_softc *sc)
{
- if (sc->sc_tunnel.t_af == AF_UNSPEC)
- return (ENXIO);
-
NET_ASSERT_LOCKED();
SET(sc->sc_if.if_flags, IFF_RUNNING);
static int
egre_up(struct egre_softc *sc)
{
+ if (sc->sc_tunnel.t_af == AF_UNSPEC)
+ return (EDESTADDRREQ);
+
NET_ASSERT_LOCKED();
+ if (RBT_INSERT(egre_tree, &egre_tree, sc) != NULL)
+ return (EADDRINUSE);
+
SET(sc->sc_ac.ac_if.if_flags, IFF_RUNNING);
return (0);
CLR(sc->sc_ac.ac_if.if_flags, IFF_RUNNING);
+ RBT_REMOVE(egre_tree, &egre_tree, sc);
+
/* barrier? */
return (0);
return (0);
}
-static inline int
+static int
gre_cmp(const struct gre_tunnel *a, const struct gre_tunnel *b)
{
uint32_t ka, kb;
return (0);
}
+static int
+egre_cmp(const struct egre_softc *a, const struct egre_softc *b)
+{
+ return (gre_cmp(&a->sc_tunnel, &b->sc_tunnel));
+}
+
+RBT_GENERATE(egre_tree, egre_softc, sc_entry, egre_cmp);