~ubuntu-branches/ubuntu/quantal/zaptel/quantal

« back to all changes in this revision

Viewing changes to ztd-eth.c

  • Committer: Bazaar Package Importer
  • Author(s): Tzafrir Cohen
  • Date: 2008-08-28 22:58:23 UTC
  • mfrom: (11.1.11 intrepid)
  • Revision ID: james.westby@ubuntu.com-20080828225823-r8bdunirm8hmc76m
Tags: 1:1.4.11~dfsg-2
* Patch xpp_fxs_power: Fixed an issue with hook detection of the Astribank
  FXS module.
* Don't fail init.d script if fxotune fails. This may happen if running it
  when Asterisk is already running.
* Bump standards version to 3.8.0.0 .
* Ignore false lintian warning ("m-a a-i" has "a a").
* Patch xpp_fxo_cid_always: do always pass PCM if that's what the user
  asked.
* Patch vzaphfc_proc_root_dir: fix vzaphfc on 2.6.26.
* Patch wcte12xp_flags: Proper time for irq save flags.
* Patch headers_2627: Fix location of semaphore.h for 2.6.27 .
* Patch xpp_fxs_dtmf_leak: Don't play DTMFs to the wrong channel.
* Patch wctdm_fix_alarm: Fix sending channel alarms.
* Patch device_class_2626: Fix building 2.6.26 (Closes: #493397).
* Using dh_lintian for lintian overrides, hence requiring debhelper 6.0.7.
* Lintian: we know we have direct changes. Too bad we're half-upstream :-(
* Fix doc-base section names. 

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Dynamic Span Interface for Zaptel (Ethernet Interface)
3
 
 *
4
 
 * Written by Mark Spencer <markster@linux-support.net>
5
 
 *
6
 
 * Copyright (C) 2001, Linux Support Services, Inc.
7
 
 *
8
 
 * All rights reserved.
9
 
 *
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.
14
 
 * 
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.
19
 
 * 
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. 
23
 
 *
24
 
 */
25
 
 
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>
35
 
 
36
 
#ifdef CONFIG_DEVFS_FS
37
 
#include <linux/devfs_fs_kernel.h>
38
 
#endif
39
 
#ifdef STANDALONE_ZAPATA
40
 
#include "zaptel.h"
41
 
#else
42
 
#include <linux/zaptel.h>
43
 
#endif
44
 
 
45
 
#define ETH_P_ZTDETH    0xd00d
46
 
 
47
 
struct ztdeth_header {
48
 
        unsigned short subaddr;
49
 
};
50
 
 
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);
55
 
#else
56
 
static spinlock_t zlock = SPIN_LOCK_UNLOCKED;
57
 
#endif
58
 
 
59
 
static struct ztdeth {
60
 
        unsigned char addr[ETH_ALEN];
61
 
        unsigned short subaddr; /* Network byte order */
62
 
        struct zt_span *span;
63
 
        char ethdev[IFNAMSIZ];
64
 
        struct net_device *dev;
65
 
        struct ztdeth *next;
66
 
} *zdevs = NULL;
67
 
 
68
 
struct zt_span *ztdeth_getspan(unsigned char *addr, unsigned short subaddr)
69
 
{
70
 
        unsigned long flags;
71
 
        struct ztdeth *z;
72
 
        struct zt_span *span = NULL;
73
 
        spin_lock_irqsave(&zlock, flags);
74
 
        z = zdevs;
75
 
        while(z) {
76
 
                if (!memcmp(addr, z->addr, ETH_ALEN) &&
77
 
                        z->subaddr == subaddr)
78
 
                        break;
79
 
                z = z->next;
80
 
        }
81
 
        if (z)
82
 
                span = z->span;
83
 
        spin_unlock_irqrestore(&zlock, flags);
84
 
        return span;
85
 
}
86
 
 
87
 
static int ztdeth_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
88
 
