OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [net/] [wan/] [hdlc.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * Generic HDLC support routines for Linux
3
 *
4
 * Copyright (C) 1999 - 2006 Krzysztof Halasa <khc@pm.waw.pl>
5
 *
6
 * This program is free software; you can redistribute it and/or modify it
7
 * under the terms of version 2 of the GNU General Public License
8
 * as published by the Free Software Foundation.
9
 *
10
 * Currently supported:
11
 *      * raw IP-in-HDLC
12
 *      * Cisco HDLC
13
 *      * Frame Relay with ANSI or CCITT LMI (both user and network side)
14
 *      * PPP
15
 *      * X.25
16
 *
17
 * Use sethdlc utility to set line parameters, protocol and PVCs
18
 *
19
 * How does it work:
20
 * - proto->open(), close(), start(), stop() calls are serialized.
21
 *   The order is: open, [ start, stop ... ] close ...
22
 * - proto->start() and stop() are called with spin_lock_irq held.
23
 */
24
 
25
#include <linux/module.h>
26
#include <linux/kernel.h>
27
#include <linux/slab.h>
28
#include <linux/poll.h>
29
#include <linux/errno.h>
30
#include <linux/if_arp.h>
31
#include <linux/init.h>
32
#include <linux/skbuff.h>
33
#include <linux/pkt_sched.h>
34
#include <linux/inetdevice.h>
35
#include <linux/lapb.h>
36
#include <linux/rtnetlink.h>
37
#include <linux/notifier.h>
38
#include <linux/hdlc.h>
39
#include <net/net_namespace.h>
40
 
41
 
42
static const char* version = "HDLC support module revision 1.21";
43
 
44
#undef DEBUG_LINK
45
 
46
static struct hdlc_proto *first_proto = NULL;
47
 
48
 
49
static int hdlc_change_mtu(struct net_device *dev, int new_mtu)
50
{
51
        if ((new_mtu < 68) || (new_mtu > HDLC_MAX_MTU))
52
                return -EINVAL;
53
        dev->mtu = new_mtu;
54
        return 0;
55
}
56
 
57
 
58
 
59
static struct net_device_stats *hdlc_get_stats(struct net_device *dev)
60
{
61
        return hdlc_stats(dev);
62
}
63
 
64
 
65
 
66
static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev,
67
                    struct packet_type *p, struct net_device *orig_dev)
68
{
69
        struct hdlc_device_desc *desc = dev_to_desc(dev);
70
 
71
        if (dev->nd_net != &init_net) {
72
                kfree_skb(skb);
73
                return 0;
74
        }
75
 
76
        if (desc->netif_rx)
77
                return desc->netif_rx(skb);
78
 
79
        desc->stats.rx_dropped++; /* Shouldn't happen */
80
        dev_kfree_skb(skb);
81
        return NET_RX_DROP;
82
}
83
 
84
 
85
 
86
static inline void hdlc_proto_start(struct net_device *dev)
87
{
88
        hdlc_device *hdlc = dev_to_hdlc(dev);
89
        if (hdlc->proto->start)
90
                return hdlc->proto->start(dev);
91
}
92
 
93
 
94
 
95
static inline void hdlc_proto_stop(struct net_device *dev)
96
{
97
        hdlc_device *hdlc = dev_to_hdlc(dev);
98
        if (hdlc->proto->stop)
99
                return hdlc->proto->stop(dev);
100
}
101
 
102
 
103
 
104
static int hdlc_device_event(struct notifier_block *this, unsigned long event,
105
                             void *ptr)
106
{
107
        struct net_device *dev = ptr;
108
        hdlc_device *hdlc;
109
        unsigned long flags;
110
        int on;
111
 
112
        if (dev->nd_net != &init_net)
113
                return NOTIFY_DONE;
114
 
115
        if (dev->get_stats != hdlc_get_stats)
116
                return NOTIFY_DONE; /* not an HDLC device */
117
 
118
        if (event != NETDEV_CHANGE)
119
                return NOTIFY_DONE; /* Only interrested in carrier changes */
120
 
121
        on = netif_carrier_ok(dev);
122
 
123
#ifdef DEBUG_LINK
124
        printk(KERN_DEBUG "%s: hdlc_device_event NETDEV_CHANGE, carrier %i\n",
125
               dev->name, on);
126
#endif
127
 
128
        hdlc = dev_to_hdlc(dev);
129
        spin_lock_irqsave(&hdlc->state_lock, flags);
130
 
131
        if (hdlc->carrier == on)
132
                goto carrier_exit; /* no change in DCD line level */
133
 
134
        hdlc->carrier = on;
135
 
136
        if (!hdlc->open)
137
                goto carrier_exit;
138
 
139
        if (hdlc->carrier) {
140
                printk(KERN_INFO "%s: Carrier detected\n", dev->name);
141
                hdlc_proto_start(dev);
142
        } else {
143
                printk(KERN_INFO "%s: Carrier lost\n", dev->name);
144
                hdlc_proto_stop(dev);
145
        }
146
 
147
carrier_exit:
148
        spin_unlock_irqrestore(&hdlc->state_lock, flags);
149
        return NOTIFY_DONE;
150
}
151
 
