summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/net/if_atm.h2
-rw-r--r--sys/net/if_atmsubr.c57
2 files changed, 59 insertions, 0 deletions
diff --git a/sys/net/if_atm.h b/sys/net/if_atm.h
index dc9fc6e..179caad 100644
--- a/sys/net/if_atm.h
+++ b/sys/net/if_atm.h
@@ -268,4 +268,6 @@ void atm_input(struct ifnet *, struct atm_pseudohdr *,
struct mbuf *, void *);
int atm_output(struct ifnet *, struct mbuf *, struct sockaddr *,
struct rtentry *);
+struct atmio_vcctable *atm_getvccs(struct atmio_vcc **, u_int, u_int,
+ struct mtx *, int);
#endif
diff --git a/sys/net/if_atmsubr.c b/sys/net/if_atmsubr.c
index ed02c2b..55393a7 100644
--- a/sys/net/if_atmsubr.c
+++ b/sys/net/if_atmsubr.c
@@ -52,6 +52,7 @@ __FBSDID("$FreeBSD$");
#include <sys/sockio.h>
#include <sys/errno.h>
#include <sys/sysctl.h>
+#include <sys/malloc.h>
#include <net/if.h>
#include <net/netisr.h>
@@ -404,6 +405,62 @@ atm_ifdetach(struct ifnet *ifp)
if_detach(ifp);
}
+/*
+ * Support routine for the SIOCATMGVCCS ioctl().
+ *
+ * This routine assumes, that the private VCC structures used by the driver
+ * begin with a struct atmio_vcc.
+ *
+ * Return a table of VCCs in a freshly allocated memory area.
+ * Here we have a problem: we first count, how many vccs we need
+ * to return. The we allocate the memory and finally fill it in.
+ * Because we cannot lock while calling malloc, the number of active
+ * vccs may change while we're in malloc. So we allocate a couple of
+ * vccs more and if space anyway is not enough re-iterate.
+ *
+ * We could use an sx lock for the vcc tables.
+ */
+struct atmio_vcctable *
+atm_getvccs(struct atmio_vcc **table, u_int size, u_int start,
+ struct mtx *lock, int waitok)
+{
+ u_int cid, alloc;
+ size_t len;
+ struct atmio_vcctable *vccs;
+ struct atmio_vcc *v;
+
+ alloc = start + 10;
+ vccs = NULL;
+
+ for (;;) {
+ len = sizeof(*vccs) + alloc * sizeof(vccs->vccs[0]);
+ vccs = reallocf(vccs, len, M_TEMP,
+ waitok ? M_WAITOK : M_NOWAIT);
+ if (vccs == NULL)
+ return (NULL);
+ bzero(vccs, len);
+
+ vccs->count = 0;
+ v = vccs->vccs;
+
+ mtx_lock(lock);
+ for (cid = 0; cid < size; cid++)
+ if (table[cid] != NULL) {
+ if (++vccs->count == alloc)
+ /* too many - try again */
+ break;
+ *v++ = *table[cid];
+ }
+ mtx_unlock(lock);
+
+ if (cid == size)
+ break;
+
+ alloc *= 2;
+ }
+ return (vccs);
+}
+
static moduledata_t atm_mod = {
"atm",
NULL,
OpenPOWER on IntegriCloud