{
89
 
        struct zt_span *span;
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);
94
 
#else
95
 
        span = ztdeth_getspan(skb->mac.ethernet->h_source, zh->subaddr);
96
 
#endif  
97
 
        if (span) {
98
 
                skb_pull(skb, sizeof(struct ztdeth_header));
99
 
                zt_dynamic_receive(span, (unsigned char *)skb->data, skb->len);
100
 
        }
101
 
        kfree_skb(skb);
102
 
        return 0;
103
 
}
104
 
 
105
 
static int ztdeth_notifier(struct notifier_block *block, unsigned long event, void *ptr)
106
 
{
107
 
        struct net_device *dev = ptr;
108
 
        struct ztdeth *z;
109
 
        unsigned long flags;
110
 
        switch(event) {
111
 
        case NETDEV_GOING_DOWN:
112
 
        case NETDEV_DOWN:
113
 
                spin_lock_irqsave(&zlock, flags);
114
 
                z = zdevs;
115
 
                while(z) {
116
 
                        /* Note that the device no longer exists */
117
 
                        if (z->dev == dev)
118
 
                                z->dev = NULL;
119
 
                        z = z->next;
120
 
                }
121
 
                spin_unlock_irqrestore(&zlock, flags);
122
 
                break;
123
 
        case NETDEV_UP:
124
 
                spin_lock_irqsave(&zlock, flags);
125
 
                z = zdevs;
126
 
                while(z) {
127
 
                        /* Now that the device exists again, use it */
128
 
                        if (!strcmp(z->ethdev, dev->name))
129
 
                                z->dev = dev;
130
 
                        z = z->next;
131
 
                }
132
 
                spin_unlock_irqrestore(&zlock, flags);
133
 
                break;
134
 
        }
135
 
        return 0;
136
 
}
137
 
 
138
 
static int ztdeth_transmit(void *pvt, unsigned char *msg, int msglen)
139
 
{
140
 
        struct ztdeth *z;
141
 
        struct sk_buff *skb;
142
 
        struct ztdeth_header *zh;
143
 
        unsigned long flags;
144
 
        struct net_device *dev;
145
 
        unsigned char addr[ETH_ALEN];
146
 
        unsigned short subaddr; /* Network byte order */
147
 
 
148
 
        spin_lock_irqsave(&zlock, flags);
149
 
        z = pvt;
150
 
        if (z->dev) {
151
 
                /* Copy fields to local variables to remove spinlock ASAP */
152
 
                dev = z->dev;
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);
157
 
                if (skb) {
158
 
                        /* Reserve header space */
159
 
                        skb_reserve(skb, dev->hard_header_len + sizeof(struct ztdeth_header));
160
 
 
161
 
                        /* Copy message body */
162
 
                        memcpy(skb_put(skb, msglen), msg, msglen);
163
 
 
164
 
                        /* Throw on header */
165
 
                        zh = (struct ztdeth_header *)skb_push(skb, sizeof(struct ztdeth_header));
166
 
                        zh->subaddr = subaddr;
167
 
 
168
 
                        /* Setup protocol and such */
169
 
                        skb->protocol = __constant_htons(ETH_P_ZTDETH);
170
 
                        skb->nh.raw = skb->data;
171
 
                        skb->dev = dev;
172
 
                        if (dev->hard_header)
173
 
                                dev->hard_header(skb, dev, ETH_P_ZTDETH, addr, dev->dev_addr, skb->len);
174
 
                        dev_queue_xmit(skb);
175
 
                }
176
 
        }
177
 
        else
178
 
                spin_unlock_irqrestore(&zlock, flags);
179
 
        return 0;
180
 
}
181
 
 
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 */
186
 
};
187
 
 
188
 
static int digit2int(char d)
189
 