152
 
153
 
154
/* Must be called by hardware driver when HDLC device is being opened */
155
int hdlc_open(struct net_device *dev)
156
{
157
        hdlc_device *hdlc = dev_to_hdlc(dev);
158
#ifdef DEBUG_LINK
159
        printk(KERN_DEBUG "%s: hdlc_open() carrier %i open %i\n", dev->name,
160
               hdlc->carrier, hdlc->open);
161
#endif
162
 
163
        if (hdlc->proto == NULL)
164
                return -ENOSYS; /* no protocol attached */
165
 
166
        if (hdlc->proto->open) {
167
                int result = hdlc->proto->open(dev);
168
                if (result)
169
                        return result;
170
        }
171
 
172
        spin_lock_irq(&hdlc->state_lock);
173
 
174
        if (hdlc->carrier) {
175
                printk(KERN_INFO "%s: Carrier detected\n", dev->name);
176
                hdlc_proto_start(dev);
177
        } else
178
                printk(KERN_INFO "%s: No carrier\n", dev->name);
179
 
180
        hdlc->open = 1;
181
 
182
        spin_unlock_irq(&hdlc->state_lock);
183
        return 0;
184
}
185
 
186
 
187
 
188
/* Must be called by hardware driver when HDLC device is being closed */
189
void hdlc_close(struct net_device *dev)
190
{
191
        hdlc_device *hdlc = dev_to_hdlc(dev);
192
#ifdef DEBUG_LINK
193
        printk(KERN_DEBUG "%s: hdlc_close() carrier %i open %i\n", dev->name,
194
               hdlc->carrier, hdlc->open);
195
#endif
196
 
197
        spin_lock_irq(&hdlc->state_lock);
198
 
199
        hdlc->open = 0;
200
        if (hdlc->carrier)
201
                hdlc_proto_stop(dev);
202
 
203
        spin_unlock_irq(&hdlc->state_lock);
204
 
205
        if (hdlc->proto->close)
206
                hdlc->proto->close(dev);
207
}
208
 
209
 
210
 
211
int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
212
{
213
        struct hdlc_proto *proto = first_proto;
214
        int result;
215
 
216
        if (cmd != SIOCWANDEV)
217
                return -EINVAL;
218
 
219
        if (dev_to_hdlc(dev)->proto) {
220
                result = dev_to_hdlc(dev)->proto->ioctl(dev, ifr);
221
                if (result != -EINVAL)
222
                        return result;
223
        }
224
 
225
        /* Not handled by currently attached protocol (if any) */
226
 
227
        while (proto) {
228
                if ((result = proto->ioctl(dev, ifr)) != -EINVAL)
229
                        return result;
230
                proto = proto->next;
231
        }
232
        return -EINVAL;
233
}
234
 
235
static const struct header_ops hdlc_null_ops;
236
 
237
static void hdlc_setup_dev(struct net_device *dev)
238
{
239
        /* Re-init all variables changed by HDLC protocol drivers,
240
         * including ether_setup() called from hdlc_raw_eth.c.
241
         */
242
        dev->get_stats           = hdlc_get_stats;
243
        dev->flags               = IFF_POINTOPOINT | IFF_NOARP;
244
        dev->mtu                 = HDLC_MAX_MTU;
245
        dev->type                = ARPHRD_RAWHDLC;
246
        dev->hard_header_len     = 16;
247
        dev->addr_len            = 0;
248
        dev->header_ops          = &hdlc_null_ops;
249
 
250
        dev->change_mtu          = hdlc_change_mtu;
251
}
252
 
253
static void hdlc_setup(struct net_device *dev)
254
{
255
        hdlc_device *hdlc = dev_to_hdlc(dev);
256
 
257
        hdlc_setup_dev(dev);
258
        hdlc->carrier = 1;
259
        hdlc->open = 0;
260
        spin_lock_init(&hdlc->state_lock);
261
}
262
 
