-/* $OpenBSD: if_etherbridge.c,v 1.1 2021/02/21 03:26:46 dlg Exp $ */
+/* $OpenBSD: if_etherbridge.c,v 1.2 2021/02/24 01:20:03 dlg Exp $ */
/*
* Copyright (c) 2018, 2021 David Gwynne <dlg@openbsd.org>
return (RBT_INSERT(eb_tree, &eb->eb_tree, ebe));
}
+static inline struct eb_entry *
+ebt_find(struct etherbridge *eb, const struct eb_entry *ebe)
+{
+ return (RBT_FIND(eb_tree, &eb->eb_tree, ebe));
+}
+
static inline void
ebt_replace(struct etherbridge *eb, struct eb_entry *oebe,
struct eb_entry *nebe)
}
}
+int
+etherbridge_add_addr(struct etherbridge *eb, void *port,
+ const struct ether_addr *ea, unsigned int type)
+{
+ struct eb_list *ebl;
+ struct eb_entry *nebe;
+ unsigned int num;
+ void *nport;
+ int error = 0;
+
+ if (ETHER_IS_MULTICAST(ea->ether_addr_octet) ||
+ ETHER_IS_EQ(ea->ether_addr_octet, etheranyaddr))
+ return (EADDRNOTAVAIL);
+
+ nport = eb_port_take(eb, port);
+ if (nport == NULL)
+ return (ENOMEM);
+
+ nebe = pool_get(&eb_entry_pool, PR_NOWAIT);
+ if (nebe == NULL) {
+ eb_port_rele(eb, nport);
+ return (ENOMEM);
+ }
+
+ smr_init(&nebe->ebe_smr_entry);
+ refcnt_init(&nebe->ebe_refs);
+ nebe->ebe_etherbridge = eb;
+
+ nebe->ebe_addr = *ea;
+ nebe->ebe_port = nport;
+ nebe->ebe_type = type;
+ nebe->ebe_age = getuptime();
+
+ ebl = etherbridge_list(eb, ea);
+
+ mtx_enter(&eb->eb_lock);
+ num = eb->eb_num + 1;
+ if (num >= eb->eb_max)
+ error = ENOSPC;
+ else if (ebt_insert(eb, nebe) != NULL)
+ error = EADDRINUSE;
+ else {
+ /* we win, do the insert */
+ ebl_insert(ebl, nebe); /* give the ref to etherbridge */
+ eb->eb_num = num;
+ }
+ mtx_leave(&eb->eb_lock);
+
+ if (error != 0) {
+ /*
+ * the new entry didnt make it into the
+ * table, so it can be freed directly.
+ */
+ ebe_free(nebe);
+ }
+
+ return (error);
+}
+int
+etherbridge_del_addr(struct etherbridge *eb, const struct ether_addr *ea)
+{
+ struct eb_list *ebl;
+ struct eb_entry *oebe;
+ const struct eb_entry key = {
+ .ebe_addr = *ea,
+ };
+ int error = 0;
+
+ ebl = etherbridge_list(eb, ea);
+
+ mtx_enter(&eb->eb_lock);
+ oebe = ebt_find(eb, &key);
+ if (oebe == NULL)
+ error = ESRCH;
+ else {
+ KASSERT(eb->eb_num > 0);
+ eb->eb_num--;
+
+ ebl_remove(ebl, oebe); /* it's our ref now */
+ ebt_remove(eb, oebe);
+ }
+ mtx_leave(&eb->eb_lock);
+
+ if (oebe != NULL)
+ ebe_rele(oebe);
+
+ return (error);
+}
+
static void
etherbridge_age(void *arg)
{
-/* $OpenBSD: if_etherbridge.h,v 1.1 2021/02/21 03:26:46 dlg Exp $ */
+/* $OpenBSD: if_etherbridge.h,v 1.2 2021/02/24 01:20:03 dlg Exp $ */
/*
* Copyright (c) 2018, 2021 David Gwynne <dlg@openbsd.org>
int etherbridge_set_tmo(struct etherbridge *, struct ifbrparam *);
int etherbridge_get_tmo(struct etherbridge *, struct ifbrparam *);
int etherbridge_rtfind(struct etherbridge *, struct ifbaconf *);
+int etherbridge_add_addr(struct etherbridge *, void *,
+ const struct ether_addr *, unsigned int);
+int etherbridge_del_addr(struct etherbridge *, const struct ether_addr *);
void etherbridge_flush(struct etherbridge *, uint32_t);
static inline unsigned int
-/* $OpenBSD: if_veb.c,v 1.7 2021/02/23 23:42:17 dlg Exp $ */
+/* $OpenBSD: if_veb.c,v 1.8 2021/02/24 01:20:03 dlg Exp $ */
/*
* Copyright (c) 2021 David Gwynne <dlg@openbsd.org>
static int veb_port_get_flags(struct veb_softc *, struct ifbreq *);
static int veb_port_set_protected(struct veb_softc *,
const struct ifbreq *);
+static int veb_add_addr(struct veb_softc *, const struct ifbareq *);
+static int veb_del_addr(struct veb_softc *, const struct ifbareq *);
static int veb_rule_add(struct veb_softc *, const struct ifbrlreq *);
static int veb_rule_list_flush(struct veb_softc *,
etherbridge_flush(&sc->sc_eb,
((struct ifbreq *)data)->ifbr_ifsflags);
break;
+ case SIOCBRDGSADDR:
+ error = veb_add_addr(sc, (struct ifbareq *)data);
+ break;
+ case SIOCBRDGDADDR:
+ error = veb_del_addr(sc, (struct ifbareq *)data);
+ break;
case SIOCBRDGSIFPROT:
error = veb_port_set_protected(sc, (struct ifbreq *)data);
return (0);
}
+static int
+veb_add_addr(struct veb_softc *sc, const struct ifbareq *ifba)
+{
+ struct veb_port *p;
+ int error = 0;
+ unsigned int type;
+
+ if (ISSET(ifba->ifba_flags, ~IFBAF_TYPEMASK))
+ return (EINVAL);
+ switch (ifba->ifba_flags & IFBAF_TYPEMASK) {
+ case IFBAF_DYNAMIC:
+ type = EBE_DYNAMIC;
+ break;
+ case IFBAF_STATIC:
+ type = EBE_STATIC;
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ if (ifba->ifba_dstsa.ss_family != AF_UNSPEC)
+ return (EAFNOSUPPORT);
+
+ p = veb_port_get(sc, ifba->ifba_ifsname);
+ if (p == NULL)
+ return (ESRCH);
+
+ error = etherbridge_add_addr(&sc->sc_eb, p, &ifba->ifba_dst, type);
+
+ veb_port_put(sc, p);
+
+ return (error);
+}
+
+static int
+veb_del_addr(struct veb_softc *sc, const struct ifbareq *ifba)
+{
+ return (etherbridge_del_addr(&sc->sc_eb, &ifba->ifba_dst));
+}
+
static int
veb_p_ioctl(struct ifnet *ifp0, u_long cmd, caddr_t data)
{