]> git.pld-linux.org Git - packages/kernel.git/blob - br2684-against2.4.10.diff
- this patch fix twice EXPORT_SYMBOL(br_ioctl_hook); in kernel-source net/netsyms.c
[packages/kernel.git] / br2684-against2.4.10.diff
1 diff -urN linux.orig/Documentation/Configure.help linux/Documentation/Configure.help
2 --- linux.orig/Documentation/Configure.help     Sat Apr 21 18:05:00 2001
3 +++ linux/Documentation/Configure.help  Sat Apr 21 18:06:09 2001
4 @@ -5328,6 +5328,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 @@ -7558,6 +7571,13 @@
25    This driver requires a specially patched pppd daemon.  The patch to
26    pppd, along with binaries of a patched pppd package can be found at:
27    http://www.shoshin.uwaterloo.ca/~mostrows
28 +
29 +PPP over ATM (EXPERIMENTAL)
30 +CONFIG_PPPOATM
31 +  PPP over ATM is one of several protocols used over DSL lines.
32 +  If you are connecting to a DSL line using an internal ATM or
33 +  DSL adaptor (as opposed to an ethernet card) then there is
34 +  a good possibility you will need this protocol.
35   
36  Wireless LAN (non-hamradio)
37  CONFIG_NET_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/atm.h linux/include/linux/atm.h
83 --- linux.orig/include/linux/atm.h      Tue Mar 27 01:49:24 2001
84 +++ linux/include/linux/atm.h   Sat Apr 21 18:06:09 2001
85 @@ -235,6 +235,7 @@
86      void *arg;
87  };
88  
89 +typedef unsigned short atm_backend_t;
90  
91  #ifdef __KERNEL__
92  
93 diff -urN linux.orig/include/linux/atmbr2684.h linux/include/linux/atmbr2684.h
94 --- linux.orig/include/linux/atmbr2684.h        Thu Jan  1 01:00:00 1970
95 +++ linux/include/linux/atmbr2684.h     Sat Apr 21 18:06:09 2001
96 @@ -0,0 +1,101 @@
97 +#ifndef _LINUX_ATMBR2684_H
98 +#define _LINUX_ATMBR2684_H
99 +
100 +#include <linux/atm.h>
101 +#include <linux/if.h>          /* For IFNAMSIZ */
102 +
103 +/*
104 + * Type of media we're bridging (ethernet, token ring, etc)  Currently only
105 + * ethernet is supported
106 + */
107 +#define BR2684_MEDIA_ETHERNET  (0)     /* 802.3 */
108 +#define BR2684_MEDIA_802_4     (1)     /* 802.4 */
109 +#define BR2684_MEDIA_TR                (2)     /* 802.5 - token ring */
110 +#define BR2684_MEDIA_FDDI      (3)
111 +#define BR2684_MEDIA_802_6     (4)     /* 802.6 */
112 +
113 +/*
114 + * Is there FCS inbound on this VC?  This currently isn't supported.
115 + */
116 +#define BR2684_FCSIN_NO                (0)
117 +#define BR2684_FCSIN_IGNORE    (1)
118 +#define BR2684_FCSIN_VERIFY    (2)
119 +
120 +/*
121 + * Is there FCS outbound on this VC?  This currently isn't supported.
122 + */
123 +#define BR2684_FCSOUT_NO       (0)
124 +#define BR2684_FCSOUT_SENDZERO (1)
125 +#define BR2684_FCSOUT_GENERATE (2)
126 +
127 +/*
128 + * Does this VC include LLC encapsulation?
129 + */
130 +#define BR2684_ENCAPS_VC       (0)     /* VC-mux */
131 +#define BR2684_ENCAPS_LLC      (1)
132 +#define BR2684_ENCAPS_AUTODETECT (2)   /* Unsuported */
133 +
134 +/*
135 + * This is for the ATM_NEWBACKENDIF call - these are like socket families:
136 + * the first element of the structure is the backend number and the rest
137 + * is per-backend specific
138 + */
139 +struct atm_newif_br2684 {
140 +       atm_backend_t   backend_num;    /* ATM_BACKEND_BR2684 */
141 +       int             media;          /* BR2684_MEDIA_* */
142 +       char            ifname[IFNAMSIZ];
143 +       int             mtu;
144 +};
145 +
146 +/*
147 + * This structure is used to specify a br2684 interface - either by a
148 + * positive integer (returned by ATM_NEWBACKENDIF) or the interfaces name
149 + */
150 +#define BR2684_FIND_BYNOTHING  (0)
151 +#define BR2684_FIND_BYNUM      (1)
152 +#define BR2684_FIND_BYIFNAME   (2)
153 +struct br2684_if_spec {
154 +       int method;                     /* BR2684_FIND_* */
155 +       union {
156 +               char            ifname[IFNAMSIZ];
157 +               int             devnum;
158 +       } spec;
159 +};
160 +
161 +/*
162 + * This is for the ATM_SETBACKEND call - these are like socket families:
163 + * the first element of the structure is the backend number and the rest
164 + * is per-backend specific
165 + */
166 +struct atm_backend_br2684 {
167 +       atm_backend_t   backend_num;    /* ATM_BACKEND_BR2684 */
168 +       struct br2684_if_spec ifspec;
169 +       int     fcs_in;         /* BR2684_FCSIN_* */
170 +       int     fcs_out;        /* BR2684_FCSOUT_* */
171 +       int     fcs_auto;       /* 1: fcs_{in,out} disabled if no FCS rx'ed */
172 +       int     encaps;         /* BR2684_ENCAPS_* */
173 +       int     has_vpiid;      /* 1: use vpn_id - Unsupported */
174 +       __u8    vpn_id[7];
175 +       int     send_padding;   /* unsupported */
176 +       int     min_size;       /* we will pad smaller packets than this */
177 +};
178 +
179 +/*
180 + * The BR2684_SETFILT ioctl is an experimental mechanism for folks
181 + * terminating a large number of IP-only vcc's.  When netfilter allows
182 + * efficient per-if in/out filters, this support will be removed
183 + */
184 +struct br2684_filter {
185 +       __u32   prefix;         /* network byte order */
186 +       __u32   netmask;        /* 0 = disable filter */
187 +};
188 +
189 +struct br2684_filter_set {
190 +       struct br2684_if_spec ifspec;
191 +       struct br2684_filter filter;
192 +};
193 +
194 +#define BR2684_SETFILT _IOW( 'a', ATMIOC_BACKEND + 0, \
195 +                               struct br2684_filter_set)
196 +
197 +#endif /* _LINUX_ATMBR2684_H */
198 diff -urN linux.orig/include/linux/atmdev.h linux/include/linux/atmdev.h
199 --- linux.orig/include/linux/atmdev.h   Tue Mar 27 01:50:03 2001
200 +++ linux/include/linux/atmdev.h        Sat Apr 21 18:06:09 2001
201 @@ -87,6 +87,20 @@
202  #define ATM_SETSC      _IOW('a',ATMIOC_SPECIAL+1,int)
203                                         /* enable or disable single-copy */
204  
205 +#define ATM_SETBACKEND _IOW('a',ATMIOC_SPECIAL+2,atm_backend_t)
206 +                                       /* set backend handler */
207 +#define ATM_NEWBACKENDIF _IOW('a',ATMIOC_SPECIAL+3,atm_backend_t)
208 +                                       /* use backend to make new if */
209 +
210 +/*
211 + * These are backend handkers that can be set via the ATM_SETBACKEND call
212 + * above.  In the future we may support dynamic loading of these - for now,
213 + * they're just being used to share the ATMIOC_BACKEND ioctls
214 + */
215 +#define ATM_BACKEND_RAW                0
216 +#define ATM_BACKEND_PPP                1       /* PPPoATM - RFC2364 */
217 +#define ATM_BACKEND_BR2684     2       /* Bridged RFC1483/2684 */
218 +
219  /* for ATM_GETTYPE */
220  #define ATM_ITFTYP_LEN 8       /* maximum length of interface type name */
221  
222 diff -urN linux.orig/include/linux/atmioc.h linux/include/linux/atmioc.h
223 --- linux.orig/include/linux/atmioc.h   Wed Feb  9 03:23:13 2000
224 +++ linux/include/linux/atmioc.h        Sat Apr 21 18:06:09 2001
225 @@ -27,7 +27,9 @@
226  #define ATMIOC_SARPRV_END 0x7f
227  #define ATMIOC_ITF       0x80 /* Interface ioctls, globally unique */
228  #define ATMIOC_ITF_END   0x8f
229 -/* 0x90-0xbf: Reserved for future use */
230 +#define ATMIOC_BACKEND   0x90 /* ATM generic backend ioctls, u. per backend */
231 +#define ATMIOC_BACKEND_END 0xaf
232 +/* 0xb0-0xbf: Reserved for future use */
233  #define ATMIOC_AREQUIPA          0xc0 /* Application requested IP over ATM, glob. u. */
234  #define ATMIOC_LANE      0xd0 /* LAN Emulation, globally unique */
235  #define ATMIOC_MPOA       0xd8 /* MPOA, globally unique */
236 diff -urN linux.orig/include/linux/atmppp.h linux/include/linux/atmppp.h
237 --- linux.orig/include/linux/atmppp.h   Thu Jan  1 01:00:00 1970
238 +++ linux/include/linux/atmppp.h        Sat Apr 21 18:06:09 2001
239 @@ -0,0 +1,24 @@
240 +/* atmppp.h - RFC2364 PPPoATM */
241 +
242 +/* Written 2000 by Mitchell Blank Jr */
243 +
244 +#ifndef _LINUX_ATMPPP_H
245 +#define _LINUX_ATMPPP_H
246 +
247 +#include <linux/atm.h>
248 +
249 +#define PPPOATM_ENCAPS_AUTODETECT      (0)
250 +#define PPPOATM_ENCAPS_VC              (1)
251 +#define PPPOATM_ENCAPS_LLC             (2)
252 +
253 +/*
254 + * This is for the ATM_SETBACKEND call - these are like socket families:
255 + * the first element of the structure is the backend number and the rest
256 + * is per-backend specific
257 + */
258 +struct atm_backend_ppp {
259 +       atm_backend_t   backend_num;    /* ATM_BACKEND_PPP */
260 +       int             encaps;         /* PPPOATM_ENCAPS_* */
261 +};
262 +
263 +#endif /* _LINUX_ATMPPP_H */
264 diff -urN linux.orig/net/Config.in linux/net/Config.in
265 --- linux.orig/net/Config.in    Sat Apr 21 18:05:00 2001
266 +++ linux/net/Config.in Sat Apr 21 18:06:09 2001
267 @@ -45,6 +45,10 @@
268        if [ "$CONFIG_INET" = "y" -a "$CONFIG_ATM_LANE" != "n" ]; then
269          tristate '    Multi-Protocol Over ATM (MPOA) support' CONFIG_ATM_MPOA
270        fi
271 +      tristate '  RFC1483/2684 Bridged protocols' CONFIG_ATM_BR2684
272 +      if [ "$CONFIG_ATM_BR2684" != "n" ]; then
273 +            bool '    Per-VC IP filter kludge' CONFIG_ATM_BR2684_IPFILTER
274 +      fi
275     fi
276  fi
277  
278 diff -urN linux.orig/net/atm/Makefile linux/net/atm/Makefile
279 --- linux.orig/net/atm/Makefile Tue Mar 27 01:36:30 2001
280 +++ linux/net/atm/Makefile      Sat Apr 21 18:06:09 2001
281 @@ -21,6 +21,15 @@
282  NEED_IPCOM = ipcommon.o
283  endif
284  
285 +ifeq ($(CONFIG_ATM_BR2684),y)
286 +  NEED_IPCOM = ipcommon.o
287 +else
288 +  ifeq ($(CONFIG_ATM_BR2684),m)
289 +       NEED_IPCOM = ipcommon.o
290 +  endif
291 +endif
292 +obj-$(CONFIG_ATM_BR2684) += br2684.o
293 +
294  ifeq ($(CONFIG_NET_SCH_ATM),y)
295  NEED_IPCOM = ipcommon.o
296  endif
297 @@ -33,6 +42,7 @@
298  
299  obj-$(CONFIG_ATM_LANE) += lec.o
300  obj-$(CONFIG_ATM_MPOA) += mpoa.o
301 +obj-$(CONFIG_PPPOATM)  += pppoatm.o
302  
303  include $(TOPDIR)/Rules.make
304  
305 diff -urN linux.orig/net/atm/br2684.c linux/net/atm/br2684.c
306 --- linux.orig/net/atm/br2684.c Thu Jan  1 01:00:00 1970
307 +++ linux/net/atm/br2684.c      Sat Apr 21 18:06:09 2001
308 @@ -0,0 +1,794 @@
309 +/*
310 +Experimental ethernet netdevice using ATM AAL5 as underlying carrier
311 +(RFC1483 obsoleted by RFC2684) for Linux 2.4
312 +Author: Marcell GAL, 2000, XDSL Ltd, Hungary
313 +*/
314 +
315 +#include <linux/module.h>
316 +#include <linux/config.h>
317 +#include <linux/init.h>
318 +#include <linux/kernel.h>
319 +#include <linux/list.h>
320 +#include <asm/uaccess.h>
321 +#include <linux/netdevice.h>
322 +#include <linux/skbuff.h>
323 +#include <linux/etherdevice.h>
324 +#include <net/arp.h>
325 +#include <linux/rtnetlink.h>
326 +#include <linux/atmbr2684.h>
327 +
328 +#include "ipcommon.h"
329 +
330 +/*
331 + * Define this to use a version of the code which interacts with the higher
332 + * layers in a more intellegent way, by always reserving enough space for
333 + * our header at the begining of the packet.  However, there may still be
334 + * some problems with programs like tcpdump.  In 2.5 we'll sort out what
335 + * we need to do to get this perfect.  For now we just will copy the packet
336 + * if we need space for the header
337 + */
338 +/* #define FASTER_VERSION */
339 +
340 +#ifdef DEBUG
341 +#define DPRINTK(format, args...) printk(KERN_DEBUG "br2684: " format, ##args)
342 +#else
343 +#define DPRINTK(format, args...)
344 +#endif
345 +
346 +#ifdef SKB_DEBUG
347 +static void skb_debug(const struct sk_buff *skb)
348 +{
349 +#define NUM2PRINT 50
350 +       char buf[NUM2PRINT * 3 + 1];    /* 3 chars per byte */
351 +       int i = 0;
352 +       for (i = 0; i < skb->len && i < NUM2PRINT; i++) {
353 +               sprintf(buf + i * 3, "%2.2x ", 0xff & skb->data[i]);
354 +       }
355 +       printk(KERN_DEBUG "br2684: skb: %s\n", buf);
356 +}
357 +#else
358 +#define skb_debug(skb) do {} while (0)
359 +#endif
360 +
361 +static unsigned char llc_oui_pid_pad[] =
362 +    { 0xAA, 0xAA, 0x03, 0x00, 0x80, 0xC2, 0x00, 0x07, 0x00, 0x00 };
363 +#define PADLEN (2)
364 +
365 +enum br2684_encaps {
366 +       e_vc  = BR2684_ENCAPS_VC,
367 +       e_llc = BR2684_ENCAPS_LLC,
368 +};
369 +
370 +struct br2684_vcc {
371 +       struct atm_vcc  *atmvcc;
372 +       struct br2684_dev *brdev;
373 +       /* keep old push,pop functions for chaining */
374 +       void (*old_push)(struct atm_vcc *vcc,struct sk_buff *skb);
375 +       /* void (*old_pop)(struct atm_vcc *vcc,struct sk_buff *skb); */
376 +       enum br2684_encaps encaps;
377 +       struct list_head brvccs;
378 +#ifdef CONFIG_ATM_BR2684_IPFILTER
379 +       struct br2684_filter filter;
380 +#endif /* CONFIG_ATM_BR2684_IPFILTER */
381 +#ifndef FASTER_VERSION
382 +       unsigned copies_needed, copies_failed;
383 +#endif /* FASTER_VERSION */
384 +};
385 +
386 +struct br2684_dev {
387 +       struct net_device net_dev;
388 +       struct list_head br2684_devs;
389 +       int number;
390 +       struct list_head brvccs; /* one device <=> one vcc (before xmas) */
391 +       struct net_device_stats stats;
392 +       int mac_was_set;
393 +};
394 +
395 +/*
396 + * This lock should be held for writing any time the list of devices or
397 + * their attached vcc's could be altered.  It should be held for reading
398 + * any time these are being queried.  Note that we sometimes need to
399 + * do read-locking under interrupt context, so write locking must block
400 + * the current CPU's interrupts
401 + */
402 +static rwlock_t devs_lock = RW_LOCK_UNLOCKED;
403 +
404 +static LIST_HEAD(br2684_devs);
405 +
406 +static inline struct br2684_dev *BRPRIV(const struct net_device *net_dev)
407 +{
408 +       return (struct br2684_dev *) ((char *) (net_dev) -
409 +           (unsigned long) (&((struct br2684_dev *) 0)->net_dev));
410 +}
411 +
412 +static inline struct br2684_dev *list_entry_brdev(const struct list_head *le)
413 +{
414 +       return list_entry(le, struct br2684_dev, br2684_devs);
415 +}
416 +
417 +static inline struct br2684_vcc *BR2684_VCC(const struct atm_vcc *atmvcc)
418 +{
419 +       return (struct br2684_vcc *) (atmvcc->user_back);
420 +}
421 +
422 +static inline struct br2684_vcc *list_entry_brvcc(const struct list_head *le)
423 +{
424 +       return list_entry(le, struct br2684_vcc, brvccs);
425 +}
426 +
427 +/* Caller should hold read_lock(&devs_lock) */
428 +static struct br2684_dev *br2684_find_dev(const struct br2684_if_spec *s)
429 +{
430 +       struct list_head *lh;
431 +       struct br2684_dev *brdev;
432 +       switch (s->method) {
433 +       case BR2684_FIND_BYNUM:
434 +               list_for_each(lh, &br2684_devs) {
435 +                       brdev = list_entry_brdev(lh);
436 +                       if (brdev->number == s->spec.devnum)
437 +                               return brdev;
438 +               }
439 +               break;
440 +       case BR2684_FIND_BYIFNAME:
441 +               list_for_each(lh, &br2684_devs) {
442 +                       brdev = list_entry_brdev(lh);
443 +                       if (!strncmp(brdev->net_dev.name, s->spec.ifname,
444 +                           sizeof brdev->net_dev.name))
445 +                               return brdev;
446 +               }
447 +               break;
448 +       }
449 +       return NULL;
450 +}
451 +
452 +/*
453 + * Send a packet out a particular vcc.  Not to useful right now, but paves
454 + * the way for multiple vcc's per itf.  Returns true if we can send,
455 + * otherwise false
456 + */
457 +static int br2684_xmit_vcc(struct sk_buff *skb, struct br2684_dev *brdev,
458 +       struct br2684_vcc *brvcc)
459 +{
460 +       struct atm_vcc *atmvcc;
461 +#ifdef FASTER_VERSION
462 +       if (brvcc->encaps == e_llc)
463 +               memcpy(skb_push(skb, 8), llc_oui_pid_pad, 8);
464 +       /* last 2 bytes of llc_oui_pid_pad are managed by header routines;
465 +          yes, you got it: 8 + 2 = sizeof(llc_oui_pid_pad)
466 +        */
467 +#else
468 +       int minheadroom = (brvcc->encaps == e_llc) ? 10 : 2;
469 +       if (skb_headroom(skb) < minheadroom) {
470 +               struct sk_buff *skb2 = skb_realloc_headroom(skb, minheadroom);
471 +               brvcc->copies_needed++;
472 +               dev_kfree_skb(skb);
473 +               if (skb2 == NULL) {
474 +                       brvcc->copies_failed++;
475 +                       return 0;
476 +               }
477 +               skb = skb2;
478 +       }
479 +       skb_push(skb, minheadroom);
480 +       if (brvcc->encaps == e_llc)
481 +               memcpy(skb->data, llc_oui_pid_pad, 10);
482 +       else
483 +               memset(skb->data, 0, 2);
484 +#endif /* FASTER_VERSION */
485 +       skb_debug(skb);
486 +
487 +       ATM_SKB(skb)->vcc = atmvcc = brvcc->atmvcc;
488 +       DPRINTK("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, atmvcc, atmvcc->dev);
489 +       if (!atm_may_send(atmvcc, skb->truesize)) {
490 +               /* we free this here for now, because we cannot know in a higher 
491 +                       layer whether the skb point it supplied wasn't freed yet.
492 +                       now, it always is.
493 +               */
494 +               dev_kfree_skb(skb);
495 +               return 0;
496 +               }
497 +       atomic_add(skb->truesize, &atmvcc->tx_inuse);
498 +       ATM_SKB(skb)->iovcnt = 0;
499 +       ATM_SKB(skb)->atm_options = atmvcc->atm_options;
500 +       brdev->stats.tx_packets++;
501 +       brdev->stats.tx_bytes += skb->len;
502 +       atmvcc->send(atmvcc, skb);
503 +       return 1;
504 +}
505 +
506 +static inline struct br2684_vcc *pick_outgoing_vcc(struct sk_buff *skb,
507 +       struct br2684_dev *brdev)
508 +{
509 +       return list_empty(&brdev->brvccs) ? NULL :
510 +           list_entry_brvcc(brdev->brvccs.next); /* 1 vcc/dev right now */
511 +}
512 +
513 +static int br2684_start_xmit(struct sk_buff *skb, struct net_device *dev)
514 +{
515 +       struct br2684_dev *brdev = BRPRIV(dev);
516 +       struct br2684_vcc *brvcc;
517 +
518 +       DPRINTK("br2684_start_xmit, skb->dst=%p\n", skb->dst);
519 +       read_lock(&devs_lock);
520 +       brvcc = pick_outgoing_vcc(skb, brdev);
521 +       if (brvcc == NULL) {
522 +               DPRINTK("no vcc attached to dev %s\n", dev->name);
523 +               brdev->stats.tx_errors++;
524 +               brdev->stats.tx_carrier_errors++;
525 +               /* netif_stop_queue(dev); */
526 +               dev_kfree_skb(skb);
527 +               read_unlock(&devs_lock);
528 +               return -EUNATCH;
529 +       }
530 +       if (!br2684_xmit_vcc(skb, brdev, brvcc)) {
531 +               /*
532 +                * We should probably use netif_*_queue() here, but that
533 +                * involves added complication.  We need to walk before
534 +                * we can run
535 +                */
536 +               /* don't free here! this pointer might be no longer valid!
537 +               dev_kfree_skb(skb);
538 +               */
539 +               brdev->stats.tx_errors++;
540 +               brdev->stats.tx_fifo_errors++;
541 +       }
542 +       read_unlock(&devs_lock);
543 +       return 0;
544 +}
545 +
546 +static struct net_device_stats *br2684_get_stats(struct net_device *dev)
547 +{
548 +       DPRINTK("br2684_get_stats\n");
549 +       return &BRPRIV(dev)->stats;
550 +}
551 +
552 +#ifdef FASTER_VERSION
553 +/*
554 + * These mirror eth_header and eth_header_cache.  They are not usually
555 + * exported for use in modules, so we grab them from net_device
556 + * after ether_setup() is done with it.  Bit of a hack.
557 + */
558 +static int (*my_eth_header)(struct sk_buff *, struct net_device *,
559 +       unsigned short, void *, void *, unsigned);
560 +static int (*my_eth_header_cache)(struct neighbour *, struct hh_cache *);
561 +
562 +static int
563 +br2684_header(struct sk_buff *skb, struct net_device *dev,
564 +             unsigned short type, void *daddr, void *saddr, unsigned len)
565 +{
566 +       u16 *pad_before_eth;
567 +       int t = my_eth_header(skb, dev, type, daddr, saddr, len);
568 +       if (t > 0) {
569 +               pad_before_eth = (u16 *) skb_push(skb, 2);
570 +               *pad_before_eth = 0;
571 +               return dev->hard_header_len;    /* or return 16; ? */
572 +       } else
573 +               return t;
574 +}
575 +
576 +static int
577 +br2684_header_cache(struct neighbour *neigh, struct hh_cache *hh)
578 +{
579 +/* hh_data is 16 bytes long. if encaps is ether-llc we need 24, so
580 +xmit will add the additional header part in that case */
581 +       u16 *pad_before_eth = (u16 *)(hh->hh_data);
582 +       int t = my_eth_header_cache(neigh, hh);
583 +       DPRINTK("br2684_header_cache, neigh=%p, hh_cache=%p\n", neigh, hh);
584 +       if (t < 0)
585 +               return t;
586 +       else {
587 +               *pad_before_eth = 0;
588 +               hh->hh_len = PADLEN + ETH_HLEN;
589 +       }
590 +       return 0;
591 +}
592 +
593 +/*
594 + * This is similar to eth_type_trans, which cannot be used because of
595 + * our dev->hard_header_len
596 + */
597 +static inline unsigned short br_type_trans(struct sk_buff *skb,
598 +                                              struct net_device *dev)
599 +{
600 +       struct ethhdr *eth;
601 +       unsigned char *rawp;
602 +       eth = skb->mac.ethernet;
603 +
604 +       if (*eth->h_dest & 1) {
605 +               if (memcmp(eth->h_dest, dev->broadcast, ETH_ALEN) == 0)
606 +                       skb->pkt_type = PACKET_BROADCAST;
607 +               else
608 +                       skb->pkt_type = PACKET_MULTICAST;
609 +       }
610 +
611 +       else if (memcmp(eth->h_dest, dev->dev_addr, ETH_ALEN))
612 +               skb->pkt_type = PACKET_OTHERHOST;
613 +
614 +       if (ntohs(eth->h_proto) >= 1536)
615 +               return eth->h_proto;
616 +
617 +       rawp = skb->data;
618 +
619 +       /*
620 +        * This is a magic hack to spot IPX packets. Older Novell breaks
621 +        * the protocol design and runs IPX over 802.3 without an 802.2 LLC
622 +        * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
623 +        * won't work for fault tolerant netware but does for the rest.
624 +        */
625 +       if (*(unsigned short *) rawp == 0xFFFF)
626 +               return htons(ETH_P_802_3);
627 +
628 +       /*
629 +        * Real 802.2 LLC
630 +        */
631 +       return htons(ETH_P_802_2);
632 +}
633 +#endif /* FASTER_VERSION */
634 +
635 +/*
636 + * We remember when the MAC gets set, so we don't override it later with
637 + * the ESI of the ATM card of the first VC
638 + */
639 +static int (*my_eth_mac_addr)(struct net_device *, void *);
640 +static int br2684_mac_addr(struct net_device *dev, void *p)
641 +{
642 +       int err = my_eth_mac_addr(dev, p);
643 +       if (!err)
644 +               BRPRIV(dev)->mac_was_set = 1;
645 +       return err;
646 +}
647 +
648 +#ifdef CONFIG_ATM_BR2684_IPFILTER
649 +/* this IOCTL is experimental. */
650 +static int br2684_setfilt(struct atm_vcc *atmvcc, unsigned long arg)
651 +{
652 +       struct br2684_vcc *brvcc;
653 +       struct br2684_filter_set fs;
654 +
655 +       if (copy_from_user(&fs, (void *) arg, sizeof fs))
656 +               return -EFAULT;
657 +       if (fs.ifspec.method != BR2684_FIND_BYNOTHING) {
658 +               /*
659 +                * This is really a per-vcc thing, but we can also search
660 +                * by device
661 +                */
662 +               struct br2684_dev *brdev;
663 +               read_lock(&devs_lock);
664 +               brdev = br2684_find_dev(&fs.ifspec);
665 +               if (brdev == NULL || list_empty(&brdev->brvccs) ||
666 +                   brdev->brvccs.next != brdev->brvccs.prev)  /* >1 VCC */
667 +                       brvcc = NULL;
668 +               else
669 +                       brvcc = list_entry_brvcc(brdev->brvccs.next);
670 +               read_unlock(&devs_lock);
671 +               if (brvcc == NULL)
672 +                       return -ESRCH;
673 +       } else
674 +               brvcc = BR2684_VCC(atmvcc);
675 +       memcpy(&brvcc->filter, &fs.filter, sizeof(brvcc->filter));
676 +       return 0;
677 +}
678 +
679 +/* Returns 1 if packet should be dropped */
680 +static inline int
681 +packet_fails_filter(u16 type, struct br2684_vcc *brvcc, struct sk_buff *skb)
682 +{
683 +       if (brvcc->filter.netmask == 0)
684 +               return 0;                       /* no filter in place */
685 +       if (type == __constant_htons(ETH_P_IP) &&
686 +           (((struct iphdr *) (skb->data))->daddr & brvcc->filter.
687 +            netmask) == brvcc->filter.prefix)
688 +               return 0;
689 +       if (type == __constant_htons(ETH_P_ARP))
690 +               return 0;
691 +       /* TODO: we should probably filter ARPs too.. don't want to have
692 +        *   them returning values that don't make sense, or is that ok?
693 +        */
694 +       return 1;               /* drop */
695 +}
696 +#endif /* CONFIG_ATM_BR2684_IPFILTER */
697 +
698 +static void br2684_close_vcc(struct br2684_vcc *brvcc)
699 +{
700 +       DPRINTK("removing VCC %p from dev %p\n", brvcc, brvcc->brdev);
701 +       write_lock_irq(&devs_lock);
702 +       list_del(&brvcc->brvccs);
703 +       write_unlock_irq(&devs_lock);
704 +       brvcc->atmvcc->user_back = NULL;        /* what about vcc->recvq ??? */
705 +       brvcc->old_push(brvcc->atmvcc, NULL);   /* pass on the bad news */
706 +       kfree(brvcc);
707 +       MOD_DEC_USE_COUNT;
708 +}
709 +
710 +/* when AAL5 PDU comes in: */
711 +static void br2684_push(struct atm_vcc *atmvcc, struct sk_buff *skb)
712 +{
713 +       struct br2684_vcc *brvcc = BR2684_VCC(atmvcc);
714 +       struct br2684_dev *brdev = brvcc->brdev;
715 +       int plen = sizeof(llc_oui_pid_pad) + ETH_HLEN;
716 +
717 +       DPRINTK("br2684_push\n");
718 +
719 +       if (skb == NULL) {      /* skb==NULL means VCC is being destroyed */
720 +               br2684_close_vcc(brvcc);
721 +               return;
722 +       }
723 +
724 +       skb_debug(skb);
725 +       atm_return(atmvcc, skb->truesize);
726 +       DPRINTK("skb from brdev %p\n", brdev);
727 +       if (brvcc->encaps == e_llc) {
728 +               /* let us waste some time for checking the encapsulation.
729 +                  Note, that only 7 char is checked so frames with a valid FCS
730 +                  are also accepted (but FCS is not checked of course) */
731 +               if (memcmp(skb->data, llc_oui_pid_pad, 7)) {
732 +                       brdev->stats.rx_errors++;
733 +                       dev_kfree_skb(skb);
734 +                       return;
735 +               }
736 +       } else {
737 +               plen = PADLEN + ETH_HLEN;       /* pad, dstmac,srcmac, ethtype */
738 +               /* first 2 chars should be 0 */
739 +               if (*((u16 *) (skb->data)) != 0) {
740 +                       brdev->stats.rx_errors++;
741 +                       dev_kfree_skb(skb);
742 +                       return;
743 +               }
744 +       }
745 +       if (skb->len < plen) {
746 +               brdev->stats.rx_errors++;
747 +               dev_kfree_skb(skb);     /* dev_ not needed? */
748 +               return;
749 +       }
750 +
751 +#ifdef FASTER_VERSION
752 +       /* FIXME: tcpdump shows that pointer to mac header is 2 bytes earlier,
753 +          than should be. What else should I set? */
754 +       skb_pull(skb, plen);
755 +       skb->mac.raw = ((char *) (skb->data)) - ETH_HLEN;
756 +       skb->pkt_type = PACKET_HOST;
757 +#ifdef CONFIG_BR2684_FAST_TRANS
758 +       skb->protocol = ((u16 *) skb->data)[-1];
759 +#else                          /* some protocols might require this: */
760 +       skb->protocol = br_type_trans(skb, &brdev->net_dev);
761 +#endif /* CONFIG_BR2684_FAST_TRANS */
762 +#else
763 +       skb_pull(skb, plen - ETH_HLEN);
764 +       skb->protocol = eth_type_trans(skb, &brdev->net_dev);
765 +#endif /* FASTER_VERSION */
766 +#ifdef CONFIG_ATM_BR2684_IPFILTER
767 +       if (packet_fails_filter(skb->protocol, brvcc, skb)) {
768 +               brdev->stats.rx_dropped++;
769 +               dev_kfree_skb(skb);
770 +               return;
771 +       }
772 +#endif /* CONFIG_ATM_BR2684_IPFILTER */
773 +       skb->dev = &brdev->net_dev;
774 +       ATM_SKB(skb)->vcc = atmvcc;     /* needed ? */
775 +       DPRINTK("received packet's protocol: %x\n", ntohs(skb->protocol));
776 +       skb_debug(skb);
777 +       if (!(brdev->net_dev.flags & IFF_UP)) { /* sigh, interface is down */
778 +               brdev->stats.rx_dropped++;
779 +               dev_kfree_skb(skb);
780 +               return;
781 +       }
782 +       brdev->stats.rx_packets++;
783 +       brdev->stats.rx_bytes += skb->len;
784 +       netif_rx(skb);
785 +}
786 +
787 +static int br2684_regvcc(struct atm_vcc *atmvcc, unsigned long arg)
788 +{
789 +/* assign a vcc to a dev
790 +Note: we do not have explicit unassign, but look at _push()
791 +*/
792 +       int err;
793 +       struct br2684_vcc *brvcc;
794 +       struct sk_buff_head copy;
795 +       struct sk_buff *skb;
796 +       struct br2684_dev *brdev;
797 +       struct atm_backend_br2684 be;
798 +
799 +       MOD_INC_USE_COUNT;
800 +       if (copy_from_user(&be, (void *) arg, sizeof be)) {
801 +               MOD_DEC_USE_COUNT;
802 +               return -EFAULT;
803 +       }
804 +       write_lock_irq(&devs_lock);
805 +       brdev = br2684_find_dev(&be.ifspec);
806 +       if (brdev == NULL) {
807 +               printk(KERN_ERR
808 +                   "br2684: tried to attach to non-existant device\n");
809 +               err = -ENXIO;
810 +               goto error;
811 +       }
812 +       if (atmvcc->push == NULL) {
813 +               err = -EBADFD;
814 +               goto error;
815 +       }
816 +       if (!list_empty(&brdev->brvccs)) {      /* Only 1 VCC/dev right now */
817 +               err = -EEXIST;
818 +               goto error;
819 +       }
820 +       if (be.fcs_in != BR2684_FCSIN_NO || be.fcs_out != BR2684_FCSOUT_NO ||
821 +           be.fcs_auto || be.has_vpiid || be.send_padding || (be.encaps !=
822 +           BR2684_ENCAPS_VC && be.encaps != BR2684_ENCAPS_LLC) ||
823 +           be.min_size != 0) {
824 +               err = -EINVAL;
825 +               goto error;
826 +       }
827 +       brvcc = kmalloc(sizeof(struct br2684_vcc), GFP_KERNEL);
828 +       if (!brvcc) {
829 +               err = -ENOMEM;
830 +               goto error;
831 +       }
832 +       memset(brvcc, 0, sizeof(struct br2684_vcc));
833 +       DPRINTK("br2684_regvcc vcc=%p, encaps=%d, brvcc=%p\n", atmvcc, be.encaps,
834 +               brvcc);
835 +       if (list_empty(&brdev->brvccs) && !brdev->mac_was_set) {
836 +               unsigned char *esi = atmvcc->dev->esi;
837 +               if (esi[0] | esi[1] | esi[2] | esi[3] | esi[4] | esi[5])
838 +                       memcpy(brdev->net_dev.dev_addr, esi,
839 +                           brdev->net_dev.addr_len);
840 +               else
841 +                       brdev->net_dev.dev_addr[2] = 1;
842 +       }
843 +       list_add(&brvcc->brvccs, &brdev->brvccs);
844 +       write_unlock_irq(&devs_lock);
845 +       brvcc->brdev = brdev;
846 +       brvcc->atmvcc = atmvcc;
847 +       atmvcc->user_back = brvcc;
848 +       brvcc->encaps = (enum br2684_encaps) be.encaps;
849 +       brvcc->old_push = atmvcc->push;
850 +       barrier();
851 +       atmvcc->push = br2684_push;
852 +       skb_queue_head_init(&copy);
853 +       skb_migrate(&atmvcc->recvq, &copy);
854 +       while ((skb = skb_dequeue(&copy))) {
855 +               BRPRIV(skb->dev)->stats.rx_bytes -= skb->len;
856 +               BRPRIV(skb->dev)->stats.rx_packets--;
857 +               br2684_push(atmvcc, skb);
858 +       }
859 +       return 0;
860 +    error:
861 +       write_unlock_irq(&devs_lock);
862 +       MOD_DEC_USE_COUNT;
863 +       return err;
864 +}
865 +
866 +static int br2684_create(unsigned long arg)
867 +{
868 +       int err;
869 +       struct br2684_dev *brdev;
870 +       struct atm_newif_br2684 ni;
871 +
872 +       DPRINTK("br2684_create\n");
873 +       /*
874 +        * We track module use by vcc's NOT the devices they're on.  We're
875 +        * protected here against module death by the kernel_lock, but if
876 +        * we need to sleep we should make sure that the module doesn't
877 +        * disappear under us.
878 +        */
879 +       MOD_INC_USE_COUNT;
880 +       if (copy_from_user(&ni, (void *) arg, sizeof ni)) {
881 +               MOD_DEC_USE_COUNT;
882 +               return -EFAULT;
883 +       }
884 +       if (ni.media != BR2684_MEDIA_ETHERNET || ni.mtu != 1500) {
885 +               MOD_DEC_USE_COUNT;
886 +               return -EINVAL;
887 +       }
888 +       if ((brdev = kmalloc(sizeof(struct br2684_dev), GFP_KERNEL)) == NULL) {
889 +               MOD_DEC_USE_COUNT;
890 +               return -ENOMEM;
891 +       }
892 +       memset(brdev, 0, sizeof(struct br2684_dev));
893 +       INIT_LIST_HEAD(&brdev->brvccs);
894 +
895 +       write_lock_irq(&devs_lock);
896 +       brdev->number = list_empty(&br2684_devs) ? 1 :
897 +           list_entry_brdev(br2684_devs.prev)->number + 1;
898 +       list_add_tail(&brdev->br2684_devs, &br2684_devs);
899 +       write_unlock_irq(&devs_lock);
900 +
901 +       if (ni.ifname[0] != '\0') {
902 +               memcpy(brdev->net_dev.name, ni.ifname,
903 +                   sizeof(brdev->net_dev.name));
904 +               brdev->net_dev.name[sizeof(brdev->net_dev.name) - 1] = '\0';
905 +       } else
906 +               sprintf(brdev->net_dev.name, "nas%d", brdev->number);
907 +       DPRINTK("registered netdev %s\n", brdev->net_dev.name);
908 +       ether_setup(&brdev->net_dev);
909 +       brdev->mac_was_set = 0;
910 +#ifdef FASTER_VERSION
911 +       my_eth_header = brdev->net_dev.hard_header;
912 +       brdev->net_dev.hard_header = br2684_header;
913 +       my_eth_header_cache = brdev->net_dev.hard_header_cache;
914 +       brdev->net_dev.hard_header_cache = br2684_header_cache;
915 +       brdev->net_dev.hard_header_len = sizeof(llc_oui_pid_pad) + ETH_HLEN;    /* 10 + 14 */
916 +#endif
917 +       my_eth_mac_addr = brdev->net_dev.set_mac_address;
918 +       brdev->net_dev.set_mac_address = br2684_mac_addr;
919 +       brdev->net_dev.hard_start_xmit = br2684_start_xmit;
920 +       brdev->net_dev.get_stats = br2684_get_stats;
921 +
922 +       /* open, stop, do_ioctl ? */
923 +       err = register_netdev(&brdev->net_dev);
924 +       MOD_DEC_USE_COUNT;
925 +       if (err < 0) {
926 +               printk(KERN_ERR "br2684_create: register_netdev failed\n");
927 +               write_lock_irq(&devs_lock);
928 +               list_del(&brdev->br2684_devs);
929 +               write_unlock_irq(&devs_lock);
930 +               kfree(brdev);
931 +               return err;
932 +       }
933 +       return 0;
934 +}
935 +
936 +/*
937 + * This handles ioctls actually performed on our vcc - we must return
938 + * -ENOIOCTLCMD for any unrecognized ioctl
939 + */
940 +static int br2684_ioctl(struct atm_vcc *atmvcc, unsigned int cmd,
941 +       unsigned long arg)
942 +{
943 +       int err;
944 +       switch(cmd) {
945 +       case ATM_SETBACKEND:
946 +       case ATM_NEWBACKENDIF: {
947 +               atm_backend_t b;
948 +               MOD_INC_USE_COUNT;
949 +               err = get_user(b, (atm_backend_t *) arg);
950 +               MOD_DEC_USE_COUNT;
951 +               if (err)
952 +                       return -EFAULT;
953 +               if (b != ATM_BACKEND_BR2684)
954 +                       return -ENOIOCTLCMD;
955 +               if (!capable(CAP_NET_ADMIN))
956 +                       return -EPERM;
957 +               if (cmd == ATM_SETBACKEND)
958 +                       return br2684_regvcc(atmvcc, arg);
959 +               else
960 +                       return br2684_create(arg);
961 +               }
962 +#ifdef CONFIG_ATM_BR2684_IPFILTER
963 +       case BR2684_SETFILT:
964 +               if (atmvcc->push != br2684_push)
965 +                       return -ENOIOCTLCMD;
966 +               if (!capable(CAP_NET_ADMIN))
967 +                       return -EPERM;
968 +               MOD_INC_USE_COUNT;
969 +               err = br2684_setfilt(atmvcc, arg);
970 +               MOD_DEC_USE_COUNT;
971 +               return err;
972 +#endif /* CONFIG_ATM_BR2684_IPFILTER */
973 +       }
974 +       return -ENOIOCTLCMD;
975 +}
976 +
977 +/* Never put more than 256 bytes in at once */
978 +static int br2684_proc_engine(loff_t pos, char *buf)
979 +{
980 +       struct list_head *lhd, *lhc;
981 +       struct br2684_dev *brdev;
982 +       struct br2684_vcc *brvcc;
983 +       list_for_each(lhd, &br2684_devs) {
984 +               brdev = list_entry_brdev(lhd);
985 +               if (pos-- == 0)
986 +                       return sprintf(buf, "dev %.16s: num=%d, mac=%02X:%02X:"
987 +                           "%02X:%02X:%02X:%02X (%s)\n", brdev->net_dev.name,
988 +                           brdev->number,
989 +                           brdev->net_dev.dev_addr[0],
990 +                           brdev->net_dev.dev_addr[1],
991 +                           brdev->net_dev.dev_addr[2],
992 +                           brdev->net_dev.dev_addr[3],
993 +                           brdev->net_dev.dev_addr[4],
994 +                           brdev->net_dev.dev_addr[5],
995 +                           brdev->mac_was_set ? "set" : "auto");
996 +               list_for_each(lhc, &brdev->brvccs) {
997 +                       brvcc = list_entry_brvcc(lhc);
998 +                       if (pos-- == 0)
999 +                               return sprintf(buf, "  vcc %d.%d.%d: encaps=%s"
1000 +#ifndef FASTER_VERSION
1001 +                                   ", failed copies %u/%u"
1002 +#endif /* FASTER_VERSION */
1003 +                                   "\n", brvcc->atmvcc->dev->number,
1004 +                                   brvcc->atmvcc->vpi, brvcc->atmvcc->vci,
1005 +                                   (brvcc->encaps == e_llc) ? "LLC" : "VC"
1006 +#ifndef FASTER_VERSION
1007 +                                   , brvcc->copies_failed
1008 +                                   , brvcc->copies_needed
1009 +#endif /* FASTER_VERSION */
1010 +                                   );
1011 +#ifdef CONFIG_ATM_BR2684_IPFILTER
1012 +#define b1(var, byte)  ((u8 *) &brvcc->filter.var)[byte]
1013 +#define bs(var)                b1(var, 0), b1(var, 1), b1(var, 2), b1(var, 3)
1014 +                       if (brvcc->filter.netmask != 0 && pos-- == 0)
1015 +                               return sprintf(buf, "    filter=%d.%d.%d.%d/"
1016 +                                   "%d.%d.%d.%d\n", bs(prefix), bs(netmask));
1017 +#undef bs
1018 +#undef b1
1019 +#endif /* CONFIG_ATM_BR2684_IPFILTER */
1020 +               }
1021 +       }
1022 +       return 0;
1023 +}
1024 +
1025 +static ssize_t br2684_proc_read(struct file *file, char *buf, size_t count,
1026 +       loff_t *pos)
1027 +{
1028 +       unsigned long page;
1029 +       int len = 0, x, left;
1030 +       page = get_free_page(GFP_KERNEL);
1031 +       if (!page)
1032 +               return -ENOMEM;
1033 +       left = PAGE_SIZE - 256;
1034 +       if (count < left)
1035 +               left = count;
1036 +       read_lock(&devs_lock);
1037 +       for (;;) {
1038 +               x = br2684_proc_engine(*pos, &((char *) page)[len]);
1039 +               if (x == 0)
1040 +                       break;
1041 +               if (x > left)
1042 +                       /*
1043 +                        * This should only happen if the user passed in
1044 +                        * a "count" too small for even one line
1045 +                        */
1046 +                       x = -EINVAL;
1047 +               if (x < 0) {
1048 +                       len = x;
1049 +                       break;
1050 +               }
1051 +               len += x;
1052 +               left -= x;
1053 +               (*pos)++;
1054 +               if (left < 256)
1055 +                       break;
1056 +       }
1057 +       read_unlock(&devs_lock);
1058 +       if (len > 0 && copy_to_user(buf, (char *) page, len))
1059 +               len = -EFAULT;
1060 +       free_page(page);
1061 +       return len;
1062 +}
1063 +
1064 +static struct file_operations br2684_proc_operations = {
1065 +       read: br2684_proc_read,
1066 +};
1067 +
1068 +extern struct proc_dir_entry *atm_proc_root;   /* from proc.c */
1069 +
1070 +extern int (*br2684_ioctl_hook)(struct atm_vcc *, unsigned int, unsigned long);
1071 +
1072 +/* the following avoids some spurious warnings from the compiler */
1073 +#define UNUSED __attribute__((unused))
1074 +
1075 +static int __init UNUSED br2684_init(void)
1076 +{
1077 +       struct proc_dir_entry *p;
1078 +       if ((p = create_proc_entry("br2684", 0, atm_proc_root)) == NULL)
1079 +               return -ENOMEM;
1080 +       p->proc_fops = &br2684_proc_operations;
1081 +       br2684_ioctl_hook = br2684_ioctl;
1082 +       return 0;
1083 +}
1084 +
1085 +static void __exit UNUSED br2684_exit(void)
1086 +{
1087 +       struct br2684_dev *brdev;
1088 +       br2684_ioctl_hook = NULL;
1089 +       remove_proc_entry("br2684", atm_proc_root);
1090 +       while (!list_empty(&br2684_devs)) {
1091 +               brdev = list_entry_brdev(br2684_devs.next);
1092 +               unregister_netdev(&brdev->net_dev);
1093 +               list_del(&brdev->br2684_devs);
1094 +               kfree(brdev);
1095 +       }
1096 +}
1097 +
1098 +module_init(br2684_init);
1099 +module_exit(br2684_exit);
1100 +
1101 +MODULE_AUTHOR("Marcell GAL");
1102 +MODULE_DESCRIPTION("RFC2684 bridged protocols over ATM/AAL5");
1103 diff -urN linux.orig/net/atm/common.c linux/net/atm/common.c
1104 --- linux.orig/net/atm/common.c Sat Apr 21 18:04:58 2001
1105 +++ linux/net/atm/common.c      Sat Apr 21 18:06:09 2001
1106 @@ -58,6 +58,18 @@
1107  #endif
1108  #endif
1109  
1110 +#if defined(CONFIG_PPPOATM) || defined(CONFIG_PPPOATM_MODULE)
1111 +int (*pppoatm_ioctl_hook)(struct atm_vcc *, unsigned int, unsigned long);
1112 +EXPORT_SYMBOL(pppoatm_ioctl_hook);
1113 +#endif
1114 +
1115 +#if defined(CONFIG_ATM_BR2684) || defined(CONFIG_ATM_BR2684_MODULE)
1116 +int (*br2684_ioctl_hook)(struct atm_vcc *, unsigned int, unsigned long);
1117 +#endif
1118 +#ifdef CONFIG_ATM_BR2684_MODULE
1119 +EXPORT_SYMBOL(br2684_ioctl_hook);
1120 +#endif
1121 +
1122  #include "resources.h"         /* atm_find_dev */
1123  #include "common.h"            /* prototypes */
1124  #include "protocols.h"         /* atm_init_<transport> */
1125 @@ -774,6 +786,20 @@
1126                 default:
1127                         break;
1128         }
1129 +#if defined(CONFIG_PPPOATM) || defined(CONFIG_PPPOATM_MODULE)
1130 +       if (pppoatm_ioctl_hook &&
1131 +           (error = pppoatm_ioctl_hook(vcc, cmd, arg)) != -ENOIOCTLCMD) {
1132 +               spin_unlock (&atm_dev_lock); 
1133 +               return error;
1134 +       }
1135 +#endif
1136 +#if defined(CONFIG_ATM_BR2684) || defined(CONFIG_ATM_BR2684_MODULE)
1137 +       if (br2684_ioctl_hook &&
1138 +           (error = br2684_ioctl_hook(vcc, cmd, arg)) != -ENOIOCTLCMD) {
1139 +               spin_unlock (&atm_dev_lock); 
1140 +               return error;
1141 +       }
1142 +#endif
1143         if (get_user(buf,&((struct atmif_sioc *) arg)->arg)) {
1144                 ret_val = -EFAULT;
1145                 goto done;
1146 diff -urN linux.orig/net/atm/pppoatm.c linux/net/atm/pppoatm.c
1147 --- linux.orig/net/atm/pppoatm.c        Thu Jan  1 01:00:00 1970
1148 +++ linux/net/atm/pppoatm.c     Sat Apr 21 18:06:09 2001
1149 @@ -0,0 +1,373 @@
1150 +/* net/atm/pppoatm.c - RFC2364 PPP over ATM/AAL5 */
1151 +
1152 +/* Copyright 1999-2000 by Mitchell Blank Jr */
1153 +/* Based on clip.c; 1995-1999 by Werner Almesberger, EPFL LRC/ICA */
1154 +/* And on ppp_async.c; Copyright 1999 Paul Mackerras */
1155 +/* And help from Jens Axboe */
1156 +
1157 +/*
1158 + *  This program is free software; you can redistribute it and/or
1159 + *  modify it under the terms of the GNU General Public License
1160 + *  as published by the Free Software Foundation; either version
1161 + *  2 of the License, or (at your option) any later version.
1162 + *
1163 + * This driver provides the encapsulation and framing for sending
1164 + * and receiving PPP frames in ATM AAL5 PDUs.
1165 + */
1166 +
1167 +/*
1168 + * One shortcoming of this driver is that it does not comply with
1169 + * section 8 of RFC2364 - we are supposed to detect a change
1170 + * in encapsulation and immediately abort the connection (in order
1171 + * to avoid a black-hole being created if our peer loses state
1172 + * and changes encapsulation unilaterally.  However, since the
1173 + * ppp_generic layer actually does the decapsulation, we need
1174 + * a way of notifying it when we _think_ there might be a problem)
1175 + * There's two cases:
1176 + *   1.        LLC-encapsulation was missing when it was enabled.  In
1177 + *     this case, we should tell the upper layer "tear down
1178 + *     this session if this skb looks ok to you"
1179 + *   2.        LLC-encapsulation was present when it was disabled.  Then
1180 + *     we need to tell the upper layer "this packet may be
1181 + *     ok, but if its in error tear down the session"
1182 + * These hooks are not yet available in ppp_generic
1183 + */
1184 +
1185 +#include <linux/module.h>
1186 +#include <linux/config.h>
1187 +#include <linux/init.h>
1188 +#include <linux/skbuff.h>
1189 +#include <linux/atm.h>
1190 +#include <linux/atmdev.h>
1191 +#include <linux/ppp_defs.h>
1192 +#include <linux/if_ppp.h>
1193 +#include <linux/ppp_channel.h>
1194 +#include <linux/atmppp.h>
1195 +
1196 +#if 0
1197 +#define DPRINTK(format, args...) \
1198 +       printk(KERN_DEBUG "pppoatm: " format, ##args)
1199 +#else
1200 +#define DPRINTK(format, args...)
1201 +#endif
1202 +
1203 +enum pppoatm_encaps {
1204 +       e_autodetect = PPPOATM_ENCAPS_AUTODETECT,
1205 +       e_vc = PPPOATM_ENCAPS_VC,
1206 +       e_llc = PPPOATM_ENCAPS_LLC,
1207 +};
1208 +
1209 +struct pppoatm_vcc {
1210 +       struct atm_vcc  *atmvcc;        /* VCC descriptor */
1211 +       void (*old_push)(struct atm_vcc *, struct sk_buff *);
1212 +       void (*old_pop)(struct atm_vcc *, struct sk_buff *);
1213 +                                       /* keep old push/pop for detaching */
1214 +       enum pppoatm_encaps encaps;
1215 +       int flags;                      /* SC_COMP_PROT - compress protocol */
1216 +       struct ppp_channel chan;        /* interface to generic ppp layer */
1217 +       struct tasklet_struct wakeup_tasklet;
1218 +};
1219 +
1220 +/*
1221 + * Header used for LLC Encapsulated PPP (4 bytes) followed by the LCP protocol
1222 + * ID (0xC021) used in autodetection
1223 + */
1224 +static const unsigned char pppllc[6] = { 0xFE, 0xFE, 0x03, 0xCF, 0xC0, 0x21 };
1225 +#define LLC_LEN                (4)
1226 +
1227 +static inline struct pppoatm_vcc *atmvcc_to_pvcc(const struct atm_vcc *atmvcc)
1228 +{
1229 +       return (struct pppoatm_vcc *) (atmvcc->user_back);
1230 +}
1231 +
1232 +static inline struct pppoatm_vcc *chan_to_pvcc(const struct ppp_channel *chan)
1233 +{
1234 +       return (struct pppoatm_vcc *) (chan->private);
1235 +}
1236 +
1237 +/*
1238 + * We can't do this directly from our _pop handler, since the ppp code
1239 + * doesn't want to be called in interrupt context, so we do it from
1240 + * a tasklet
1241 + */
1242 +static void pppoatm_wakeup_sender(unsigned long arg)
1243 +{
1244 +       ppp_output_wakeup((struct ppp_channel *) arg);
1245 +}
1246 +
1247 +/*
1248 + * This gets called every time the ATM card has finished sending our
1249 + * skb.  The ->old_pop will take care up normal atm flow control,
1250 + * but we also need to wake up the device if we blocked it
1251 + */
1252 +static void pppoatm_pop(struct atm_vcc *atmvcc, struct sk_buff *skb)
1253 +{
1254 +       struct pppoatm_vcc *pvcc = atmvcc_to_pvcc(atmvcc);
1255 +       pvcc->old_pop(atmvcc, skb);
1256 +       /*
1257 +        * We don't really always want to do this since it's
1258 +        * really inefficient - it would be much better if we could
1259 +        * test if we had actually throttled the generic layer.
1260 +        * Unfortunately then there would be a nasty SMP race where
1261 +        * we could clear that flag just as we refuse another packet.
1262 +        * For now we do the safe thing.
1263 +        */
1264 +       tasklet_schedule(&pvcc->wakeup_tasklet);
1265 +}
1266 +
1267 +/*
1268 + * Unbind from PPP - currently we only do this when closing the socket,
1269 + * but we could put this into an ioctl if need be
1270 + */
1271 +static void pppoatm_unassign_vcc(struct atm_vcc *atmvcc)
1272 +{
1273 +       struct pppoatm_vcc *pvcc;
1274 +       pvcc = atmvcc_to_pvcc(atmvcc);
1275 +       atmvcc->push = pvcc->old_push;
1276 +       atmvcc->pop = pvcc->old_pop;
1277 +       tasklet_disable(&pvcc->wakeup_tasklet);
1278 +       ppp_unregister_channel(&pvcc->chan);
1279 +       atmvcc->user_back = NULL;
1280 +       kfree(pvcc);
1281 +       /* Gee, I hope we have the big kernel lock here... */
1282 +       MOD_DEC_USE_COUNT;
1283 +}
1284 +
1285 +/* Called when an AAL5 PDU comes in */
1286 +static void pppoatm_push(struct atm_vcc *atmvcc, struct sk_buff *skb)
1287 +{
1288 +       struct pppoatm_vcc *pvcc = atmvcc_to_pvcc(atmvcc);
1289 +       DPRINTK("pppoatm push\n");
1290 +       if (skb == NULL) {                      /* VCC was closed */
1291 +               DPRINTK("removing ATMPPP VCC %p\n", pvcc);
1292 +               pppoatm_unassign_vcc(atmvcc);
1293 +               atmvcc->push(atmvcc, NULL);     /* Pass along bad news */
1294 +               return;
1295 +       }
1296 +       atm_return(atmvcc, skb->truesize);
1297 +       switch (pvcc->encaps) {
1298 +       case e_llc:
1299 +               if (skb->len < LLC_LEN ||
1300 +                   memcmp(skb->data, pppllc, LLC_LEN))
1301 +                       goto error;
1302 +               skb_pull(skb, LLC_LEN);
1303 +               break;
1304 +       case e_autodetect:
1305 +               if (pvcc->chan.ppp == NULL) {   /* Not bound yet! */
1306 +                       kfree_skb(skb);
1307 +                       return;
1308 +               }
1309 +               if (skb->len >= sizeof(pppllc) &&
1310 +                   !memcmp(skb->data, pppllc, sizeof(pppllc))) {
1311 +                       pvcc->encaps = e_llc;
1312 +                       skb_pull(skb, LLC_LEN);
1313 +                       break;
1314 +               }
1315 +               if (skb->len >= (sizeof(pppllc) - LLC_LEN) &&
1316 +                   !memcmp(skb->data, &pppllc[LLC_LEN],
1317 +                   sizeof(pppllc) - LLC_LEN)) {
1318 +                       pvcc->encaps = e_vc;
1319 +                       pvcc->chan.mtu += LLC_LEN;
1320 +                       break;
1321 +               }
1322 +               DPRINTK("(unit %d): Couldn't autodetect yet "
1323 +                   "(skb: %02X %02X %02X %02X %02X %02X)\n",
1324 +                   pvcc->chan.unit,
1325 +                   skb->data[0], skb->data[1], skb->data[2],
1326 +                   skb->data[3], skb->data[4], skb->data[5]);
1327 +               goto error;
1328 +       case e_vc:
1329 +               break;
1330 +       }
1331 +       ppp_input(&pvcc->chan, skb);
1332 +       return;
1333 +    error:
1334 +       kfree_skb(skb);
1335 +       ppp_input_error(&pvcc->chan, 0);
1336 +}
1337 +
1338 +/*
1339 + * Called by the ppp_generic.c to send a packet - returns true if packet
1340 + * was accepted.  If we return false, then it's our job to call
1341 + * ppp_output_wakeup(chan) when we're feeling more up to it.
1342 + * Note that in the ENOMEM case (as opposed to the !atm_may_send case)
1343 + * we should really drop the packet, but the generic layer doesn't
1344 + * support this yet.  We just return 'DROP_PACKET' which we actually define
1345 + * as success, just to be clear what we're really doing.
1346 + */
1347 +#define DROP_PACKET 1
1348 +static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb)
1349 +{
1350 +       struct pppoatm_vcc *pvcc = chan_to_pvcc(chan);
1351 +       ATM_SKB(skb)->vcc = pvcc->atmvcc;
1352 +       DPRINTK("(unit %d): pppoatm_send (skb=0x%p, vcc=0x%p)\n",
1353 +           pvcc->chan.unit, skb, pvcc->atmvcc);
1354 +       if (skb->data[0] == '\0' && (pvcc->flags & SC_COMP_PROT))
1355 +               (void) skb_pull(skb, 1);
1356 +       switch (pvcc->encaps) {         /* LLC encapsulation needed */
1357 +       case e_llc:
1358 +               if (skb_headroom(skb) < LLC_LEN) {
1359 +                       struct sk_buff *n;
1360 +                       n = skb_realloc_headroom(skb, LLC_LEN);
1361 +                       if (n != NULL &&
1362 +                           !atm_may_send(pvcc->atmvcc, n->truesize)) {
1363 +                               kfree_skb(n);
1364 +                               goto nospace;
1365 +                       }
1366 +                       kfree_skb(skb);
1367 +                       if ((skb = n) == NULL)
1368 +                               return DROP_PACKET;
1369 +               } else if (!atm_may_send(pvcc->atmvcc, skb->truesize))
1370 +                       goto nospace;
1371 +               memcpy(skb_push(skb, LLC_LEN), pppllc, LLC_LEN);
1372 +               break;
1373 +       case e_vc:
1374 +               if (!atm_may_send(pvcc->atmvcc, skb->truesize))
1375 +                       goto nospace;
1376 +               break;
1377 +       case e_autodetect:
1378 +               DPRINTK("(unit %d): Trying to send without setting encaps!\n",
1379 +                   pvcc->chan.unit);
1380 +               kfree_skb(skb);
1381 +               return 1;
1382 +       }
1383 +       atomic_add(skb->truesize, &ATM_SKB(skb)->vcc->tx_inuse);
1384 +       ATM_SKB(skb)->iovcnt = 0;
1385 +       ATM_SKB(skb)->atm_options = ATM_SKB(skb)->vcc->atm_options;
1386 +       DPRINTK("(unit %d): atm_skb(%p)->vcc(%p)->dev(%p)\n",
1387 +           pvcc->chan.unit, skb, ATM_SKB(skb)->vcc,
1388 +           ATM_SKB(skb)->vcc->dev);
1389 +       return ATM_SKB(skb)->vcc->send(ATM_SKB(skb)->vcc, skb)
1390 +           ? DROP_PACKET : 1;
1391 +    nospace:
1392 +       /*
1393 +        * We don't have space to send this SKB now, but we might have
1394 +        * already applied SC_COMP_PROT compression, so may need to undo
1395 +        */
1396 +       if ((pvcc->flags & SC_COMP_PROT) && skb_headroom(skb) > 0 &&
1397 +           skb->data[-1] == '\0')
1398 +               (void) skb_push(skb, 1);
1399 +       return 0;
1400 +}
1401 +
1402 +/* This handles ioctls sent to the /dev/ppp interface */
1403 +static int pppoatm_devppp_ioctl(struct ppp_channel *chan, unsigned int cmd,
1404 +       unsigned long arg)
1405 +{
1406 +       switch (cmd) {
1407 +       case PPPIOCGFLAGS:
1408 +               return put_user(chan_to_pvcc(chan)->flags, (int *) arg)
1409 +                   ? -EFAULT : 0;
1410 +       case PPPIOCSFLAGS:
1411 +               return get_user(chan_to_pvcc(chan)->flags, (int *) arg)
1412 +                   ? -EFAULT : 0;
1413 +       }
1414 +       return -ENOTTY;
1415 +}
1416 +
1417 +static /*const*/ struct ppp_channel_ops pppoatm_ops = {
1418 +       start_xmit: pppoatm_send,
1419 +       ioctl: pppoatm_devppp_ioctl,
1420 +};
1421 +
1422 +static int pppoatm_assign_vcc(struct atm_vcc *atmvcc, unsigned long arg)
1423 +{
1424 +       struct atm_backend_ppp be;
1425 +       struct pppoatm_vcc *pvcc;
1426 +       int err;
1427 +       /*
1428 +        * Each PPPoATM instance has its own tasklet - this is just a
1429 +        * prototypical one used to initialize them
1430 +        */
1431 +       static const DECLARE_TASKLET(tasklet_proto, pppoatm_wakeup_sender, 0);
1432 +       if (copy_from_user(&be, (void *) arg, sizeof be))
1433 +               return -EFAULT;
1434 +       if (be.encaps != PPPOATM_ENCAPS_AUTODETECT &&
1435 +           be.encaps != PPPOATM_ENCAPS_VC && be.encaps != PPPOATM_ENCAPS_LLC)
1436 +               return -EINVAL;
1437 +       MOD_INC_USE_COUNT;
1438 +       pvcc = kmalloc(sizeof(*pvcc), GFP_KERNEL);
1439 +       if (pvcc == NULL) {
1440 +               MOD_DEC_USE_COUNT;
1441 +               return -ENOMEM;
1442 +       }
1443 +       memset(pvcc, 0, sizeof(*pvcc));
1444 +       pvcc->atmvcc = atmvcc;
1445 +       pvcc->old_push = atmvcc->push;
1446 +       pvcc->old_pop = atmvcc->pop;
1447 +       pvcc->encaps = (enum pppoatm_encaps) be.encaps;
1448 +       pvcc->chan.private = pvcc;
1449 +       pvcc->chan.ops = &pppoatm_ops;
1450 +       pvcc->chan.mtu = atmvcc->qos.txtp.max_sdu - PPP_HDRLEN -
1451 +           (be.encaps == e_vc ? 0 : LLC_LEN);
1452 +       pvcc->wakeup_tasklet = tasklet_proto;
1453 +       pvcc->wakeup_tasklet.data = (unsigned long) &pvcc->chan;
1454 +       if ((err = ppp_register_channel(&pvcc->chan)) != 0) {
1455 +               kfree(pvcc);
1456 +               return err;
1457 +       }
1458 +       atmvcc->user_back = pvcc;
1459 +       atmvcc->push = pppoatm_push;
1460 +       atmvcc->pop = pppoatm_pop;
1461 +       return 0;
1462 +}
1463 +
1464 +/*
1465 + * This handles ioctls actually performed on our vcc - we must return
1466 + * -ENOIOCTLCMD for any unrecognized ioctl
1467 + */
1468 +static int pppoatm_ioctl(struct atm_vcc *atmvcc, unsigned int cmd,
1469 +       unsigned long arg)
1470 +{
1471 +       int err;
1472 +       if (cmd != ATM_SETBACKEND && atmvcc->push != pppoatm_push)
1473 +               return -ENOIOCTLCMD;
1474 +       switch (cmd) {
1475 +       case ATM_SETBACKEND: {
1476 +               atm_backend_t b;
1477 +               MOD_INC_USE_COUNT;
1478 +               err = get_user(b, (atm_backend_t *) arg);
1479 +               MOD_DEC_USE_COUNT;
1480 +               if (err)
1481 +                       return -EFAULT;
1482 +               if (b != ATM_BACKEND_PPP)
1483 +                       return -ENOIOCTLCMD;
1484 +               if (!capable(CAP_NET_ADMIN))
1485 +                       return -EPERM;
1486 +               return pppoatm_assign_vcc(atmvcc, arg);
1487 +               }
1488 +       case PPPIOCGCHAN:
1489 +       case PPPIOCGUNIT:
1490 +               MOD_INC_USE_COUNT;
1491 +               err = put_user((cmd == PPPIOCGCHAN) ?
1492 +                   ppp_channel_index(&atmvcc_to_pvcc(atmvcc)->chan) :
1493 +                   ppp_unit_number(&atmvcc_to_pvcc(atmvcc)->chan),
1494 +                   (int *) arg);
1495 +               MOD_DEC_USE_COUNT;
1496 +               return err ? -EFAULT : 0;
1497 +       }
1498 +       return -ENOIOCTLCMD;
1499 +}
1500 +
1501 +/* the following avoids some spurious warnings from the compiler */
1502 +#define UNUSED __attribute__((unused))
1503 +
1504 +extern int (*pppoatm_ioctl_hook)(struct atm_vcc *,
1505 +        unsigned int, unsigned long);
1506 +
1507 +static int __init UNUSED pppoatm_init(void)
1508 +{
1509 +       pppoatm_ioctl_hook = pppoatm_ioctl;
1510 +       return 0;
1511 +}
1512 +
1513 +static void __exit UNUSED pppoatm_exit(void)
1514 +{
1515 +       pppoatm_ioctl_hook = NULL;
1516 +}
1517 +
1518 +module_init(pppoatm_init);
1519 +module_exit(pppoatm_exit);
1520 +
1521 +MODULE_AUTHOR("Mitchell Blank Jr <mitch@sfgoth.com>");
1522 +MODULE_DESCRIPTION("RFC2364 PPP over ATM/AAL5");
This page took 0.133813 seconds and 3 git commands to generate.