diff options
author | harti <harti@FreeBSD.org> | 2003-07-15 10:37:09 +0000 |
---|---|---|
committer | harti <harti@FreeBSD.org> | 2003-07-15 10:37:09 +0000 |
commit | 2a47fc8b0be63f17e8b84f15ef840181c2edd374 (patch) | |
tree | 9b66f55bc2a3c18effc3cfffee5f4ca6309768ca /sys/net | |
parent | dadf9247dd385b9f1597c2b9a1838f1a53ed1400 (diff) | |
download | FreeBSD-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')
-rw-r--r-- | sys/net/if_atm.h | 2 | ||||
-rw-r--r-- | sys/net/if_atmsubr.c | 57 |
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, |