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

Subversion Repositories or1k_old

[/] [or1k_old/] [trunk/] [rc203soc/] [sw/] [uClinux/] [net/] [netlink.c] - Blame information for rev 1782

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1629 jcastillo
/*
2
 * SKIPLINK     An implementation of a loadable kernel mode driver providing
3
 *              multiple kernel/user space bidirectional communications links.
4
 *
5
 *              Author:         Alan Cox <alan@cymru.net>
6
 *
7
 *              This program is free software; you can redistribute it and/or
8
 *              modify it under the terms of the GNU General Public License
9
 *              as published by the Free Software Foundation; either version
10
 *              2 of the License, or (at your option) any later version.
11
 *
12
 */
13
 
14
#include <linux/module.h>
15
 
16
#include <linux/errno.h>
17
#include <linux/kernel.h>
18
#include <linux/major.h>
19
#include <linux/sched.h>
20
#include <linux/lp.h>
21
#include <linux/malloc.h>
22
#include <linux/ioport.h>
23
#include <linux/fcntl.h>
24
#include <linux/delay.h>
25
#include <linux/skbuff.h>
26
 
27
#include <net/netlink.h>
28
 
29
#include <asm/io.h>
30
#include <asm/segment.h>
31
#include <asm/system.h>
32
 
33
static int (*netlink_handler[MAX_LINKS])(struct sk_buff *skb);
34
static struct sk_buff_head skb_queue_rd[MAX_LINKS];
35
static int rdq_size[MAX_LINKS];
36
static struct wait_queue *read_space_wait[MAX_LINKS];
37
 
38
static int active_map = 0;
39
static int open_map = 0;
40
 
41
/*
42
 *      Device operations
43
 */
44
 
45
/*
46
 *      Default write handler.
47
 */
48
 
49
static int netlink_err(struct sk_buff *skb)
50
{
51
        kfree_skb(skb, FREE_READ);
52
        return -EUNATCH;
53
}
54
 
55
/*
56
 *      Exported do nothing receiver for one way
57
 *      interfaces.
58
 */
59
 
60
int netlink_donothing(struct sk_buff *skb)
61
{
62
        kfree_skb(skb, FREE_READ);
63
        return -EINVAL;
64
}
65
 
66
static int netlink_select(struct inode *inode, struct file *file, int sel_type, select_table * wait)
67
{
68
        unsigned int minor = MINOR(inode->i_rdev);
69
        switch (sel_type) {
70
        case SEL_IN:
71
                if (skb_peek(&skb_queue_rd[minor])!=NULL)
72
                        return 1;
73
                select_wait(&read_space_wait[minor], wait);
74
                break;
75
        case SEL_OUT:
76
                return 1;
77
        }
78
        return 0;
79
}
80
 
81
/*
82
 *      Write a message to the kernel side of a communication link
83
 */
84
 
85
static int netlink_write(struct inode * inode, struct file * file, const char * buf, int count)
86
{
87
        unsigned int minor = MINOR(inode->i_rdev);
88
        struct sk_buff *skb;
89
        skb=alloc_skb(count, GFP_KERNEL);
90
        if (!skb)
91
                return -ENOBUFS;
92
        skb->free=1;
93
        memcpy_fromfs(skb_put(skb,count),buf, count);
94
        return (netlink_handler[minor])(skb);
95
}
96
 
97
/*
98
 *      Read a message from the kernel side of the communication link
99
 */
100
 
101
static int netlink_read(struct inode * inode, struct file * file, char * buf, int count)
102
{
103
        unsigned int minor = MINOR(inode->i_rdev);
104
        struct sk_buff *skb;
105
        cli();
106
        while((skb=skb_dequeue(&skb_queue_rd[minor]))==NULL)
107
        {
108
                if(file->f_flags&O_NONBLOCK)
109
                {
110
                        sti();
111
                        return -EAGAIN;
112
                }
113
                interruptible_sleep_on(&read_space_wait[minor]);
114
                if(current->signal & ~current->blocked)
115
                {
116
                        sti();
117
                        return -ERESTARTSYS;
118
                }
119
        }
120
        rdq_size[minor]-=skb->len;
121
        sti();
122
        if(skb->len<count)
123
                count=skb->len;
124
        memcpy_tofs(buf,skb->data,count);
125
        kfree_skb(skb, FREE_READ);
126
        return count;
127
}
128
 