{
190
 
        switch(d) {
191
 
        case 'F':
192
 
        case 'E':
193
 
        case 'D':
194
 
        case 'C':
195
 
        case 'B':
196
 
        case 'A':
197
 
                return d - 'A' + 10;
198
 
        case 'f':
199
 
        case 'e':
200
 
        case 'd':
201
 
        case 'c':
202
 
        case 'b':
203
 
        case 'a':
204
 
                return d - 'a' + 10;
205
 
        case '9':
206
 
        case '8':
207
 
        case '7':
208
 
        case '6':
209
 
        case '5':
210
 
        case '4':
211
 
        case '3':
212
 
        case '2':
213
 
        case '1':
214
 
        case '0':
215
 
                return d - '0';
216
 
        }
217
 
        return -1;
218
 
}
219
 
 
220
 
static int hex2int(char *s)
221
 
{
222
 
        int res;
223
 
        int tmp;
224
 
        /* Gotta be at least one digit */
225
 
        if (strlen(s) < 1)
226
 
                return -1;
227
 
        /* Can't be more than two */
228
 
        if (strlen(s) > 2)
229
 
                return -1;
230
 
        /* Grab the first digit */
231
 
        res = digit2int(s[0]);
232
 
        if (res < 0)
233
 
                return -1;
234
 
        tmp = res;
235
 
        /* Grab the next */
236
 
        if (strlen(s) > 1) {
237
 
                res = digit2int(s[1]);
238
 
                if (res < 0)
239
 
                        return -1;
240
 
                tmp = tmp * 16 + res;
241
 
        }
242
 
        return tmp;
243
 
}
244
 
 
245
 
static void ztdeth_destroy(void *pvt)
246
 
{
247
 
        struct ztdeth *z = pvt;
248
 
        unsigned long flags;
249
 
        struct ztdeth *prev=NULL, *cur;
250
 
        spin_lock_irqsave(&zlock, flags);
251
 
        cur = zdevs;
252
 
        while(cur) {
253
 
                if (cur == z) {
254
 
                        if (prev)
255
 
                                prev->next = cur->next;
256
 
                        else
257
 
                                zdevs = cur->next;
258
 
                        break;
259
 
                }
260
 
                prev = cur;
261
 
                cur = cur->next;
262
 
        }
263
 
        spin_unlock_irqrestore(&zlock, flags);
264
 
        if (cur == z) { /* Successfully removed */
265
 
                printk("TDMoE: Removed interface for %s\n", z->span->name);
266
 
                kfree(z);
267
 
#ifndef LINUX26
268
 
                MOD_DEC_USE_COUNT;
269
 
#endif
270
 
        }
271
 
}
272
 
 
273
 
static void *ztdeth_create(struct zt_span *span, char *addr)
274
 
