]>
Commit | Line | Data |
---|---|---|
1cfdc698 | 1 | diff -urN linux.orig/Documentation/Configure.help linux/Documentation/Configure.help |
2 | --- linux.orig/Documentation/Configure.help.orig Fri Jan 4 12:58:32 2002 | |
3 | +++ linux/Documentation/Configure.help Fri Jan 4 13:00:14 2002 | |
4 | @@ -6391,6 +6391,19 @@ | |
5 | briefly removed during revalidation. If you say Y here, packets to | |
6 | such neighbours are silently discarded instead. | |
7 | ||
8 | +RFC1483/2684 Bridged protocols | |
9 | +CONFIG_ATM_BR2684 | |
10 | + ATM PVCs can carry ethernet PDUs according to rfc2684 (formerly 1483) | |
11 | + This device will act like an ethernet from the kernels point of view, | |
12 | + with the traffic being carried by ATM PVCs (currently 1 PVC/device). | |
13 | + This is sometimes used over DSL lines. If in doubt, say N. | |
14 | + | |
15 | +Per-VC IP filter kludge | |
16 | +CONFIG_ATM_BR2684_IPFILTER | |
17 | + This is an experimental mechanism for users who need to terminating a | |
18 | + large number of IP-only vcc's. Do not enable this unless you are sure | |
19 | + you know what you are doing. | |
20 | + | |
21 | LAN Emulation (LANE) support | |
22 | CONFIG_ATM_LANE | |
23 | LAN Emulation emulates services of existing LANs across an ATM | |
24 | @@ -8826,6 +8839,13 @@ | |
25 | pppd, along with binaries of a patched pppd package can be found at: | |
26 | <http://www.shoshin.uwaterloo.ca/~mostrows/>. | |
27 | ||
28 | +PPP over ATM (EXPERIMENTAL) | |
29 | +CONFIG_PPPOATM | |
30 | + PPP over ATM is one of several protocols used over DSL lines. | |
31 | + If you are connecting to a DSL line using an internal ATM or | |
32 | + DSL adaptor (as opposed to an ethernet card) then there is | |
33 | + a good possibility you will need this protocol. | |
34 | + | |
35 | Wireless LAN (non-hamradio) | |
36 | CONFIG_NET_RADIO | |
37 | Support for wireless LANs and everything having to do with radio, | |
38 | diff -urN linux.orig/MAINTAINERS linux/MAINTAINERS | |
39 | --- linux.orig/MAINTAINERS Sat Apr 21 18:05:00 2001 | |
40 | +++ linux/MAINTAINERS Sat Apr 21 18:07:12 2001 | |
41 | @@ -1060,6 +1060,11 @@ | |
42 | L: linux-ppp@vger.kernel.org | |
43 | S: Maintained | |
44 | ||
45 | +PPP OVER ATM (RFC 2364) | |
46 | +P: Mitchell Blank Jr | |
47 | +M: mitch@sfgoth.com | |
48 | +S: Maintained | |
49 | + | |
50 | PPP OVER ETHERNET | |
51 | P: Michal Ostrowski | |
52 | M: mostrows@styx.uwaterloo.ca | |
53 | diff -urN linux.orig/arch/sparc/config.in linux/arch/sparc/config.in | |
54 | --- linux.orig/arch/sparc/config.in Sat Apr 21 18:04:59 2001 | |
55 | +++ linux/arch/sparc/config.in Sat Apr 21 18:06:09 2001 | |
56 | @@ -215,6 +215,12 @@ | |
57 | dep_tristate ' PPP support for sync tty ports' CONFIG_PPP_SYNC_TTY $CONFIG_PPP | |
58 | dep_tristate ' PPP Deflate compression' CONFIG_PPP_DEFLATE $CONFIG_PPP | |
59 | dep_tristate ' PPP BSD-Compress compression' CONFIG_PPP_BSDCOMP m | |
60 | + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then | |
61 | + dep_tristate ' PPP over Ethernet (EXPERIMENTAL)' CONFIG_PPPOE $CONFIG_PPP | |
62 | + if [ "$CONFIG_ATM" = "y" ]; then | |
63 | + dep_tristate ' PPP over ATM (EXPERIMENTAL)' CONFIG_PPPOATM $CONFIG_PPP | |
64 | + fi | |
65 | + fi | |
66 | fi | |
67 | tristate ' SLIP (serial line) support' CONFIG_SLIP | |
68 | if [ "$CONFIG_SLIP" != "n" ]; then | |
69 | diff -urN linux.orig/drivers/net/Config.in linux/drivers/net/Config.in | |
70 | --- linux.orig/drivers/net/Config.in Sat Apr 21 18:04:55 2001 | |
71 | +++ linux/drivers/net/Config.in Sat Apr 21 18:06:09 2001 | |
72 | @@ -245,6 +245,9 @@ | |
73 | dep_tristate ' PPP BSD-Compress compression' CONFIG_PPP_BSDCOMP $CONFIG_PPP | |
74 | if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then | |
75 | dep_tristate ' PPP over Ethernet (EXPERIMENTAL)' CONFIG_PPPOE $CONFIG_PPP | |
76 | + if [ "$CONFIG_ATM" = "y" ]; then | |
77 | + dep_tristate ' PPP over ATM (EXPERIMENTAL)' CONFIG_PPPOATM $CONFIG_PPP $CONFIG_EXPERIMENTAL | |
78 | + fi | |
79 | fi | |
80 | fi | |
81 | ||
82 | diff -urN linux.orig/include/linux/atmbr2684.h linux/include/linux/atmbr2684.h | |
83 | --- linux.orig/include/linux/atmbr2684.h Thu Jan 1 01:00:00 1970 | |
84 | +++ linux/include/linux/atmbr2684.h Sat Apr 21 18:06:09 2001 | |
85 | @@ -0,0 +1,101 @@ | |
86 | +#ifndef _LINUX_ATMBR2684_H | |
87 | +#define _LINUX_ATMBR2684_H | |
88 | + | |
89 | +#include <linux/atm.h> | |
90 | +#include <linux/if.h> /* For IFNAMSIZ */ | |
91 | + | |
92 | +/* | |
93 | + * Type of media we're bridging (ethernet, token ring, etc) Currently only | |
94 | + * ethernet is supported | |
95 | + */ | |
96 | +#define BR2684_MEDIA_ETHERNET (0) /* 802.3 */ | |
97 | +#define BR2684_MEDIA_802_4 (1) /* 802.4 */ | |
98 | +#define BR2684_MEDIA_TR (2) /* 802.5 - token ring */ | |
99 | +#define BR2684_MEDIA_FDDI (3) | |
100 | +#define BR2684_MEDIA_802_6 (4) /* 802.6 */ | |
101 | + | |
102 | +/* | |
103 | + * Is there FCS inbound on this VC? This currently isn't supported. | |
104 | + */ | |
105 | +#define BR2684_FCSIN_NO (0) | |
106 | +#define BR2684_FCSIN_IGNORE (1) | |
107 | +#define BR2684_FCSIN_VERIFY (2) | |
108 | + | |
109 | +/* | |
110 | + * Is there FCS outbound on this VC? This currently isn't supported. | |
111 | + */ | |
112 | +#define BR2684_FCSOUT_NO (0) | |
113 | +#define BR2684_FCSOUT_SENDZERO (1) | |
114 | +#define BR2684_FCSOUT_GENERATE (2) | |
115 | + | |
116 | +/* | |
117 | + * Does this VC include LLC encapsulation? | |
118 | + */ | |
119 | +#define BR2684_ENCAPS_VC (0) /* VC-mux */ | |
120 | +#define BR2684_ENCAPS_LLC (1) | |
121 | +#define BR2684_ENCAPS_AUTODETECT (2) /* Unsuported */ | |
122 | + | |
123 | +/* | |
124 | + * This is for the ATM_NEWBACKENDIF call - these are like socket families: | |
125 | + * the first element of the structure is the backend number and the rest | |
126 | + * is per-backend specific | |
127 | + */ | |
128 | +struct atm_newif_br2684 { | |
129 | + atm_backend_t backend_num; /* ATM_BACKEND_BR2684 */ | |
130 | + int media; /* BR2684_MEDIA_* */ | |
131 | + char ifname[IFNAMSIZ]; | |
132 | + int mtu; | |
133 | +}; | |
134 | + | |
135 | +/* | |
136 | + * This structure is used to specify a br2684 interface - either by a | |
137 | + * positive integer (returned by ATM_NEWBACKENDIF) or the interfaces name | |
138 | + */ | |
139 | +#define BR2684_FIND_BYNOTHING (0) | |
140 | +#define BR2684_FIND_BYNUM (1) | |
141 | +#define BR2684_FIND_BYIFNAME (2) | |
142 | +struct br2684_if_spec { | |
143 | + int method; /* BR2684_FIND_* */ | |
144 | + union { | |
145 | + char ifname[IFNAMSIZ]; | |
146 | + int devnum; | |
147 | + } spec; | |
148 | +}; | |
149 | + | |
150 | +/* | |
151 | + * This is for the ATM_SETBACKEND call - these are like socket families: | |
152 | + * the first element of the structure is the backend number and the rest | |
153 | + * is per-backend specific | |
154 | + */ | |
155 | +struct atm_backend_br2684 { | |
156 | + atm_backend_t backend_num; /* ATM_BACKEND_BR2684 */ | |
157 | + struct br2684_if_spec ifspec; | |
158 | + int fcs_in; /* BR2684_FCSIN_* */ | |
159 | + int fcs_out; /* BR2684_FCSOUT_* */ | |
160 | + int fcs_auto; /* 1: fcs_{in,out} disabled if no FCS rx'ed */ | |
161 | + int encaps; /* BR2684_ENCAPS_* */ | |
162 | + int has_vpiid; /* 1: use vpn_id - Unsupported */ | |
163 | + __u8 vpn_id[7]; | |
164 | + int send_padding; /* unsupported */ | |
165 | + int min_size; /* we will pad smaller packets than this */ | |
166 | +}; | |
167 | + | |
168 | +/* | |
169 | + * The BR2684_SETFILT ioctl is an experimental mechanism for folks | |
170 | + * terminating a large number of IP-only vcc's. When netfilter allows | |
171 | + * efficient per-if in/out filters, this support will be removed | |
172 | + */ | |
173 | +struct br2684_filter { | |
174 | + __u32 prefix; /* network byte order */ | |
175 | + __u32 netmask; /* 0 = disable filter */ | |
176 | +}; | |
177 | + | |
178 | +struct br2684_filter_set { | |
179 | + struct br2684_if_spec ifspec; | |
180 | + struct br2684_filter filter; | |
181 | +}; | |
182 | + | |
183 | +#define BR2684_SETFILT _IOW( 'a', ATMIOC_BACKEND + 0, \ | |
184 | + struct br2684_filter_set) | |
185 | + | |
186 | +#endif /* _LINUX_ATMBR2684_H */ | |
187 | diff -urN linux.orig/include/linux/atmdev.h linux/include/linux/atmdev.h | |
188 | --- linux.orig/include/linux/atmdev.h Tue Mar 27 01:50:03 2001 | |
189 | +++ linux/include/linux/atmdev.h Sat Apr 21 18:06:09 2001 | |
190 | @@ -95,6 +95,8 @@ | |
191 | /* enable or disable single-copy */ | |
192 | #define ATM_SETBACKEND _IOW('a',ATMIOC_SPECIAL+2,atm_backend_t) | |
193 | /* set backend handler */ | |
194 | +#define ATM_NEWBACKENDIF _IOW('a',ATMIOC_SPECIAL+3,atm_backend_t) | |
195 | + /* use backend to make new if */ | |
196 | ||
197 | /* | |
198 | * These are backend handkers that can be set via the ATM_SETBACKEND call | |
199 | diff -urN linux.orig/net/Config.in linux/net/Config.in | |
200 | --- linux.orig/net/Config.in Sat Apr 21 18:05:00 2001 | |
201 | +++ linux/net/Config.in Sat Apr 21 18:06:09 2001 | |
202 | @@ -45,6 +45,10 @@ | |
203 | if [ "$CONFIG_INET" = "y" -a "$CONFIG_ATM_LANE" != "n" ]; then | |
204 | tristate ' Multi-Protocol Over ATM (MPOA) support' CONFIG_ATM_MPOA | |
205 | fi | |
206 | + tristate ' RFC1483/2684 Bridged protocols' CONFIG_ATM_BR2684 | |
207 | + if [ "$CONFIG_ATM_BR2684" != "n" ]; then | |
208 | + bool ' Per-VC IP filter kludge' CONFIG_ATM_BR2684_IPFILTER | |
209 | + fi | |
210 | fi | |
211 | fi | |
212 | ||
213 | diff -urN linux.orig/net/atm/Makefile linux/net/atm/Makefile | |
214 | --- linux.orig/net/atm/Makefile Tue Mar 27 01:36:30 2001 | |
215 | +++ linux/net/atm/Makefile Sat Apr 21 18:06:09 2001 | |
216 | @@ -21,6 +21,15 @@ | |
217 | NEED_IPCOM = ipcommon.o | |
218 | endif | |
219 | ||
220 | +ifeq ($(CONFIG_ATM_BR2684),y) | |
221 | + NEED_IPCOM = ipcommon.o | |
222 | +else | |
223 | + ifeq ($(CONFIG_ATM_BR2684),m) | |
224 | + NEED_IPCOM = ipcommon.o | |
225 | + endif | |
226 | +endif | |
227 | +obj-$(CONFIG_ATM_BR2684) += br2684.o | |
228 | + | |
229 | ifeq ($(CONFIG_NET_SCH_ATM),y) | |
230 | NEED_IPCOM = ipcommon.o | |
231 | endif | |
232 | diff -urN linux.orig/net/atm/br2684.c linux/net/atm/br2684.c | |
233 | --- linux.orig/net/atm/br2684.c Thu Jan 1 01:00:00 1970 | |
234 | +++ linux/net/atm/br2684.c Sat Apr 21 18:06:09 2001 | |
235 | @@ -0,0 +1,794 @@ | |
236 | +/* | |
237 | +Experimental ethernet netdevice using ATM AAL5 as underlying carrier | |
238 | +(RFC1483 obsoleted by RFC2684) for Linux 2.4 | |
239 | +Author: Marcell GAL, 2000, XDSL Ltd, Hungary | |
240 | +*/ | |
241 | + | |
242 | +#include <linux/module.h> | |
243 | +#include <linux/config.h> | |
244 | +#include <linux/init.h> | |
245 | +#include <linux/kernel.h> | |
246 | +#include <linux/list.h> | |
247 | +#include <asm/uaccess.h> | |
248 | +#include <linux/netdevice.h> | |
249 | +#include <linux/skbuff.h> | |
250 | +#include <linux/etherdevice.h> | |
251 | +#include <net/arp.h> | |
252 | +#include <linux/rtnetlink.h> | |
253 | +#include <linux/atmbr2684.h> | |
254 | + | |
255 | +#include "ipcommon.h" | |
256 | + | |
257 | +/* | |
258 | + * Define this to use a version of the code which interacts with the higher | |
259 | + * layers in a more intellegent way, by always reserving enough space for | |
260 | + * our header at the begining of the packet. However, there may still be | |
261 | + * some problems with programs like tcpdump. In 2.5 we'll sort out what | |
262 | + * we need to do to get this perfect. For now we just will copy the packet | |
263 | + * if we need space for the header | |
264 | + */ | |
265 | +/* #define FASTER_VERSION */ | |
266 | + | |
267 | +#ifdef DEBUG | |
268 | +#define DPRINTK(format, args...) printk(KERN_DEBUG "br2684: " format, ##args) | |
269 | +#else | |
270 | +#define DPRINTK(format, args...) | |
271 | +#endif | |
272 | + | |
273 | +#ifdef SKB_DEBUG | |
274 | +static void skb_debug(const struct sk_buff *skb) | |
275 | +{ | |
276 | +#define NUM2PRINT 50 | |
277 | + char buf[NUM2PRINT * 3 + 1]; /* 3 chars per byte */ | |
278 | + int i = 0; | |
279 | + for (i = 0; i < skb->len && i < NUM2PRINT; i++) { | |
280 | + sprintf(buf + i * 3, "%2.2x ", 0xff & skb->data[i]); | |
281 | + } | |
282 | + printk(KERN_DEBUG "br2684: skb: %s\n", buf); | |
283 | +} | |
284 | +#else | |
285 | +#define skb_debug(skb) do {} while (0) | |
286 | +#endif | |
287 | + | |
288 | +static unsigned char llc_oui_pid_pad[] = | |
289 | + { 0xAA, 0xAA, 0x03, 0x00, 0x80, 0xC2, 0x00, 0x07, 0x00, 0x00 }; | |
290 | +#define PADLEN (2) | |
291 | + | |
292 | +enum br2684_encaps { | |
293 | + e_vc = BR2684_ENCAPS_VC, | |
294 | + e_llc = BR2684_ENCAPS_LLC, | |
295 | +}; | |
296 | + | |
297 | +struct br2684_vcc { | |
298 | + struct atm_vcc *atmvcc; | |
299 | + struct br2684_dev *brdev; | |
300 | + /* keep old push,pop functions for chaining */ | |
301 | + void (*old_push)(struct atm_vcc *vcc,struct sk_buff *skb); | |
302 | + /* void (*old_pop)(struct atm_vcc *vcc,struct sk_buff *skb); */ | |
303 | + enum br2684_encaps encaps; | |
304 | + struct list_head brvccs; | |
305 | +#ifdef CONFIG_ATM_BR2684_IPFILTER | |
306 | + struct br2684_filter filter; | |
307 | +#endif /* CONFIG_ATM_BR2684_IPFILTER */ | |
308 | +#ifndef FASTER_VERSION | |
309 | + unsigned copies_needed, copies_failed; | |
310 | +#endif /* FASTER_VERSION */ | |
311 | +}; | |
312 | + | |
313 | +struct br2684_dev { | |
314 | + struct net_device net_dev; | |
315 | + struct list_head br2684_devs; | |
316 | + int number; | |
317 | + struct list_head brvccs; /* one device <=> one vcc (before xmas) */ | |
318 | + struct net_device_stats stats; | |
319 | + int mac_was_set; | |
320 | +}; | |
321 | + | |
322 | +/* | |
323 | + * This lock should be held for writing any time the list of devices or | |
324 | + * their attached vcc's could be altered. It should be held for reading | |
325 | + * any time these are being queried. Note that we sometimes need to | |
326 | + * do read-locking under interrupt context, so write locking must block | |
327 | + * the current CPU's interrupts | |
328 | + */ | |
329 | +static rwlock_t devs_lock = RW_LOCK_UNLOCKED; | |
330 | + | |
331 | +static LIST_HEAD(br2684_devs); | |
332 | + | |
333 | +static inline struct br2684_dev *BRPRIV(const struct net_device *net_dev) | |
334 | +{ | |
335 | + return (struct br2684_dev *) ((char *) (net_dev) - | |
336 | + (unsigned long) (&((struct br2684_dev *) 0)->net_dev)); | |
337 | +} | |
338 | + | |
339 | +static inline struct br2684_dev *list_entry_brdev(const struct list_head *le) | |
340 | +{ | |
341 | + return list_entry(le, struct br2684_dev, br2684_devs); | |
342 | +} | |
343 | + | |
344 | +static inline struct br2684_vcc *BR2684_VCC(const struct atm_vcc *atmvcc) | |
345 | +{ | |
346 | + return (struct br2684_vcc *) (atmvcc->user_back); | |
347 | +} | |
348 | + | |
349 | +static inline struct br2684_vcc *list_entry_brvcc(const struct list_head *le) | |
350 | +{ | |
351 | + return list_entry(le, struct br2684_vcc, brvccs); | |
352 | +} | |
353 | + | |
354 | +/* Caller should hold read_lock(&devs_lock) */ | |
355 | +static struct br2684_dev *br2684_find_dev(const struct br2684_if_spec *s) | |
356 | +{ | |
357 | + struct list_head *lh; | |
358 | + struct br2684_dev *brdev; | |
359 | + switch (s->method) { | |
360 | + case BR2684_FIND_BYNUM: | |
361 | + list_for_each(lh, &br2684_devs) { | |
362 | + brdev = list_entry_brdev(lh); | |
363 | + if (brdev->number == s->spec.devnum) | |
364 | + return brdev; | |
365 | + } | |
366 | + break; | |
367 | + case BR2684_FIND_BYIFNAME: | |
368 | + list_for_each(lh, &br2684_devs) { | |
369 | + brdev = list_entry_brdev(lh); | |
370 | + if (!strncmp(brdev->net_dev.name, s->spec.ifname, | |
371 | + sizeof brdev->net_dev.name)) | |
372 | + return brdev; | |
373 | + } | |
374 | + break; | |
375 | + } | |
376 | + return NULL; | |
377 | +} | |
378 | + | |
379 | +/* | |
380 | + * Send a packet out a particular vcc. Not to useful right now, but paves | |
381 | + * the way for multiple vcc's per itf. Returns true if we can send, | |
382 | + * otherwise false | |
383 | + */ | |
384 | +static int br2684_xmit_vcc(struct sk_buff *skb, struct br2684_dev *brdev, | |
385 | + struct br2684_vcc *brvcc) | |
386 | +{ | |
387 | + struct atm_vcc *atmvcc; | |
388 | +#ifdef FASTER_VERSION | |
389 | + if (brvcc->encaps == e_llc) | |
390 | + memcpy(skb_push(skb, 8), llc_oui_pid_pad, 8); | |
391 | + /* last 2 bytes of llc_oui_pid_pad are managed by header routines; | |
392 | + yes, you got it: 8 + 2 = sizeof(llc_oui_pid_pad) | |
393 | + */ | |
394 | +#else | |
395 | + int minheadroom = (brvcc->encaps == e_llc) ? 10 : 2; | |
396 | + if (skb_headroom(skb) < minheadroom) { | |
397 | + struct sk_buff *skb2 = skb_realloc_headroom(skb, minheadroom); | |
398 | + brvcc->copies_needed++; | |
399 | + dev_kfree_skb(skb); | |
400 | + if (skb2 == NULL) { | |
401 | + brvcc->copies_failed++; | |
402 | + return 0; | |
403 | + } | |
404 | + skb = skb2; | |
405 | + } | |
406 | + skb_push(skb, minheadroom); | |
407 | + if (brvcc->encaps == e_llc) | |
408 | + memcpy(skb->data, llc_oui_pid_pad, 10); | |
409 | + else | |
410 | + memset(skb->data, 0, 2); | |
411 | +#endif /* FASTER_VERSION */ | |
412 | + skb_debug(skb); | |
413 | + | |
414 | + ATM_SKB(skb)->vcc = atmvcc = brvcc->atmvcc; | |
415 | + DPRINTK("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, atmvcc, atmvcc->dev); | |
416 | + if (!atm_may_send(atmvcc, skb->truesize)) { | |
417 | + /* we free this here for now, because we cannot know in a higher | |
418 | + layer whether the skb point it supplied wasn't freed yet. | |
419 | + now, it always is. | |
420 | + */ | |
421 | + dev_kfree_skb(skb); | |
422 | + return 0; | |
423 | + } | |
424 | + atomic_add(skb->truesize, &atmvcc->tx_inuse); | |
425 | + ATM_SKB(skb)->iovcnt = 0; | |
426 | + ATM_SKB(skb)->atm_options = atmvcc->atm_options; | |
427 | + brdev->stats.tx_packets++; | |
428 | + brdev->stats.tx_bytes += skb->len; | |
429 | + atmvcc->send(atmvcc, skb); | |
430 | + return 1; | |
431 | +} | |
432 | + | |
433 | +static inline struct br2684_vcc *pick_outgoing_vcc(struct sk_buff *skb, | |
434 | + struct br2684_dev *brdev) | |
435 | +{ | |
436 | + return list_empty(&brdev->brvccs) ? NULL : | |
437 | + list_entry_brvcc(brdev->brvccs.next); /* 1 vcc/dev right now */ | |
438 | +} | |
439 | + | |
440 | +static int br2684_start_xmit(struct sk_buff *skb, struct net_device *dev) | |
441 | +{ | |
442 | + struct br2684_dev *brdev = BRPRIV(dev); | |
443 | + struct br2684_vcc *brvcc; | |
444 | + | |
445 | + DPRINTK("br2684_start_xmit, skb->dst=%p\n", skb->dst); | |
446 | + read_lock(&devs_lock); | |
447 | + brvcc = pick_outgoing_vcc(skb, brdev); | |
448 | + if (brvcc == NULL) { | |
449 | + DPRINTK("no vcc attached to dev %s\n", dev->name); | |
450 | + brdev->stats.tx_errors++; | |
451 | + brdev->stats.tx_carrier_errors++; | |
452 | + /* netif_stop_queue(dev); */ | |
453 | + dev_kfree_skb(skb); | |
454 | + read_unlock(&devs_lock); | |
455 | + return -EUNATCH; | |
456 | + } | |
457 | + if (!br2684_xmit_vcc(skb, brdev, brvcc)) { | |
458 | + /* | |
459 | + * We should probably use netif_*_queue() here, but that | |
460 | + * involves added complication. We need to walk before | |
461 | + * we can run | |
462 | + */ | |
463 | + /* don't free here! this pointer might be no longer valid! | |
464 | + dev_kfree_skb(skb); | |
465 | + */ | |
466 | + brdev->stats.tx_errors++; | |
467 | + brdev->stats.tx_fifo_errors++; | |
468 | + } | |
469 | + read_unlock(&devs_lock); | |
470 | + return 0; | |
471 | +} | |
472 | + | |
473 | +static struct net_device_stats *br2684_get_stats(struct net_device *dev) | |
474 | +{ | |
475 | + DPRINTK("br2684_get_stats\n"); | |
476 | + return &BRPRIV(dev)->stats; | |
477 | +} | |
478 | + | |
479 | +#ifdef FASTER_VERSION | |
480 | +/* | |
481 | + * These mirror eth_header and eth_header_cache. They are not usually | |
482 | + * exported for use in modules, so we grab them from net_device | |
483 | + * after ether_setup() is done with it. Bit of a hack. | |
484 | + */ | |
485 | +static int (*my_eth_header)(struct sk_buff *, struct net_device *, | |
486 | + unsigned short, void *, void *, unsigned); | |
487 | +static int (*my_eth_header_cache)(struct neighbour *, struct hh_cache *); | |
488 | + | |
489 | +static int | |
490 | +br2684_header(struct sk_buff *skb, struct net_device *dev, | |
491 | + unsigned short type, void *daddr, void *saddr, unsigned len) | |
492 | +{ | |
493 | + u16 *pad_before_eth; | |
494 | + int t = my_eth_header(skb, dev, type, daddr, saddr, len); | |
495 | + if (t > 0) { | |
496 | + pad_before_eth = (u16 *) skb_push(skb, 2); | |
497 | + *pad_before_eth = 0; | |
498 | + return dev->hard_header_len; /* or return 16; ? */ | |
499 | + } else | |
500 | + return t; | |
501 | +} | |
502 | + | |
503 | +static int | |
504 | +br2684_header_cache(struct neighbour *neigh, struct hh_cache *hh) | |
505 | +{ | |
506 | +/* hh_data is 16 bytes long. if encaps is ether-llc we need 24, so | |
507 | +xmit will add the additional header part in that case */ | |
508 | + u16 *pad_before_eth = (u16 *)(hh->hh_data); | |
509 | + int t = my_eth_header_cache(neigh, hh); | |
510 | + DPRINTK("br2684_header_cache, neigh=%p, hh_cache=%p\n", neigh, hh); | |
511 | + if (t < 0) | |
512 | + return t; | |
513 | + else { | |
514 | + *pad_before_eth = 0; | |
515 | + hh->hh_len = PADLEN + ETH_HLEN; | |
516 | + } | |
517 | + return 0; | |
518 | +} | |
519 | + | |
520 | +/* | |
521 | + * This is similar to eth_type_trans, which cannot be used because of | |
522 | + * our dev->hard_header_len | |
523 | + */ | |
524 | +static inline unsigned short br_type_trans(struct sk_buff *skb, | |
525 | + struct net_device *dev) | |
526 | +{ | |
527 | + struct ethhdr *eth; | |
528 | + unsigned char *rawp; | |
529 | + eth = skb->mac.ethernet; | |
530 | + | |
531 | + if (*eth->h_dest & 1) { | |
532 | + if (memcmp(eth->h_dest, dev->broadcast, ETH_ALEN) == 0) | |
533 | + skb->pkt_type = PACKET_BROADCAST; | |
534 | + else | |
535 | + skb->pkt_type = PACKET_MULTICAST; | |
536 | + } | |
537 | + | |
538 | + else if (memcmp(eth->h_dest, dev->dev_addr, ETH_ALEN)) | |
539 | + skb->pkt_type = PACKET_OTHERHOST; | |
540 | + | |
541 | + if (ntohs(eth->h_proto) >= 1536) | |
542 | + return eth->h_proto; | |
543 | + | |
544 | + rawp = skb->data; | |
545 | + | |
546 | + /* | |
547 | + * This is a magic hack to spot IPX packets. Older Novell breaks | |
548 | + * the protocol design and runs IPX over 802.3 without an 802.2 LLC | |
549 | + * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This | |
550 | + * won't work for fault tolerant netware but does for the rest. | |
551 | + */ | |
552 | + if (*(unsigned short *) rawp == 0xFFFF) | |
553 | + return htons(ETH_P_802_3); | |
554 | + | |
555 | + /* | |
556 | + * Real 802.2 LLC | |
557 | + */ | |
558 | + return htons(ETH_P_802_2); | |
559 | +} | |
560 | +#endif /* FASTER_VERSION */ | |
561 | + | |
562 | +/* | |
563 | + * We remember when the MAC gets set, so we don't override it later with | |
564 | + * the ESI of the ATM card of the first VC | |
565 | + */ | |
566 | +static int (*my_eth_mac_addr)(struct net_device *, void *); | |
567 | +static int br2684_mac_addr(struct net_device *dev, void *p) | |
568 | +{ | |
569 | + int err = my_eth_mac_addr(dev, p); | |
570 | + if (!err) | |
571 | + BRPRIV(dev)->mac_was_set = 1; | |
572 | + return err; | |
573 | +} | |
574 | + | |
575 | +#ifdef CONFIG_ATM_BR2684_IPFILTER | |
576 | +/* this IOCTL is experimental. */ | |
577 | +static int br2684_setfilt(struct atm_vcc *atmvcc, unsigned long arg) | |
578 | +{ | |
579 | + struct br2684_vcc *brvcc; | |
580 | + struct br2684_filter_set fs; | |
581 | + | |
582 | + if (copy_from_user(&fs, (void *) arg, sizeof fs)) | |
583 | + return -EFAULT; | |
584 | + if (fs.ifspec.method != BR2684_FIND_BYNOTHING) { | |
585 | + /* | |
586 | + * This is really a per-vcc thing, but we can also search | |
587 | + * by device | |
588 | + */ | |
589 | + struct br2684_dev *brdev; | |
590 | + read_lock(&devs_lock); | |
591 | + brdev = br2684_find_dev(&fs.ifspec); | |
592 | + if (brdev == NULL || list_empty(&brdev->brvccs) || | |
593 | + brdev->brvccs.next != brdev->brvccs.prev) /* >1 VCC */ | |
594 | + brvcc = NULL; | |
595 | + else | |
596 | + brvcc = list_entry_brvcc(brdev->brvccs.next); | |
597 | + read_unlock(&devs_lock); | |
598 | + if (brvcc == NULL) | |
599 | + return -ESRCH; | |
600 | + } else | |
601 | + brvcc = BR2684_VCC(atmvcc); | |
602 | + memcpy(&brvcc->filter, &fs.filter, sizeof(brvcc->filter)); | |
603 | + return 0; | |
604 | +} | |
605 | + | |
606 | +/* Returns 1 if packet should be dropped */ | |
607 | +static inline int | |
608 | +packet_fails_filter(u16 type, struct br2684_vcc *brvcc, struct sk_buff *skb) | |
609 | +{ | |
610 | + if (brvcc->filter.netmask == 0) | |
611 | + return 0; /* no filter in place */ | |
612 | + if (type == __constant_htons(ETH_P_IP) && | |
613 | + (((struct iphdr *) (skb->data))->daddr & brvcc->filter. | |
614 | + netmask) == brvcc->filter.prefix) | |
615 | + return 0; | |
616 | + if (type == __constant_htons(ETH_P_ARP)) | |
617 | + return 0; | |
618 | + /* TODO: we should probably filter ARPs too.. don't want to have | |
619 | + * them returning values that don't make sense, or is that ok? | |
620 | + */ | |
621 | + return 1; /* drop */ | |
622 | +} | |
623 | +#endif /* CONFIG_ATM_BR2684_IPFILTER */ | |
624 | + | |
625 | +static void br2684_close_vcc(struct br2684_vcc *brvcc) | |
626 | +{ | |
627 | + DPRINTK("removing VCC %p from dev %p\n", brvcc, brvcc->brdev); | |
628 | + write_lock_irq(&devs_lock); | |
629 | + list_del(&brvcc->brvccs); | |
630 | + write_unlock_irq(&devs_lock); | |
631 | + brvcc->atmvcc->user_back = NULL; /* what about vcc->recvq ??? */ | |
632 | + brvcc->old_push(brvcc->atmvcc, NULL); /* pass on the bad news */ | |
633 | + kfree(brvcc); | |
634 | + MOD_DEC_USE_COUNT; | |
635 | +} | |
636 | + | |
637 | +/* when AAL5 PDU comes in: */ | |
638 | +static void br2684_push(struct atm_vcc *atmvcc, struct sk_buff *skb) | |
639 | +{ | |
640 | + struct br2684_vcc *brvcc = BR2684_VCC(atmvcc); | |
641 | + struct br2684_dev *brdev = brvcc->brdev; | |
642 | + int plen = sizeof(llc_oui_pid_pad) + ETH_HLEN; | |
643 | + | |
644 | + DPRINTK("br2684_push\n"); | |
645 | + | |
646 | + if (skb == NULL) { /* skb==NULL means VCC is being destroyed */ | |
647 | + br2684_close_vcc(brvcc); | |
648 | + return; | |
649 | + } | |
650 | + | |
651 | + skb_debug(skb); | |
652 | + atm_return(atmvcc, skb->truesize); | |
653 | + DPRINTK("skb from brdev %p\n", brdev); | |
654 | + if (brvcc->encaps == e_llc) { | |
655 | + /* let us waste some time for checking the encapsulation. | |
656 | + Note, that only 7 char is checked so frames with a valid FCS | |
657 | + are also accepted (but FCS is not checked of course) */ | |
658 | + if (memcmp(skb->data, llc_oui_pid_pad, 7)) { | |
659 | + brdev->stats.rx_errors++; | |
660 | + dev_kfree_skb(skb); | |
661 | + return; | |
662 | + } | |
663 | + } else { | |
664 | + plen = PADLEN + ETH_HLEN; /* pad, dstmac,srcmac, ethtype */ | |
665 | + /* first 2 chars should be 0 */ | |
666 | + if (*((u16 *) (skb->data)) != 0) { | |
667 | + brdev->stats.rx_errors++; | |
668 | + dev_kfree_skb(skb); | |
669 | + return; | |
670 | + } | |
671 | + } | |
672 | + if (skb->len < plen) { | |
673 | + brdev->stats.rx_errors++; | |
674 | + dev_kfree_skb(skb); /* dev_ not needed? */ | |
675 | + return; | |
676 | + } | |
677 | + | |
678 | +#ifdef FASTER_VERSION | |
679 | + /* FIXME: tcpdump shows that pointer to mac header is 2 bytes earlier, | |
680 | + than should be. What else should I set? */ | |
681 | + skb_pull(skb, plen); | |
682 | + skb->mac.raw = ((char *) (skb->data)) - ETH_HLEN; | |
683 | + skb->pkt_type = PACKET_HOST; | |
684 | +#ifdef CONFIG_BR2684_FAST_TRANS | |
685 | + skb->protocol = ((u16 *) skb->data)[-1]; | |
686 | +#else /* some protocols might require this: */ | |
687 | + skb->protocol = br_type_trans(skb, &brdev->net_dev); | |
688 | +#endif /* CONFIG_BR2684_FAST_TRANS */ | |
689 | +#else | |
690 | + skb_pull(skb, plen - ETH_HLEN); | |
691 | + skb->protocol = eth_type_trans(skb, &brdev->net_dev); | |
692 | +#endif /* FASTER_VERSION */ | |
693 | +#ifdef CONFIG_ATM_BR2684_IPFILTER | |
694 | + if (packet_fails_filter(skb->protocol, brvcc, skb)) { | |
695 | + brdev->stats.rx_dropped++; | |
696 | + dev_kfree_skb(skb); | |
697 | + return; | |
698 | + } | |
699 | +#endif /* CONFIG_ATM_BR2684_IPFILTER */ | |
700 | + skb->dev = &brdev->net_dev; | |
701 | + ATM_SKB(skb)->vcc = atmvcc; /* needed ? */ | |
702 | + DPRINTK("received packet's protocol: %x\n", ntohs(skb->protocol)); | |
703 | + skb_debug(skb); | |
704 | + if (!(brdev->net_dev.flags & IFF_UP)) { /* sigh, interface is down */ | |
705 | + brdev->stats.rx_dropped++; | |
706 | + dev_kfree_skb(skb); | |
707 | + return; | |
708 | + } | |
709 | + brdev->stats.rx_packets++; | |
710 | + brdev->stats.rx_bytes += skb->len; | |
711 | + netif_rx(skb); | |
712 | +} | |
713 | + | |
714 | +static int br2684_regvcc(struct atm_vcc *atmvcc, unsigned long arg) | |
715 | +{ | |
716 | +/* assign a vcc to a dev | |
717 | +Note: we do not have explicit unassign, but look at _push() | |
718 | +*/ | |
719 | + int err; | |
720 | + struct br2684_vcc *brvcc; | |
721 | + struct sk_buff_head copy; | |
722 | + struct sk_buff *skb; | |
723 | + struct br2684_dev *brdev; | |
724 | + struct atm_backend_br2684 be; | |
725 | + | |
726 | + MOD_INC_USE_COUNT; | |
727 | + if (copy_from_user(&be, (void *) arg, sizeof be)) { | |
728 | + MOD_DEC_USE_COUNT; | |
729 | + return -EFAULT; | |
730 | + } | |
731 | + write_lock_irq(&devs_lock); | |
732 | + brdev = br2684_find_dev(&be.ifspec); | |
733 | + if (brdev == NULL) { | |
734 | + printk(KERN_ERR | |
735 | + "br2684: tried to attach to non-existant device\n"); | |
736 | + err = -ENXIO; | |
737 | + goto error; | |
738 | + } | |
739 | + if (atmvcc->push == NULL) { | |
740 | + err = -EBADFD; | |
741 | + goto error; | |
742 | + } | |
743 | + if (!list_empty(&brdev->brvccs)) { /* Only 1 VCC/dev right now */ | |
744 | + err = -EEXIST; | |
745 | + goto error; | |
746 | + } | |
747 | + if (be.fcs_in != BR2684_FCSIN_NO || be.fcs_out != BR2684_FCSOUT_NO || | |
748 | + be.fcs_auto || be.has_vpiid || be.send_padding || (be.encaps != | |
749 | + BR2684_ENCAPS_VC && be.encaps != BR2684_ENCAPS_LLC) || | |
750 | + be.min_size != 0) { | |
751 | + err = -EINVAL; | |
752 | + goto error; | |
753 | + } | |
754 | + brvcc = kmalloc(sizeof(struct br2684_vcc), GFP_KERNEL); | |
755 | + if (!brvcc) { | |
756 | + err = -ENOMEM; | |
757 | + goto error; | |
758 | + } | |
759 | + memset(brvcc, 0, sizeof(struct br2684_vcc)); | |
760 | + DPRINTK("br2684_regvcc vcc=%p, encaps=%d, brvcc=%p\n", atmvcc, be.encaps, | |
761 | + brvcc); | |
762 | + if (list_empty(&brdev->brvccs) && !brdev->mac_was_set) { | |
763 | + unsigned char *esi = atmvcc->dev->esi; | |
764 | + if (esi[0] | esi[1] | esi[2] | esi[3] | esi[4] | esi[5]) | |
765 | + memcpy(brdev->net_dev.dev_addr, esi, | |
766 | + brdev->net_dev.addr_len); | |
767 | + else | |
768 | + brdev->net_dev.dev_addr[2] = 1; | |
769 | + } | |
770 | + list_add(&brvcc->brvccs, &brdev->brvccs); | |
771 | + write_unlock_irq(&devs_lock); | |
772 | + brvcc->brdev = brdev; | |
773 | + brvcc->atmvcc = atmvcc; | |
774 | + atmvcc->user_back = brvcc; | |
775 | + brvcc->encaps = (enum br2684_encaps) be.encaps; | |
776 | + brvcc->old_push = atmvcc->push; | |
777 | + barrier(); | |
778 | + atmvcc->push = br2684_push; | |
779 | + skb_queue_head_init(©); | |
780 | + skb_migrate(&atmvcc->recvq, ©); | |
781 | + while ((skb = skb_dequeue(©))) { | |
782 | + BRPRIV(skb->dev)->stats.rx_bytes -= skb->len; | |
783 | + BRPRIV(skb->dev)->stats.rx_packets--; | |
784 | + br2684_push(atmvcc, skb); | |
785 | + } | |
786 | + return 0; | |
787 | + error: | |
788 | + write_unlock_irq(&devs_lock); | |
789 | + MOD_DEC_USE_COUNT; | |
790 | + return err; | |
791 | +} | |
792 | + | |
793 | +static int br2684_create(unsigned long arg) | |
794 | +{ | |
795 | + int err; | |
796 | + struct br2684_dev *brdev; | |
797 | + struct atm_newif_br2684 ni; | |
798 | + | |
799 | + DPRINTK("br2684_create\n"); | |
800 | + /* | |
801 | + * We track module use by vcc's NOT the devices they're on. We're | |
802 | + * protected here against module death by the kernel_lock, but if | |
803 | + * we need to sleep we should make sure that the module doesn't | |
804 | + * disappear under us. | |
805 | + */ | |
806 | + MOD_INC_USE_COUNT; | |
807 | + if (copy_from_user(&ni, (void *) arg, sizeof ni)) { | |
808 | + MOD_DEC_USE_COUNT; | |
809 | + return -EFAULT; | |
810 | + } | |
811 | + if (ni.media != BR2684_MEDIA_ETHERNET || ni.mtu != 1500) { | |
812 | + MOD_DEC_USE_COUNT; | |
813 | + return -EINVAL; | |
814 | + } | |
815 | + if ((brdev = kmalloc(sizeof(struct br2684_dev), GFP_KERNEL)) == NULL) { | |
816 | + MOD_DEC_USE_COUNT; | |
817 | + return -ENOMEM; | |
818 | + } | |
819 | + memset(brdev, 0, sizeof(struct br2684_dev)); | |
820 | + INIT_LIST_HEAD(&brdev->brvccs); | |
821 | + | |
822 | + write_lock_irq(&devs_lock); | |
823 | + brdev->number = list_empty(&br2684_devs) ? 1 : | |
824 | + list_entry_brdev(br2684_devs.prev)->number + 1; | |
825 | + list_add_tail(&brdev->br2684_devs, &br2684_devs); | |
826 | + write_unlock_irq(&devs_lock); | |
827 | + | |
828 | + if (ni.ifname[0] != '\0') { | |
829 | + memcpy(brdev->net_dev.name, ni.ifname, | |
830 | + sizeof(brdev->net_dev.name)); | |
831 | + brdev->net_dev.name[sizeof(brdev->net_dev.name) - 1] = '\0'; | |
832 | + } else | |
833 | + sprintf(brdev->net_dev.name, "nas%d", brdev->number); | |
834 | + DPRINTK("registered netdev %s\n", brdev->net_dev.name); | |
835 | + ether_setup(&brdev->net_dev); | |
836 | + brdev->mac_was_set = 0; | |
837 | +#ifdef FASTER_VERSION | |
838 | + my_eth_header = brdev->net_dev.hard_header; | |
839 | + brdev->net_dev.hard_header = br2684_header; | |
840 | + my_eth_header_cache = brdev->net_dev.hard_header_cache; | |
841 | + brdev->net_dev.hard_header_cache = br2684_header_cache; | |
842 | + brdev->net_dev.hard_header_len = sizeof(llc_oui_pid_pad) + ETH_HLEN; /* 10 + 14 */ | |
843 | +#endif | |
844 | + my_eth_mac_addr = brdev->net_dev.set_mac_address; | |
845 | + brdev->net_dev.set_mac_address = br2684_mac_addr; | |
846 | + brdev->net_dev.hard_start_xmit = br2684_start_xmit; | |
847 | + brdev->net_dev.get_stats = br2684_get_stats; | |
848 | + | |
849 | + /* open, stop, do_ioctl ? */ | |
850 | + err = register_netdev(&brdev->net_dev); | |
851 | + MOD_DEC_USE_COUNT; | |
852 | + if (err < 0) { | |
853 | + printk(KERN_ERR "br2684_create: register_netdev failed\n"); | |
854 | + write_lock_irq(&devs_lock); | |
855 | + list_del(&brdev->br2684_devs); | |
856 | + write_unlock_irq(&devs_lock); | |
857 | + kfree(brdev); | |
858 | + return err; | |
859 | + } | |
860 | + return 0; | |
861 | +} | |
862 | + | |
863 | +/* | |
864 | + * This handles ioctls actually performed on our vcc - we must return | |
865 | + * -ENOIOCTLCMD for any unrecognized ioctl | |
866 | + */ | |
867 | +static int br2684_ioctl(struct atm_vcc *atmvcc, unsigned int cmd, | |
868 | + unsigned long arg) | |
869 | +{ | |
870 | + int err; | |
871 | + switch(cmd) { | |
872 | + case ATM_SETBACKEND: | |
873 | + case ATM_NEWBACKENDIF: { | |
874 | + atm_backend_t b; | |
875 | + MOD_INC_USE_COUNT; | |
876 | + err = get_user(b, (atm_backend_t *) arg); | |
877 | + MOD_DEC_USE_COUNT; | |
878 | + if (err) | |
879 | + return -EFAULT; | |
880 | + if (b != ATM_BACKEND_BR_2684) | |
881 | + return -ENOIOCTLCMD; | |
882 | + if (!capable(CAP_NET_ADMIN)) | |
883 | + return -EPERM; | |
884 | + if (cmd == ATM_SETBACKEND) | |
885 | + return br2684_regvcc(atmvcc, arg); | |
886 | + else | |
887 | + return br2684_create(arg); | |
888 | + } | |
889 | +#ifdef CONFIG_ATM_BR2684_IPFILTER | |
890 | + case BR2684_SETFILT: | |
891 | + if (atmvcc->push != br2684_push) | |
892 | + return -ENOIOCTLCMD; | |
893 | + if (!capable(CAP_NET_ADMIN)) | |
894 | + return -EPERM; | |
895 | + MOD_INC_USE_COUNT; | |
896 | + err = br2684_setfilt(atmvcc, arg); | |
897 | + MOD_DEC_USE_COUNT; | |
898 | + return err; | |
899 | +#endif /* CONFIG_ATM_BR2684_IPFILTER */ | |
900 | + } | |
901 | + return -ENOIOCTLCMD; | |
902 | +} | |
903 | + | |
904 | +/* Never put more than 256 bytes in at once */ | |
905 | +static int br2684_proc_engine(loff_t pos, char *buf) | |
906 | +{ | |
907 | + struct list_head *lhd, *lhc; | |
908 | + struct br2684_dev *brdev; | |
909 | + struct br2684_vcc *brvcc; | |
910 | + list_for_each(lhd, &br2684_devs) { | |
911 | + brdev = list_entry_brdev(lhd); | |
912 | + if (pos-- == 0) | |
913 | + return sprintf(buf, "dev %.16s: num=%d, mac=%02X:%02X:" | |
914 | + "%02X:%02X:%02X:%02X (%s)\n", brdev->net_dev.name, | |
915 | + brdev->number, | |
916 | + brdev->net_dev.dev_addr[0], | |
917 | + brdev->net_dev.dev_addr[1], | |
918 | + brdev->net_dev.dev_addr[2], | |
919 | + brdev->net_dev.dev_addr[3], | |
920 | + brdev->net_dev.dev_addr[4], | |
921 | + brdev->net_dev.dev_addr[5], | |
922 | + brdev->mac_was_set ? "set" : "auto"); | |
923 | + list_for_each(lhc, &brdev->brvccs) { | |
924 | + brvcc = list_entry_brvcc(lhc); | |
925 | + if (pos-- == 0) | |
926 | + return sprintf(buf, " vcc %d.%d.%d: encaps=%s" | |
927 | +#ifndef FASTER_VERSION | |
928 | + ", failed copies %u/%u" | |
929 | +#endif /* FASTER_VERSION */ | |
930 | + "\n", brvcc->atmvcc->dev->number, | |
931 | + brvcc->atmvcc->vpi, brvcc->atmvcc->vci, | |
932 | + (brvcc->encaps == e_llc) ? "LLC" : "VC" | |
933 | +#ifndef FASTER_VERSION | |
934 | + , brvcc->copies_failed | |
935 | + , brvcc->copies_needed | |
936 | +#endif /* FASTER_VERSION */ | |
937 | + ); | |
938 | +#ifdef CONFIG_ATM_BR2684_IPFILTER | |
939 | +#define b1(var, byte) ((u8 *) &brvcc->filter.var)[byte] | |
940 | +#define bs(var) b1(var, 0), b1(var, 1), b1(var, 2), b1(var, 3) | |
941 | + if (brvcc->filter.netmask != 0 && pos-- == 0) | |
942 | + return sprintf(buf, " filter=%d.%d.%d.%d/" | |
943 | + "%d.%d.%d.%d\n", bs(prefix), bs(netmask)); | |
944 | +#undef bs | |
945 | +#undef b1 | |
946 | +#endif /* CONFIG_ATM_BR2684_IPFILTER */ | |
947 | + } | |
948 | + } | |
949 | + return 0; | |
950 | +} | |
951 | + | |
952 | +static ssize_t br2684_proc_read(struct file *file, char *buf, size_t count, | |
953 | + loff_t *pos) | |
954 | +{ | |
955 | + unsigned long page; | |
956 | + int len = 0, x, left; | |
957 | + page = get_free_page(GFP_KERNEL); | |
958 | + if (!page) | |
959 | + return -ENOMEM; | |
960 | + left = PAGE_SIZE - 256; | |
961 | + if (count < left) | |
962 | + left = count; | |
963 | + read_lock(&devs_lock); | |
964 | + for (;;) { | |
965 | + x = br2684_proc_engine(*pos, &((char *) page)[len]); | |
966 | + if (x == 0) | |
967 | + break; | |
968 | + if (x > left) | |
969 | + /* | |
970 | + * This should only happen if the user passed in | |
971 | + * a "count" too small for even one line | |
972 | + */ | |
973 | + x = -EINVAL; | |
974 | + if (x < 0) { | |
975 | + len = x; | |
976 | + break; | |
977 | + } | |
978 | + len += x; | |
979 | + left -= x; | |
980 | + (*pos)++; | |
981 | + if (left < 256) | |
982 | + break; | |
983 | + } | |
984 | + read_unlock(&devs_lock); | |
985 | + if (len > 0 && copy_to_user(buf, (char *) page, len)) | |
986 | + len = -EFAULT; | |
987 | + free_page(page); | |
988 | + return len; | |
989 | +} | |
990 | + | |
991 | +static struct file_operations br2684_proc_operations = { | |
992 | + read: br2684_proc_read, | |
993 | +}; | |
994 | + | |
995 | +extern struct proc_dir_entry *atm_proc_root; /* from proc.c */ | |
996 | + | |
997 | +extern int (*br2684_ioctl_hook)(struct atm_vcc *, unsigned int, unsigned long); | |
998 | + | |
999 | +/* the following avoids some spurious warnings from the compiler */ | |
1000 | +#define UNUSED __attribute__((unused)) | |
1001 | + | |
1002 | +static int __init UNUSED br2684_init(void) | |
1003 | +{ | |
1004 | + struct proc_dir_entry *p; | |
1005 | + if ((p = create_proc_entry("br2684", 0, atm_proc_root)) == NULL) | |
1006 | + return -ENOMEM; | |
1007 | + p->proc_fops = &br2684_proc_operations; | |
1008 | + br2684_ioctl_hook = br2684_ioctl; | |
1009 | + return 0; | |
1010 | +} | |
1011 | + | |
1012 | +static void __exit UNUSED br2684_exit(void) | |
1013 | +{ | |
1014 | + struct br2684_dev *brdev; | |
1015 | + br2684_ioctl_hook = NULL; | |
1016 | + remove_proc_entry("br2684", atm_proc_root); | |
1017 | + while (!list_empty(&br2684_devs)) { | |
1018 | + brdev = list_entry_brdev(br2684_devs.next); | |
1019 | + unregister_netdev(&brdev->net_dev); | |
1020 | + list_del(&brdev->br2684_devs); | |
1021 | + kfree(brdev); | |
1022 | + } | |
1023 | +} | |
1024 | + | |
1025 | +module_init(br2684_init); | |
1026 | +module_exit(br2684_exit); | |
1027 | + | |
1028 | +MODULE_AUTHOR("Marcell GAL"); | |
1029 | +MODULE_DESCRIPTION("RFC2684 bridged protocols over ATM/AAL5"); | |
1030 | diff -urN linux.orig/net/atm/common.c linux/net/atm/common.c | |
1031 | --- linux.orig/net/atm/common.c Sat Apr 21 18:04:58 2001 | |
1032 | +++ linux/net/atm/common.c Sat Apr 21 18:06:09 2001 | |
1033 | @@ -63,6 +63,13 @@ | |
1034 | EXPORT_SYMBOL(pppoatm_ioctl_hook); | |
1035 | #endif | |
1036 | ||
1037 | +#if defined(CONFIG_ATM_BR2684) || defined(CONFIG_ATM_BR2684_MODULE) | |
1038 | +int (*br2684_ioctl_hook)(struct atm_vcc *, unsigned int, unsigned long); | |
1039 | +#endif | |
1040 | +#ifdef CONFIG_ATM_BR2684_MODULE | |
1041 | +EXPORT_SYMBOL(br2684_ioctl_hook); | |
1042 | +#endif | |
1043 | + | |
1044 | #include "resources.h" /* atm_find_dev */ | |
1045 | #include "common.h" /* prototypes */ | |
1046 | #include "protocols.h" /* atm_init_<transport> */ | |
1047 | @@ -774,6 +786,13 @@ | |
1048 | goto done; | |
1049 | } | |
1050 | #endif | |
1051 | +#if defined(CONFIG_ATM_BR2684) || defined(CONFIG_ATM_BR2684_MODULE) | |
1052 | + if (br2684_ioctl_hook) { | |
1053 | + ret_val = br2684_ioctl_hook(vcc, cmd, arg); | |
1054 | + if (ret_val != -ENOIOCTLCMD) | |
1055 | + goto done; | |
1056 | + } | |
1057 | +#endif | |
1058 | if (get_user(buf,&((struct atmif_sioc *) arg)->arg)) { | |
1059 | ret_val = -EFAULT; | |
1060 | goto done; |