129
static int netlink_lseek(struct inode * inode, struct file * file,
130
                    off_t offset, int origin)
131
{
132
        return -ESPIPE;
133
}
134
 
135
static int netlink_open(struct inode * inode, struct file * file)
136
{
137
        unsigned int minor = MINOR(inode->i_rdev);
138
 
139
        if(minor>=MAX_LINKS)
140
                return -ENODEV;
141
        if(open_map&(1<<minor))
142
                return -EBUSY;
143
        if(active_map&(1<<minor))
144
        {
145
                open_map|=(1<<minor);
146
                MOD_INC_USE_COUNT;
147
                return 0;
148
        }
149
        return -EUNATCH;
150
}
151
 
152
static void netlink_release(struct inode * inode, struct file * file)
153
{
154
        unsigned int minor = MINOR(inode->i_rdev);
155
        open_map&=~(1<<minor);
156
        MOD_DEC_USE_COUNT;
157
}
158
 
159
 
160
static int netlink_ioctl(struct inode *inode, struct file *file,
161
                    unsigned int cmd, unsigned long arg)
162
{
163
        unsigned int minor = MINOR(inode->i_rdev);
164
        int retval = 0;
165
 
166
        if (minor >= MAX_LINKS)
167
                return -ENODEV;
168
        switch ( cmd ) {
169
                default:
170
                        retval = -EINVAL;
171
        }
172
        return retval;
173
}
174
 
175
 
176
static struct file_operations netlink_fops = {
177
        netlink_lseek,
178
        netlink_read,
179
        netlink_write,
180
        NULL,           /* netlink_readdir */
181
        netlink_select,
182
        netlink_ioctl,
183
        NULL,           /* netlink_mmap */
184
        netlink_open,
185
        netlink_release
186
};
187
 
188
/*
189
 *      We export these functions to other modules. They provide a
190
 *      complete set of kernel non-blocking support for message
191
 *      queueing.
192
 */
193
 
194
int netlink_attach(int unit, int (*function)(struct sk_buff *skb))
195
{
196
        if(unit>=MAX_LINKS)
197
                return -ENODEV;
198
        if(active_map&(1<<unit))
199
                return -EBUSY;
200
        active_map|=(1<<unit);
201
        open_map&=~(1<<unit);
202
        netlink_handler[unit]=function;
203
        return 0;
204
}
205
 
206
void netlink_detach(int unit)
207
{
208
        active_map&=~(1<<unit);
209
        netlink_handler[unit]=netlink_err;
210
        open_map&=~(1<<unit);
211
}
212
 
213
int netlink_post(int unit, struct sk_buff *skb)
214
{
215
        unsigned long flags;
216
        int ret=-EUNATCH;
217
        if(open_map&(1<<unit))
218
        {
219
                save_flags(flags);
220
                cli();
221
                if(rdq_size[unit]+skb->len>MAX_QBYTES)
222
                        ret=-EAGAIN;
223
                else
224
                {
225
                        skb_queue_tail(&skb_queue_rd[unit], skb);
226
                        rdq_size[unit]+=skb->len;
227
                        ret=0;
228
                        wake_up_interruptible(&read_space_wait[unit]);
229
                }
230
                restore_flags(flags);
231
        }
232
        return ret;
233
}
234
 
235
int init_netlink(void)
236
{
237
        int ct;
238
 
239
        if(register_chrdev(NETLINK_MAJOR,"netlink", &netlink_fops)) {
240
                printk(KERN_ERR "netlink: unable to get major %d\n", NETLINK_MAJOR);
241
                return -EIO;
242
        }
243
        for(ct=0;ct<MAX_LINKS;ct++)
244
        {
245
                skb_queue_head_init(&skb_queue_rd[ct]);
246
                netlink_handler[ct]=netlink_err;
247
        }
248
        return 0;
249
}
250
 
251
#ifdef MODULE
252
 
253
int init_module(void)
254
{
255
        printk(KERN_INFO "Network Kernel/User communications module 0.03\n");
256
        return init_netlink();
257
}
258
 
259
void cleanup_module(void)
260
{
261
        unregister_chrdev(NET_MAJOR,"netlink");
262
}
263
 
264
#endif

powered by: WebSVN 2.1.0

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