2
* Dynamic Span Interface for Zaptel (Ethernet Interface)
4
* Written by Mark Spencer <markster@linux-support.net>
6
* Copyright (C) 2001, Linux Support Services, Inc.
10
* This program is free software; you can redistribute it and/or modify
11
* it under the terms of the GNU General Public License as published by
12
* the Free Software Foundation; either version 2 of the License, or
13
* (at your option) any later version.
15
* This program is distributed in the hope that it will be useful,
16
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
* GNU General Public License for more details.
20
* You should have received a copy of the GNU General Public License
21
* along with this program; if not, write to the Free Software
22
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26
#include <linux/kernel.h>
27
#include <linux/errno.h>
28
#include <linux/module.h>
29
#include <linux/init.h>
30
#include <linux/spinlock.h>
31
#include <linux/slab.h>
32
#include <linux/kmod.h>
33
#include <linux/netdevice.h>
34
#include <linux/notifier.h>
36
#ifdef CONFIG_DEVFS_FS
37
#include <linux/devfs_fs_kernel.h>
39
#ifdef STANDALONE_ZAPATA
42
#include <linux/zaptel.h>
45
#define ETH_P_ZTDETH 0xd00d
47
struct ztdeth_header {
48
unsigned short subaddr;
51
/* We take the raw message, put it in an ethernet frame, and add a
52
two byte addressing header at the top for future use */
53
#ifdef DEFINE_SPINLOCK
54
static DEFINE_SPINLOCK(zlock);
56
static spinlock_t zlock = SPIN_LOCK_UNLOCKED;
59
static struct ztdeth {
60
unsigned char addr[ETH_ALEN];
61
unsigned short subaddr; /* Network byte order */
63
char ethdev[IFNAMSIZ];
64
struct net_device *dev;
68
struct zt_span *ztdeth_getspan(unsigned char *addr, unsigned short subaddr)
72
struct zt_span *span = NULL;
73
spin_lock_irqsave(&zlock, flags);
76
if (!memcmp(addr, z->addr, ETH_ALEN) &&
77
z->subaddr == subaddr)
83
spin_unlock_irqrestore(&zlock, flags);
87
static int ztdeth_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
90
struct ztdeth_header *zh;
91
zh = (struct ztdeth_header *)skb->nh.raw;
92
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,9)
93
span = ztdeth_getspan(eth_hdr(skb)->h_source, zh->subaddr);
95
span = ztdeth_getspan(skb->mac.ethernet->h_source, zh->subaddr);
98
skb_pull(skb, sizeof(struct ztdeth_header));
99
zt_dynamic_receive(span, (unsigned char *)skb->data, skb->len);
105
static int ztdeth_notifier(struct notifier_block *block, unsigned long event, void *ptr)
107
struct net_device *dev = ptr;
111
case NETDEV_GOING_DOWN:
113
spin_lock_irqsave(&zlock, flags);
116
/* Note that the device no longer exists */
121
spin_unlock_irqrestore(&zlock, flags);
124
spin_lock_irqsave(&zlock, flags);
127
/* Now that the device exists again, use it */
128
if (!strcmp(z->ethdev, dev->name))
132
spin_unlock_irqrestore(&zlock, flags);
138
static int ztdeth_transmit(void *pvt, unsigned char *msg, int msglen)
142
struct ztdeth_header *zh;
144
struct net_device *dev;
145
unsigned char addr[ETH_ALEN];
146
unsigned short subaddr; /* Network byte order */
148
spin_lock_irqsave(&zlock, flags);
151
/* Copy fields to local variables to remove spinlock ASAP */
153
memcpy(addr, z->addr, sizeof(z->addr));
154
subaddr = z->subaddr;
155
spin_unlock_irqrestore(&zlock, flags);
156
skb = dev_alloc_skb(msglen + dev->hard_header_len + sizeof(struct ztdeth_header) + 32);
158
/* Reserve header space */
159
skb_reserve(skb, dev->hard_header_len + sizeof(struct ztdeth_header));
161
/* Copy message body */
162
memcpy(skb_put(skb, msglen), msg, msglen);
164
/* Throw on header */
165
zh = (struct ztdeth_header *)skb_push(skb, sizeof(struct ztdeth_header));
166
zh->subaddr = subaddr;
168
/* Setup protocol and such */
169
skb->protocol = __constant_htons(ETH_P_ZTDETH);
170
skb->nh.raw = skb->data;
172
if (dev->hard_header)
173
dev->hard_header(skb, dev, ETH_P_ZTDETH, addr, dev->dev_addr, skb->len);
178
spin_unlock_irqrestore(&zlock, flags);
182
static struct packet_type ztdeth_ptype = {
183
type: __constant_htons(ETH_P_ZTDETH), /* Protocol */
184
dev: NULL, /* Device (NULL = wildcard) */
185
func: ztdeth_rcv, /* Receiver */
188
static int digit2int(char d)
220
static int hex2int(char *s)
224
/* Gotta be at least one digit */
227
/* Can't be more than two */
230
/* Grab the first digit */
231
res = digit2int(s[0]);
237
res = digit2int(s[1]);
240
tmp = tmp * 16 + res;
245
static void ztdeth_destroy(void *pvt)
247
struct ztdeth *z = pvt;
249
struct ztdeth *prev=NULL, *cur;
250
spin_lock_irqsave(&zlock, flags);
255
prev->next = cur->next;
263
spin_unlock_irqrestore(&zlock, flags);
264
if (cur == z) { /* Successfully removed */
265
printk("TDMoE: Removed interface for %s\n", z->span->name);
273
static void *ztdeth_create(struct zt_span *span, char *addr)
277
char tmp[256], *tmp2, *tmp3, *tmp4 = NULL;
281
z = kmalloc(sizeof(struct ztdeth), GFP_KERNEL);
284
memset(z, 0, sizeof(struct ztdeth));
286
/* Address should be <dev>/<macaddr>[/subaddr] */
287
strncpy(tmp, addr, sizeof(tmp) - 1);
288
tmp2 = strchr(tmp, '/');
292
strncpy(z->ethdev, tmp, sizeof(z->ethdev) - 1);
294
printk("Invalid TDMoE address (no device) '%s'\n", addr);
299
tmp4 = strchr(tmp2+1, '/');
304
/* We don't have SSCANF :( Gotta do this the hard way */
305
tmp3 = strchr(tmp2, ':');
315
z->addr[x] = res & 0xff;
319
tmp3 = strchr(tmp2, ':');
322
printk("TDMoE: Invalid MAC address in: %s\n", addr);
327
printk("TDMoE: Missing MAC address\n");
335
/* We have a subaddr */
336
tmp3 = tmp4 + strlen (tmp4) - 1;
337
while (tmp3 >= tmp4) {
338
if (*tmp3 >= '0' && *tmp3 <= '9') {
339
sub += (*tmp3 - '0') * mul;
341
printk("TDMoE: Invalid subaddress\n");
348
z->subaddr = htons(sub);
350
z->dev = dev_get_by_name(z->ethdev);
352
printk("TDMoE: Invalid device '%s'\n", z->ethdev);
359
sprintf(src + strlen(src), "%02x:", z->dev->dev_addr[x]);
360
sprintf(src + strlen(src), "%02x", z->dev->dev_addr[5]);
361
printk("TDMoE: Added new interface for %s at %s (addr=%s, src=%s, subaddr=%d)\n", span->name, z->dev->name, addr, src, ntohs(z->subaddr));
363
spin_lock_irqsave(&zlock, flags);
366
spin_unlock_irqrestore(&zlock, flags);
374
static struct zt_dynamic_driver ztd_eth = {
382
static struct notifier_block ztdeth_nblock = {
383
notifier_call: ztdeth_notifier,
386
static int __init ztdeth_init(void)
388
dev_add_pack(&ztdeth_ptype);
389
register_netdevice_notifier(&ztdeth_nblock);
390
zt_dynamic_register(&ztd_eth);
394
static void __exit ztdeth_exit(void)
396
dev_remove_pack(&ztdeth_ptype);
397
unregister_netdevice_notifier(&ztdeth_nblock);
398
zt_dynamic_unregister(&ztd_eth);
401
MODULE_DESCRIPTION("Zaptel Dynamic TDMoE Support");
402
MODULE_AUTHOR("Mark Spencer <markster@linux-support.net>");
403
#ifdef MODULE_LICENSE
404
MODULE_LICENSE("GPL");
407
module_init(ztdeth_init);
408
module_exit(ztdeth_exit);