summaryrefslogtreecommitdiffstats
path: root/sys/net/if_atmsubr.c
diff options
context:
space:
mode:
authorharti <harti@FreeBSD.org>2003-07-15 10:37:09 +0000
committerharti <harti@FreeBSD.org>2003-07-15 10:37:09 +0000
commit2a47fc8b0be63f17e8b84f15ef840181c2edd374 (patch)
tree9b66f55bc2a3c18effc3cfffee5f4ca6309768ca /sys/net/if_atmsubr.c
parentdadf9247dd385b9f1597c2b9a1838f1a53ed1400 (diff)
downloadFreeBSD-src-2a47fc8b0be63f17e8b84f15ef840181c2edd374.zip
FreeBSD-src-2a47fc8b0be63f17e8b84f15ef840181c2edd374.tar.gz
Implement an utility function that can be used by device drivers to
implement the ATMIOCGVCCS ioctls. This routine handles changing VCC tables (which can occure because we cannot hold the driver mutex while allocating memory) with a loop and a re-allocation, should the table not fit in the allocated memory.
Diffstat (limited to 'sys/net/if_atmsubr.c')
-rw-r--r--sys/net/if_atmsubr.c57
1 files changed, 57 insertions, 0 deletions
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