{
275
 
        struct ztdeth *z;
276
 
        char src[256];
277
 
        char tmp[256], *tmp2, *tmp3, *tmp4 = NULL;
278
 
        int res,x;
279
 
        unsigned long flags;
280
 
 
281
 
        z = kmalloc(sizeof(struct ztdeth), GFP_KERNEL);
282
 
        if (z) {
283
 
                /* Zero it out */
284
 
                memset(z, 0, sizeof(struct ztdeth));
285
 
 
286
 
                /* Address should be <dev>/<macaddr>[/subaddr] */
287
 
                strncpy(tmp, addr, sizeof(tmp) - 1);
288
 
                tmp2 = strchr(tmp, '/');
289
 
                if (tmp2) {
290
 
                        *tmp2 = '\0';
291
 
                        tmp2++;
292
 
                        strncpy(z->ethdev, tmp, sizeof(z->ethdev) - 1);
293
 
                } else {
294
 
                        printk("Invalid TDMoE address (no device) '%s'\n", addr);
295
 
                        kfree(z);
296
 
                        return NULL;
297
 
                }
298
 
                if (tmp2) {
299
 
                        tmp4 = strchr(tmp2+1, '/');
300
 
                        if (tmp4) {
301
 
                                *tmp4 = '\0';
302
 
                                tmp4++;
303
 
                        }
304
 
                        /* We don't have SSCANF :(  Gotta do this the hard way */
305
 
                        tmp3 = strchr(tmp2, ':');
306
 
                        for (x=0;x<6;x++) {
307
 
                                if (tmp2) {
308
 
                                        if (tmp3) {
309
 
                                                *tmp3 = '\0';
310
 
                                                tmp3++;
311
 
                                        }
312
 
                                        res = hex2int(tmp2);
313
 
                                        if (res < 0)
314
 
                                                break;
315
 
                                        z->addr[x] = res & 0xff;
316
 
                                } else
317
 
                                        break;
318
 
                                if ((tmp2 = tmp3))
319
 
                                        tmp3 = strchr(tmp2, ':');
320
 
                        }
321
 
                        if (x != 6) {
322
 
                                printk("TDMoE: Invalid MAC address in: %s\n", addr);
323
 
                                kfree(z);
324
 
                                return NULL;
325
 
                        }
326
 
                } else {
327
 
                        printk("TDMoE: Missing MAC address\n");
328
 
                        kfree(z);
329
 
                        return NULL;
330
 
                }
331
 
                if (tmp4) {
332
 
                        int sub = 0;
333
 
                        int mul = 1;
334
 
 
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;
340
 
                                } else {
341
 
                                        printk("TDMoE: Invalid subaddress\n");
342
 
                                        kfree(z);
343
 
                                        return NULL;
344
 
                                }
345
 
                                mul *= 10;
346
 
                                tmp3--;
347
 
                        }
348
 
                        z->subaddr = htons(sub);
349
 
                }
350
 
                z->dev = dev_get_by_name(z->ethdev);
351
 
                if (!z->dev) {
352
 
                        printk("TDMoE: Invalid device '%s'\n", z->ethdev);
353
 
                        kfree(z);
354
 
                        return NULL;
355
 
                }
356
 
                z->span = span;
357
 
                src[0] ='\0';
358
 
                for (x=0;x<5;x++)
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));
362
 
                        
363
 
                spin_lock_irqsave(&zlock, flags);
364
 
                z->next = zdevs;
365
 
                zdevs = z;
366
 
                spin_unlock_irqrestore(&zlock, flags);
367
 
#ifndef LINUX26
368
 
                MOD_INC_USE_COUNT;
369
 
#endif
370
 
        }
371
 
        return z;
372
 
}
373
 
 
374
 
static struct zt_dynamic_driver ztd_eth = {
375
 
        "eth",
376
 
        "Ethernet",
377
 
        ztdeth_create,
378
 
        ztdeth_destroy,
379
 
        ztdeth_transmit
380
 
};
381
 
 
382
 
static struct notifier_block ztdeth_nblock = {
383
 
        notifier_call: ztdeth_notifier,
384
 
};
385
 
 
386
 
static int __init ztdeth_init(void)
387
 
{
388
 
        dev_add_pack(&ztdeth_ptype);
389
 
        register_netdevice_notifier(&ztdeth_nblock);
390
 
        zt_dynamic_register(&ztd_eth);
391
 
        return 0;
392
 
}
393
 
 
394
 
static void __exit ztdeth_exit(void)
395
 
{
396
 
        dev_remove_pack(&ztdeth_ptype);
397
 
        unregister_netdevice_notifier(&ztdeth_nblock);
398
 
        zt_dynamic_unregister(&ztd_eth);
399
 
}
400
 
 
401
 
MODULE_DESCRIPTION("Zaptel Dynamic TDMoE Support");
402
 
MODULE_AUTHOR("Mark Spencer <markster@linux-support.net>");
403
 
#ifdef MODULE_LICENSE
404
 
MODULE_LICENSE("GPL");
405
 
#endif
406
 
 
407
 
module_init(ztdeth_init);
408
 
module_exit(ztdeth_exit);