123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813 |
- /*
- * Dynamic Span Interface for DAHDI (Multi-Span Ethernet Interface)
- *
- * Written by Joseph Benden <joe@thrallingpenguin.com>
- *
- * Copyright (C) 2007-2010, Thralling Penguin LLC.
- *
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
- #include <linux/kernel.h>
- #include <linux/errno.h>
- #include <linux/module.h>
- #include <linux/init.h>
- #include <linux/spinlock.h>
- #include <linux/slab.h>
- #include <linux/kmod.h>
- #include <linux/sched.h>
- #include <linux/interrupt.h>
- #include <linux/moduleparam.h>
- #include <linux/netdevice.h>
- #include <linux/notifier.h>
- #include <linux/crc32.h>
- #include <linux/seq_file.h>
- /**
- * Undefine USE_PROC_FS, if you do not want the /proc/dahdi/dynamic-ethmf
- * support. Undefining this would give a slight performance increase.
- */
- #define USE_PROC_FS
- #ifdef USE_PROC_FS
- # include <linux/proc_fs.h>
- # include <asm/atomic.h>
- #endif
- #ifdef CONFIG_DEVFS_FS
- # include <linux/devfs_fs_kernel.h>
- #endif
- #include <dahdi/kernel.h>
- #include <dahdi/user.h>
- #define ETH_P_ZTDETH 0xd00d
- #define ETHMF_MAX_PER_SPAN_GROUP 8
- #define ETHMF_MAX_GROUPS 16
- #define ETHMF_FLAG_IGNORE_CHAN0 (1 << 3)
- #define ETHMF_MAX_SPANS 4
- struct ztdeth_header {
- unsigned short subaddr;
- };
- /* Timer for enabling spans - used to combat a lock problem */
- static struct timer_list timer;
- /* Whether or not the timer has been deleted */
- static atomic_t timer_deleted = ATOMIC_INIT(0);
- /* Global error counter */
- static atomic_t errcount = ATOMIC_INIT(0);
- /* Whether or not we are in shutdown */
- static atomic_t shutdown = ATOMIC_INIT(0);
- static struct sk_buff_head skbs;
- #ifdef USE_PROC_FS
- struct ethmf_group {
- unsigned int hash_addr;
- atomic_t spans;
- atomic_t rxframecount;
- atomic_t txframecount;
- atomic_t rxbytecount;
- atomic_t txbytecount;
- atomic_t devupcount;
- atomic_t devdowncount;
- };
- static struct ethmf_group ethmf_groups[ETHMF_MAX_GROUPS];
- #endif
- struct ztdeth {
- /* Destination MAC address */
- unsigned char addr[ETH_ALEN];
- /* Destination MAC address hash value */
- unsigned int addr_hash;
- /* span sub-address, in network byte order */
- unsigned short subaddr;
- /* DAHDI span associated with this TDMoE-mf span */
- struct dahdi_span *span;
- /* Ethernet interface name */
- char ethdev[IFNAMSIZ];
- /* Ethernet device reference */
- struct net_device *dev;
- /* trx buffer */
- unsigned char *msgbuf;
- /* trx buffer length */
- int msgbuf_len;
- /* wether or not this frame is ready for trx */
- atomic_t ready;
- /* delay counter, to ensure all spans are added, prior to usage */
- atomic_t delay;
- /* rvc buffer */
- unsigned char *rcvbuf;
- /* the number of channels in this span */
- int real_channels;
- /* use padding if 1, else no padding */
- atomic_t no_front_padding;
- /* counter to pseudo lock the rcvbuf */
- atomic_t refcnt;
- struct list_head list;
- };
- /**
- * Lock for adding and removing items in ethmf_list
- */
- static DEFINE_SPINLOCK(ethmf_lock);
- /**
- * The active list of all running spans
- */
- static LIST_HEAD(ethmf_list);
- static inline void ethmf_errors_inc(void)
- {
- #ifdef USE_PROC_FS
- atomic_inc(&errcount);
- #endif
- }
- #ifdef USE_PROC_FS
- static inline int hashaddr_to_index(unsigned int hash_addr)
- {
- int i, z = -1;
- for (i = 0; i < ETHMF_MAX_GROUPS; ++i) {
- if (z == -1 && ethmf_groups[i].hash_addr == 0)
- z = i;
- if (ethmf_groups[i].hash_addr == hash_addr)
- return i;
- }
- if (z != -1) {
- ethmf_groups[z].hash_addr = hash_addr;
- }
- return z;
- }
- #endif
- /**
- * Find the Ztdeth Struct and DAHDI span for a given MAC address and subaddr.
- *
- * NOTE: RCU read lock must already be held.
- */
- static inline void find_ethmf(const unsigned char *addr,
- const unsigned short subaddr, struct ztdeth **ze,
- struct dahdi_span **span)
- {
- struct ztdeth *z;
- list_for_each_entry_rcu(z, ðmf_list, list) {
- if (!atomic_read(&z->delay)) {
- if (!memcmp(addr, z->addr, ETH_ALEN)
- && z->subaddr == subaddr) {
- *ze = z;
- *span = z->span;
- return;
- }
- }
- }
- /* no results */
- *ze = NULL;
- *span = NULL;
- }
- /**
- * Determines if all spans are ready for transmit. If all spans are ready,
- * we return the number of spans which indeed are ready and populate the
- * array of pointers to those spans..
- *
- * NOTE: RCU read lock must already be held.
- */
- static inline int ethmf_trx_spans_ready(unsigned int addr_hash, struct ztdeth *(*ready_spans)[ETHMF_MAX_PER_SPAN_GROUP])
- {
- struct ztdeth *t;
- int span_count = 0, spans_ready = 0;
- list_for_each_entry_rcu(t, ðmf_list, list) {
- if (!atomic_read(&t->delay) && t->addr_hash == addr_hash) {
- ++span_count;
- if (atomic_read(&t->ready)) {
- short subaddr = ntohs(t->subaddr);
- if (subaddr < ETHMF_MAX_PER_SPAN_GROUP) {
- (*ready_spans)[subaddr] = t;
- ++spans_ready;
- } else {
- printk(KERN_ERR "More than %d spans per multi-frame group are not currently supported.",
- ETHMF_MAX_PER_SPAN_GROUP);
- }
- }
- }
- }
- if (span_count && spans_ready && span_count == spans_ready) {
- return spans_ready;
- }
- return 0;
- }
- /**
- * Ethernet receiving side processing function.
- */
- static int ztdethmf_rcv(struct sk_buff *skb, struct net_device *dev,
- struct packet_type *pt, struct net_device *orig_dev)
- {
- int num_spans = 0, span_index = 0;
- unsigned char *data;
- struct dahdi_span *span;
- struct ztdeth *z = NULL;
- struct ztdeth_header *zh;
- unsigned int samples, channels, rbslen, flags;
- unsigned int skip = 0;
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
- zh = (struct ztdeth_header *) skb_network_header(skb);
- #else
- zh = (struct ztdeth_header *) skb->nh.raw;
- #endif
- if (ntohs(zh->subaddr) & 0x8000) {
- /* got a multi-span frame */
- num_spans = ntohs(zh->subaddr) & 0xFF;
- /* Currently max of 4 spans supported */
- if (unlikely(num_spans > ETHMF_MAX_SPANS)) {
- kfree_skb(skb);
- return 0;
- }
- skb_pull(skb, sizeof(struct ztdeth_header));
- #ifdef NEW_SKB_LINEARIZE
- if (skb_is_nonlinear(skb))
- skb_linearize(skb);
- #else
- if (skb_is_nonlinear(skb))
- skb_linearize(skb, GFP_KERNEL);
- #endif
- data = (unsigned char *) skb->data;
- rcu_read_lock();
- do {
- find_ethmf(eth_hdr(skb)->h_source,
- htons(span_index), &z, &span);
- if (unlikely(!z || !span)) {
- /* The recv'd span does not belong to us */
- /* ethmf_errors_inc(); */
- ++span_index;
- continue;
- }
- samples = data[(span_index * 6)] & 0xFF;
- flags = data[((span_index * 6) + 1)] & 0xFF;
- channels = data[((span_index * 6) + 5)] & 0xFF;
- /* Precomputed defaults for most typical values */
- if (channels == 24)
- rbslen = 12;
- else if (channels == 31)
- rbslen = 16;
- else
- rbslen = ((channels + 3) / 4) * 2;
- if (unlikely(samples != 8 || channels >= 32 || channels == 0)) {
- ethmf_errors_inc();
- ++span_index;
- continue;
- }
- if (atomic_dec_and_test(&z->refcnt) == 0) {
- memcpy(z->rcvbuf, data + 6*span_index, 6); /* TDM Header */
- /*
- * If we ignore channel zero we must skip the first eight bytes and
- * ensure that ztdynamic doesn't get confused by this new flag
- */
- if (flags & ETHMF_FLAG_IGNORE_CHAN0) {
- skip = 8;
- /* Remove this flag since ztdynamic may not understand it */
- z->rcvbuf[1] = flags & ~(ETHMF_FLAG_IGNORE_CHAN0);
- /* Additionally, now we will transmit with front padding */
- atomic_set(&z->no_front_padding, 0);
- } else {
- /* Disable front padding if we recv'd a packet without it */
- atomic_set(&z->no_front_padding, 1);
- }
- memcpy(z->rcvbuf + 6, data + 6*num_spans + 16
- *span_index, rbslen); /* RBS Header */
- /* 256 == 32*8; if padding lengths change, this must be modified */
- memcpy(z->rcvbuf + 6 + rbslen, data + 6*num_spans + 16
- *num_spans + (256)*span_index + skip, channels
- * 8); /* Payload */
- dahdi_dynamic_receive(span, z->rcvbuf, 6 + rbslen
- + channels*8);
- } else {
- ethmf_errors_inc();
- printk(KERN_INFO "TDMoE span overflow detected. Span %d was dropped.", span_index);
- }
- atomic_inc(&z->refcnt);
- #ifdef USE_PROC_FS
- if (span_index == 0) {
- atomic_inc(&(ethmf_groups[hashaddr_to_index(z->addr_hash)].rxframecount));
- atomic_add(skb->len + z->dev->hard_header_len +
- sizeof(struct ztdeth_header),
- &(ethmf_groups[hashaddr_to_index(z->addr_hash)].rxbytecount));
- }
- #endif
- ++span_index;
- } while (!atomic_read(&shutdown) && span_index < num_spans);
- rcu_read_unlock();
- }
- kfree_skb(skb);
- return 0;
- }
- static int ztdethmf_notifier(struct notifier_block *block, unsigned long event,
- void *ptr)
- {
- struct net_device *dev = ptr;
- struct ztdeth *z;
- switch (event) {
- case NETDEV_GOING_DOWN:
- case NETDEV_DOWN:
- rcu_read_lock();
- list_for_each_entry_rcu(z, ðmf_list, list) {
- /* Note that the device no longer exists */
- if (z->dev == dev) {
- z->dev = NULL;
- #ifdef USE_PROC_FS
- atomic_inc(&(ethmf_groups[hashaddr_to_index(z->addr_hash)].devdowncount));
- #endif
- }
- }
- rcu_read_unlock();
- break;
- case NETDEV_UP:
- rcu_read_lock();
- list_for_each_entry_rcu(z, ðmf_list, list) {
- /* Now that the device exists again, use it */
- if (!strcmp(z->ethdev, dev->name)) {
- z->dev = dev;
- #ifdef USE_PROC_FS
- atomic_inc(&(ethmf_groups[hashaddr_to_index(z->addr_hash)].devupcount));
- #endif
- }
- }
- rcu_read_unlock();
- break;
- }
- return 0;
- }
- static void ztdethmf_transmit(struct dahdi_dynamic *dyn, u8 *msg, size_t msglen)
- {
- struct ztdeth *z = dyn->pvt, *ready_spans[ETHMF_MAX_PER_SPAN_GROUP];
- struct sk_buff *skb;
- struct ztdeth_header *zh;
- struct net_device *dev;
- unsigned char addr[ETH_ALEN];
- int spans_ready = 0, index = 0;
- if (atomic_read(&shutdown))
- return;
- rcu_read_lock();
- if (unlikely(!z || !z->dev)) {
- rcu_read_unlock();
- return;
- }
- if (!atomic_read(&z->ready)) {
- if (atomic_inc_return(&z->ready) == 1) {
- memcpy(z->msgbuf, msg, msglen);
- z->msgbuf_len = msglen;
- }
- }
- spans_ready = ethmf_trx_spans_ready(z->addr_hash, &ready_spans);
- if (spans_ready) {
- int pad[ETHMF_MAX_SPANS], rbs[ETHMF_MAX_SPANS];
- dev = z->dev;
- memcpy(addr, z->addr, sizeof(z->addr));
- for (index = 0; index < spans_ready; index++) {
- int chan = ready_spans[index]->real_channels;
- /* By default we pad to 32 channels, but if
- * no_front_padding is false then we have a pad
- * in the front of 8 bytes, so this implies one
- * less channel
- */
- if (atomic_read(&(ready_spans[index]->no_front_padding)))
- pad[index] = (32 - chan)*8;
- else
- pad[index] = (31 - chan)*8;
- if (chan == 24)
- rbs[index] = 12;
- else if (chan == 31)
- rbs[index] = 16;
- else
- /* Shouldn't this be index, not spans_ready? */
- rbs[spans_ready] = ((chan + 3) / 4) * 2;
- }
- /* Allocate the standard size for a 32-chan frame */
- skb = dev_alloc_skb(1112 + dev->hard_header_len
- + sizeof(struct ztdeth_header) + 32);
- if (unlikely(!skb)) {
- rcu_read_unlock();
- ethmf_errors_inc();
- return;
- }
- /* Reserve header space */
- skb_reserve(skb, dev->hard_header_len
- + sizeof(struct ztdeth_header));
- /* copy each spans header */
- for (index = 0; index < spans_ready; index++) {
- if (!atomic_read(&(ready_spans[index]->no_front_padding)))
- ready_spans[index]->msgbuf[1]
- |= ETHMF_FLAG_IGNORE_CHAN0;
- memcpy(skb_put(skb, 6), ready_spans[index]->msgbuf, 6);
- }
- /* copy each spans RBS payload */
- for (index = 0; index < spans_ready; index++) {
- memcpy(skb_put(skb, 16), ready_spans[index]->msgbuf + 6,
- rbs[index]);
- }
- /* copy each spans data/voice payload */
- for (index = 0; index < spans_ready; index++) {
- int chan = ready_spans[index]->real_channels;
- if (!atomic_read(&(ready_spans[index]->no_front_padding))) {
- /* This adds an additional (padded) channel to our total */
- memset(skb_put(skb, 8), 0xA5, 8); /* ETHMF_IGNORE_CHAN0 */
- }
- memcpy(skb_put(skb, chan*8), ready_spans[index]->msgbuf
- + (6 + rbs[index]), chan*8);
- if (pad[index] > 0) {
- memset(skb_put(skb, pad[index]), 0xDD, pad[index]);
- }
- /* mark span as ready for new data/voice */
- atomic_set(&(ready_spans[index]->ready), 0);
- }
- /* Throw on header */
- zh = (struct ztdeth_header *)skb_push(skb,
- sizeof(struct ztdeth_header));
- zh->subaddr = htons((unsigned short)(0x8000 | (unsigned char)(spans_ready & 0xFF)));
- /* Setup protocol type */
- skb->protocol = __constant_htons(ETH_P_ZTDETH);
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
- skb_set_network_header(skb, 0);
- #else
- skb->nh.raw = skb->data;
- #endif
- skb->dev = dev;
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
- dev_hard_header(skb, dev, ETH_P_ZTDETH, addr, dev->dev_addr, skb->len);
- #else
- if (dev->hard_header)
- dev->hard_header(skb, dev, ETH_P_ZTDETH, addr,
- dev->dev_addr, skb->len);
- #endif
- /* queue frame for delivery */
- if (dev) {
- skb_queue_tail(&skbs, skb);
- }
- #ifdef USE_PROC_FS
- atomic_inc(&(ethmf_groups[hashaddr_to_index(z->addr_hash)].txframecount));
- atomic_add(skb->len, &(ethmf_groups[hashaddr_to_index(z->addr_hash)].txbytecount));
- #endif
- }
- rcu_read_unlock();
- return;
- }
- static int ztdethmf_flush(void)
- {
- struct sk_buff *skb;
- /* Handle all transmissions now */
- while ((skb = skb_dequeue(&skbs))) {
- dev_queue_xmit(skb);
- }
- return 0;
- }
- static struct packet_type ztdethmf_ptype = {
- .type = __constant_htons(ETH_P_ZTDETH), /* Protocol */
- .dev = NULL, /* Device (NULL = wildcard) */
- .func = ztdethmf_rcv, /* Receiver */
- };
- static void ztdethmf_destroy(struct dahdi_dynamic *dyn)
- {
- struct ztdeth *z = dyn->pvt;
- unsigned long flags;
- atomic_set(&shutdown, 1);
- synchronize_rcu();
- spin_lock_irqsave(ðmf_lock, flags);
- list_del_rcu(&z->list);
- spin_unlock_irqrestore(ðmf_lock, flags);
- synchronize_rcu();
- atomic_dec(&(ethmf_groups[hashaddr_to_index(z->addr_hash)].spans));
- if (z) { /* Successfully removed */
- printk(KERN_INFO "Removed interface for %s\n",
- z->span->name);
- kfree(z->msgbuf);
- kfree(z);
- } else {
- if (z && z->span && z->span->name) {
- printk(KERN_ERR "Cannot find interface for %s\n",
- z->span->name);
- }
- }
- }
- static int ztdethmf_create(struct dahdi_dynamic *dyn, const char *addr)
- {
- struct ztdeth *z;
- char src[256];
- char *src_ptr;
- int x, bufsize, num_matched;
- unsigned long flags;
- struct dahdi_span *const span = &dyn->span;
- BUG_ON(!span);
- BUG_ON(!addr);
- z = kmalloc(sizeof(struct ztdeth), GFP_KERNEL);
- if (!z)
- return -ENOMEM;
- /* Zero it out */
- memset(z, 0, sizeof(struct ztdeth));
- /* set a delay for xmit/recv to workaround Zaptel problems */
- atomic_set(&z->delay, 4);
- /* create a msg buffer. MAX OF 31 CHANNELS!!!! */
- bufsize = 31 * DAHDI_CHUNKSIZE + 31 / 4 + 48;
- z->msgbuf = kmalloc(bufsize, GFP_KERNEL);
- z->rcvbuf = kmalloc(bufsize, GFP_KERNEL);
- /* Address should be <dev>/<macaddr>/subaddr */
- strlcpy(src, addr, sizeof(src));
- /* replace all / with space; otherwise kernel sscanf does not work */
- src_ptr = src;
- while (*src_ptr) {
- if (*src_ptr == '/')
- *src_ptr = ' ';
- ++src_ptr;
- }
- num_matched = sscanf(src,
- "%16s %hhx:%hhx:%hhx:%hhx:%hhx:%hhx %hu",
- z->ethdev, &z->addr[0], &z->addr[1],
- &z->addr[2], &z->addr[3], &z->addr[4],
- &z->addr[5], &z->subaddr);
- if (8 != num_matched) {
- printk(KERN_ERR "Only matched %d entries in '%s'\n", num_matched, src);
- printk(KERN_ERR "Invalid TDMoE Multiframe address: %s\n", addr);
- kfree(z);
- return -EINVAL;
- }
- z->dev = dev_get_by_name(
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
- &init_net,
- #endif
- z->ethdev);
- if (!z->dev) {
- printk(KERN_ERR "TDMoE Multiframe: Invalid device '%s'\n", z->ethdev);
- kfree(z);
- return -EINVAL;
- }
- z->span = span;
- z->subaddr = htons(z->subaddr);
- z->addr_hash = crc32_le(0, z->addr, ETH_ALEN);
- z->real_channels = span->channels;
- src[0] = '\0';
- for (x = 0; x < 5; x++)
- sprintf(src + strlen(src), "%02x:", z->dev->dev_addr[x]);
- sprintf(src + strlen(src), "%02x", z->dev->dev_addr[5]);
- printk(KERN_INFO "TDMoEmf: Added new interface for %s at %s "
- "(addr=%s, src=%s, subaddr=%d)\n", span->name, z->dev->name,
- addr, src, ntohs(z->subaddr));
- atomic_set(&z->ready, 0);
- atomic_set(&z->refcnt, 0);
- spin_lock_irqsave(ðmf_lock, flags);
- list_add_rcu(&z->list, ðmf_list);
- spin_unlock_irqrestore(ðmf_lock, flags);
- atomic_inc(&(ethmf_groups[hashaddr_to_index(z->addr_hash)].spans));
- /* enable the timer for enabling the spans */
- mod_timer(&timer, jiffies + HZ);
- atomic_set(&shutdown, 0);
- dyn->pvt = z;
- return 0;
- }
- static struct dahdi_dynamic_driver ztd_ethmf = {
- .owner = THIS_MODULE,
- .name = "ethmf",
- .desc = "Ethernet",
- .create = ztdethmf_create,
- .destroy = ztdethmf_destroy,
- .transmit = ztdethmf_transmit,
- .flush = ztdethmf_flush,
- };
- static struct notifier_block ztdethmf_nblock = {
- .notifier_call = ztdethmf_notifier,
- };
- /**
- * Decrements each delay counter in the ethmf_list and returns the number of
- * delay counters that are not equal to zero.
- */
- static int ethmf_delay_dec(void)
- {
- struct ztdeth *z;
- int count_nonzero = 0;
- rcu_read_lock();
- list_for_each_entry_rcu(z, ðmf_list, list) {
- if (atomic_read(&z->delay)) {
- atomic_dec(&z->delay);
- ++count_nonzero;
- } else
- atomic_set(&z->delay, 0);
- }
- rcu_read_unlock();
- return count_nonzero;
- }
- /**
- * Timer callback function to allow all spans to be added, prior to any of
- * them being used.
- */
- static void timer_callback(unsigned long param)
- {
- if (ethmf_delay_dec()) {
- if (!atomic_read(&timer_deleted)) {
- timer.expires = jiffies + HZ;
- add_timer(&timer);
- }
- } else {
- printk(KERN_INFO "All TDMoE multiframe span groups are active.\n");
- del_timer(&timer);
- }
- }
- #ifdef USE_PROC_FS
- static struct proc_dir_entry *proc_entry;
- static const char *ztdethmf_procname = "dahdi/dynamic-ethmf";
- static int ztdethmf_proc_show(struct seq_file *sfile, void *not_used)
- {
- struct ztdeth *z = NULL;
- int i = 0;
- unsigned int group = 0, c = 0;
- rcu_read_lock();
- seq_printf(sfile, "Errors: %d\n\n", atomic_read(&errcount));
- for (group = 0; group < ETHMF_MAX_GROUPS; ++group) {
- if (atomic_read(&(ethmf_groups[group].spans))) {
- seq_printf(sfile, "Group #%d (0x%x)\n", i++,
- ethmf_groups[group].hash_addr);
- seq_printf(sfile, "Spans: %d\n",
- atomic_read(&(ethmf_groups[group].spans)));
- c = 1;
- list_for_each_entry_rcu(z, ðmf_list, list) {
- if (z->addr_hash == ethmf_groups[group].hash_addr) {
- if (c == 1) {
- seq_printf(sfile,
- " Device: %s (MAC: %02x:%02x:%02x:%02x:%02x:%02x)\n",
- z->ethdev,
- z->addr[0], z->addr[1], z->addr[2],
- z->addr[3], z->addr[4], z->addr[5]);
- }
- seq_printf(sfile, " Span %d: subaddr=%u ready=%d delay=%d real_channels=%d no_front_padding=%d\n",
- c++, ntohs(z->subaddr),
- atomic_read(&z->ready), atomic_read(&z->delay),
- z->real_channels, atomic_read(&z->no_front_padding));
- }
- }
- seq_printf(sfile, " Device UPs: %u\n",
- atomic_read(&(ethmf_groups[group].devupcount)));
- seq_printf(sfile, " Device DOWNs: %u\n",
- atomic_read(&(ethmf_groups[group].devdowncount)));
- seq_printf(sfile, " Rx Frames: %u\n",
- atomic_read(&(ethmf_groups[group].rxframecount)));
- seq_printf(sfile, " Tx Frames: %u\n",
- atomic_read(&(ethmf_groups[group].txframecount)));
- seq_printf(sfile, " Rx Bytes: %u\n",
- atomic_read(&(ethmf_groups[group].rxbytecount)));
- seq_printf(sfile, " Tx Bytes: %u\n",
- atomic_read(&(ethmf_groups[group].txbytecount)));
- }
- }
- rcu_read_unlock();
- return 0;
- }
- static int ztdethmf_proc_open(struct inode *inode, struct file *file)
- {
- return single_open(file, ztdethmf_proc_show, NULL);
- }
- static const struct file_operations ztdethmf_proc_fops = {
- .open = ztdethmf_proc_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release,
- };
- #endif
- static int __init ztdethmf_init(void)
- {
- init_timer(&timer);
- timer.expires = jiffies + HZ;
- timer.function = &timer_callback;
- if (!timer_pending(&timer))
- add_timer(&timer);
- dev_add_pack(&ztdethmf_ptype);
- register_netdevice_notifier(&ztdethmf_nblock);
- dahdi_dynamic_register_driver(&ztd_ethmf);
- skb_queue_head_init(&skbs);
- #ifdef USE_PROC_FS
- proc_entry = proc_create_data(ztdethmf_procname, 0444, NULL,
- &ztdethmf_proc_fops, NULL);
- if (!proc_entry) {
- printk(KERN_ALERT "create_proc_read_entry failed.\n");
- }
- #endif
- return 0;
- }
- static void __exit ztdethmf_exit(void)
- {
- atomic_set(&timer_deleted, 1);
- del_timer_sync(&timer);
- dev_remove_pack(&ztdethmf_ptype);
- unregister_netdevice_notifier(&ztdethmf_nblock);
- dahdi_dynamic_unregister_driver(&ztd_ethmf);
- #ifdef USE_PROC_FS
- if (proc_entry)
- remove_proc_entry(ztdethmf_procname, NULL);
- #endif
- }
- MODULE_DESCRIPTION("DAHDI Dynamic TDMoEmf Support");
- MODULE_AUTHOR("Joseph Benden <joe@thrallingpenguin.com>");
- #ifdef MODULE_LICENSE
- MODULE_LICENSE("GPL");
- #endif
- module_init(ztdethmf_init);
- module_exit(ztdethmf_exit);
|