263
struct net_device *alloc_hdlcdev(void *priv)
264
{
265
        struct net_device *dev;
266
        dev = alloc_netdev(sizeof(struct hdlc_device_desc) +
267
                           sizeof(hdlc_device), "hdlc%d", hdlc_setup);
268
        if (dev)
269
                dev_to_hdlc(dev)->priv = priv;
270
        return dev;
271
}
272
 
273
void unregister_hdlc_device(struct net_device *dev)
274
{
275
        rtnl_lock();
276
        unregister_netdevice(dev);
277
        detach_hdlc_protocol(dev);
278
        rtnl_unlock();
279
}
280
 
281
 
282
 
283
int attach_hdlc_protocol(struct net_device *dev, struct hdlc_proto *proto,
284
                         int (*rx)(struct sk_buff *skb), size_t size)
285
{
286
        detach_hdlc_protocol(dev);
287
 
288
        if (!try_module_get(proto->module))
289
                return -ENOSYS;
290
 
291
        if (size)
292
                if ((dev_to_hdlc(dev)->state = kmalloc(size,
293
                                                       GFP_KERNEL)) == NULL) {
294
                        printk(KERN_WARNING "Memory squeeze on"
295
                               " hdlc_proto_attach()\n");
296
                        module_put(proto->module);
297
                        return -ENOBUFS;
298
                }
299
        dev_to_hdlc(dev)->proto = proto;
300
        dev_to_desc(dev)->netif_rx = rx;
301
        return 0;
302
}
303
 
304
 
305
void detach_hdlc_protocol(struct net_device *dev)
306
{
307
        hdlc_device *hdlc = dev_to_hdlc(dev);
308
 
309
        if (hdlc->proto) {
310
                if (hdlc->proto->detach)
311
                        hdlc->proto->detach(dev);
312
                module_put(hdlc->proto->module);
313
                hdlc->proto = NULL;
314
        }
315
        kfree(hdlc->state);
316
        hdlc->state = NULL;
317
        hdlc_setup_dev(dev);
318
}
319
 
320
 
321
void register_hdlc_protocol(struct hdlc_proto *proto)
322
{
323
        proto->next = first_proto;
324
        first_proto = proto;
325
}
326
 
327
 
328
void unregister_hdlc_protocol(struct hdlc_proto *proto)
329
{
330
        struct hdlc_proto **p = &first_proto;
331
        while (*p) {
332
                if (*p == proto) {
333
                        *p = proto->next;
334
                        return;
335
                }
336
                p = &((*p)->next);
337
        }
338
}
339
 
340
 
341
 
342
MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
343
MODULE_DESCRIPTION("HDLC support module");
344
MODULE_LICENSE("GPL v2");
345
 
346
EXPORT_SYMBOL(hdlc_open);
347
EXPORT_SYMBOL(hdlc_close);
348
EXPORT_SYMBOL(hdlc_ioctl);
349
EXPORT_SYMBOL(alloc_hdlcdev);
350
EXPORT_SYMBOL(unregister_hdlc_device);
351
EXPORT_SYMBOL(register_hdlc_protocol);
352
EXPORT_SYMBOL(unregister_hdlc_protocol);
353
EXPORT_SYMBOL(attach_hdlc_protocol);
354
EXPORT_SYMBOL(detach_hdlc_protocol);
355
 
356
static struct packet_type hdlc_packet_type = {
357
        .type = __constant_htons(ETH_P_HDLC),
358
        .func = hdlc_rcv,
359
};
360
 
361
 
362
static struct notifier_block hdlc_notifier = {
363
        .notifier_call = hdlc_device_event,
364
};
365
 
366
 
367
static int __init hdlc_module_init(void)
368
{
369
        int result;
370
 
371
        printk(KERN_INFO "%s\n", version);
372
        if ((result = register_netdevice_notifier(&hdlc_notifier)) != 0)
373
                return result;
374
        dev_add_pack(&hdlc_packet_type);
375
        return 0;
376
}
377
 
378
 
379
 
380
static void __exit hdlc_module_exit(void)
381
{
382
        dev_remove_pack(&hdlc_packet_type);
383
        unregister_netdevice_notifier(&hdlc_notifier);
384
}
385
 
386
 
387
module_init(hdlc_module_init);
388
module_exit(hdlc_module_exit);

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.