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
5 briefly removed during revalidation. If you say Y here, packets to
6 such neighbours are silently discarded instead.
8 +RFC1483/2684 Bridged protocols
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.
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.
21 LAN Emulation (LANE) support
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
29 +PPP over ATM (EXPERIMENTAL)
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.
36 Wireless LAN (non-hamradio)
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
45 +PPP OVER ATM (RFC 2364)
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
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
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
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
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
89 +typedef unsigned short atm_backend_t;
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
97 +#ifndef _LINUX_ATMBR2684_H
98 +#define _LINUX_ATMBR2684_H
100 +#include <linux/atm.h>
101 +#include <linux/if.h> /* For IFNAMSIZ */
104 + * Type of media we're bridging (ethernet, token ring, etc) Currently only
105 + * ethernet is supported
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 */
114 + * Is there FCS inbound on this VC? This currently isn't supported.
116 +#define BR2684_FCSIN_NO (0)
117 +#define BR2684_FCSIN_IGNORE (1)
118 +#define BR2684_FCSIN_VERIFY (2)
121 + * Is there FCS outbound on this VC? This currently isn't supported.
123 +#define BR2684_FCSOUT_NO (0)
124 +#define BR2684_FCSOUT_SENDZERO (1)
125 +#define BR2684_FCSOUT_GENERATE (2)
128 + * Does this VC include LLC encapsulation?
130 +#define BR2684_ENCAPS_VC (0) /* VC-mux */
131 +#define BR2684_ENCAPS_LLC (1)
132 +#define BR2684_ENCAPS_AUTODETECT (2) /* Unsuported */
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
139 +struct atm_newif_br2684 {
140 + atm_backend_t backend_num; /* ATM_BACKEND_BR2684 */
141 + int media; /* BR2684_MEDIA_* */
142 + char ifname[IFNAMSIZ];
147 + * This structure is used to specify a br2684 interface - either by a
148 + * positive integer (returned by ATM_NEWBACKENDIF) or the interfaces name
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_* */
156 + char ifname[IFNAMSIZ];
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
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 */
175 + int send_padding; /* unsupported */
176 + int min_size; /* we will pad smaller packets than this */
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
184 +struct br2684_filter {
185 + __u32 prefix; /* network byte order */
186 + __u32 netmask; /* 0 = disable filter */
189 +struct br2684_filter_set {
190 + struct br2684_if_spec ifspec;
191 + struct br2684_filter filter;
194 +#define BR2684_SETFILT _IOW( 'a', ATMIOC_BACKEND + 0, \
195 + struct br2684_filter_set)
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
202 #define ATM_SETSC _IOW('a',ATMIOC_SPECIAL+1,int)
203 /* enable or disable single-copy */
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 */
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
215 +#define ATM_BACKEND_RAW 0
216 +#define ATM_BACKEND_PPP 1 /* PPPoATM - RFC2364 */
217 +#define ATM_BACKEND_BR2684 2 /* Bridged RFC1483/2684 */
219 /* for ATM_GETTYPE */
220 #define ATM_ITFTYP_LEN 8 /* maximum length of interface type name */
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
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
240 +/* atmppp.h - RFC2364 PPPoATM */
242 +/* Written 2000 by Mitchell Blank Jr */
244 +#ifndef _LINUX_ATMPPP_H
245 +#define _LINUX_ATMPPP_H
247 +#include <linux/atm.h>
249 +#define PPPOATM_ENCAPS_AUTODETECT (0)
250 +#define PPPOATM_ENCAPS_VC (1)
251 +#define PPPOATM_ENCAPS_LLC (2)
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
258 +struct atm_backend_ppp {
259 + atm_backend_t backend_num; /* ATM_BACKEND_PPP */
260 + int encaps; /* PPPOATM_ENCAPS_* */
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
268 if [ "$CONFIG_INET" = "y" -a "$CONFIG_ATM_LANE" != "n" ]; then
269 tristate ' Multi-Protocol Over ATM (MPOA) support' CONFIG_ATM_MPOA
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
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
282 NEED_IPCOM = ipcommon.o
285 +ifeq ($(CONFIG_ATM_BR2684),y)
286 + NEED_IPCOM = ipcommon.o
288 + ifeq ($(CONFIG_ATM_BR2684),m)
289 + NEED_IPCOM = ipcommon.o
292 +obj-$(CONFIG_ATM_BR2684) += br2684.o
294 ifeq ($(CONFIG_NET_SCH_ATM),y)
295 NEED_IPCOM = ipcommon.o
299 obj-$(CONFIG_ATM_LANE) += lec.o
300 obj-$(CONFIG_ATM_MPOA) += mpoa.o
301 +obj-$(CONFIG_PPPOATM) += pppoatm.o
303 include $(TOPDIR)/Rules.make
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
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
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>
328 +#include "ipcommon.h"
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
338 +/* #define FASTER_VERSION */
341 +#define DPRINTK(format, args...) printk(KERN_DEBUG "br2684: " format, ##args)
343 +#define DPRINTK(format, args...)
347 +static void skb_debug(const struct sk_buff *skb)
349 +#define NUM2PRINT 50
350 + char buf[NUM2PRINT * 3 + 1]; /* 3 chars per byte */
352 + for (i = 0; i < skb->len && i < NUM2PRINT; i++) {
353 + sprintf(buf + i * 3, "%2.2x ", 0xff & skb->data[i]);
355 + printk(KERN_DEBUG "br2684: skb: %s\n", buf);
358 +#define skb_debug(skb) do {} while (0)
361 +static unsigned char llc_oui_pid_pad[] =
362 + { 0xAA, 0xAA, 0x03, 0x00, 0x80, 0xC2, 0x00, 0x07, 0x00, 0x00 };
365 +enum br2684_encaps {
366 + e_vc = BR2684_ENCAPS_VC,
367 + e_llc = BR2684_ENCAPS_LLC,
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 */
387 + struct net_device net_dev;
388 + struct list_head br2684_devs;
390 + struct list_head brvccs; /* one device <=> one vcc (before xmas) */
391 + struct net_device_stats stats;
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
402 +static rwlock_t devs_lock = RW_LOCK_UNLOCKED;
404 +static LIST_HEAD(br2684_devs);
406 +static inline struct br2684_dev *BRPRIV(const struct net_device *net_dev)
408 + return (struct br2684_dev *) ((char *) (net_dev) -
409 + (unsigned long) (&((struct br2684_dev *) 0)->net_dev));
412 +static inline struct br2684_dev *list_entry_brdev(const struct list_head *le)
414 + return list_entry(le, struct br2684_dev, br2684_devs);
417 +static inline struct br2684_vcc *BR2684_VCC(const struct atm_vcc *atmvcc)
419 + return (struct br2684_vcc *) (atmvcc->user_back);
422 +static inline struct br2684_vcc *list_entry_brvcc(const struct list_head *le)
424 + return list_entry(le, struct br2684_vcc, brvccs);
427 +/* Caller should hold read_lock(&devs_lock) */
428 +static struct br2684_dev *br2684_find_dev(const struct br2684_if_spec *s)
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)
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))
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,
457 +static int br2684_xmit_vcc(struct sk_buff *skb, struct br2684_dev *brdev,
458 + struct br2684_vcc *brvcc)
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)
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++;
479 + skb_push(skb, minheadroom);
480 + if (brvcc->encaps == e_llc)
481 + memcpy(skb->data, llc_oui_pid_pad, 10);
483 + memset(skb->data, 0, 2);
484 +#endif /* FASTER_VERSION */
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.
494 + dev_kfree_skb(skb);
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);
506 +static inline struct br2684_vcc *pick_outgoing_vcc(struct sk_buff *skb,
507 + struct br2684_dev *brdev)
509 + return list_empty(&brdev->brvccs) ? NULL :
510 + list_entry_brvcc(brdev->brvccs.next); /* 1 vcc/dev right now */
513 +static int br2684_start_xmit(struct sk_buff *skb, struct net_device *dev)
515 + struct br2684_dev *brdev = BRPRIV(dev);
516 + struct br2684_vcc *brvcc;
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);
530 + if (!br2684_xmit_vcc(skb, brdev, brvcc)) {
532 + * We should probably use netif_*_queue() here, but that
533 + * involves added complication. We need to walk before
536 + /* don't free here! this pointer might be no longer valid!
537 + dev_kfree_skb(skb);
539 + brdev->stats.tx_errors++;
540 + brdev->stats.tx_fifo_errors++;
542 + read_unlock(&devs_lock);
546 +static struct net_device_stats *br2684_get_stats(struct net_device *dev)
548 + DPRINTK("br2684_get_stats\n");
549 + return &BRPRIV(dev)->stats;
552 +#ifdef FASTER_VERSION
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.
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 *);
563 +br2684_header(struct sk_buff *skb, struct net_device *dev,
564 + unsigned short type, void *daddr, void *saddr, unsigned len)
566 + u16 *pad_before_eth;
567 + int t = my_eth_header(skb, dev, type, daddr, saddr, len);
569 + pad_before_eth = (u16 *) skb_push(skb, 2);
570 + *pad_before_eth = 0;
571 + return dev->hard_header_len; /* or return 16; ? */
577 +br2684_header_cache(struct neighbour *neigh, struct hh_cache *hh)
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);
587 + *pad_before_eth = 0;
588 + hh->hh_len = PADLEN + ETH_HLEN;
594 + * This is similar to eth_type_trans, which cannot be used because of
595 + * our dev->hard_header_len
597 +static inline unsigned short br_type_trans(struct sk_buff *skb,
598 + struct net_device *dev)
600 + struct ethhdr *eth;
601 + unsigned char *rawp;
602 + eth = skb->mac.ethernet;
604 + if (*eth->h_dest & 1) {
605 + if (memcmp(eth->h_dest, dev->broadcast, ETH_ALEN) == 0)
606 + skb->pkt_type = PACKET_BROADCAST;
608 + skb->pkt_type = PACKET_MULTICAST;
611 + else if (memcmp(eth->h_dest, dev->dev_addr, ETH_ALEN))
612 + skb->pkt_type = PACKET_OTHERHOST;
614 + if (ntohs(eth->h_proto) >= 1536)
615 + return eth->h_proto;
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.
625 + if (*(unsigned short *) rawp == 0xFFFF)
626 + return htons(ETH_P_802_3);
631 + return htons(ETH_P_802_2);
633 +#endif /* FASTER_VERSION */
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
639 +static int (*my_eth_mac_addr)(struct net_device *, void *);
640 +static int br2684_mac_addr(struct net_device *dev, void *p)
642 + int err = my_eth_mac_addr(dev, p);
644 + BRPRIV(dev)->mac_was_set = 1;
648 +#ifdef CONFIG_ATM_BR2684_IPFILTER
649 +/* this IOCTL is experimental. */
650 +static int br2684_setfilt(struct atm_vcc *atmvcc, unsigned long arg)
652 + struct br2684_vcc *brvcc;
653 + struct br2684_filter_set fs;
655 + if (copy_from_user(&fs, (void *) arg, sizeof fs))
657 + if (fs.ifspec.method != BR2684_FIND_BYNOTHING) {
659 + * This is really a per-vcc thing, but we can also search
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 */
669 + brvcc = list_entry_brvcc(brdev->brvccs.next);
670 + read_unlock(&devs_lock);
674 + brvcc = BR2684_VCC(atmvcc);
675 + memcpy(&brvcc->filter, &fs.filter, sizeof(brvcc->filter));
679 +/* Returns 1 if packet should be dropped */
681 +packet_fails_filter(u16 type, struct br2684_vcc *brvcc, struct sk_buff *skb)
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)
689 + if (type == __constant_htons(ETH_P_ARP))
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?
694 + return 1; /* drop */
696 +#endif /* CONFIG_ATM_BR2684_IPFILTER */
698 +static void br2684_close_vcc(struct br2684_vcc *brvcc)
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 */
710 +/* when AAL5 PDU comes in: */
711 +static void br2684_push(struct atm_vcc *atmvcc, struct sk_buff *skb)
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;
717 + DPRINTK("br2684_push\n");
719 + if (skb == NULL) { /* skb==NULL means VCC is being destroyed */
720 + br2684_close_vcc(brvcc);
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);
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);
745 + if (skb->len < plen) {
746 + brdev->stats.rx_errors++;
747 + dev_kfree_skb(skb); /* dev_ not needed? */
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 */
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);
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));
777 + if (!(brdev->net_dev.flags & IFF_UP)) { /* sigh, interface is down */
778 + brdev->stats.rx_dropped++;
779 + dev_kfree_skb(skb);
782 + brdev->stats.rx_packets++;
783 + brdev->stats.rx_bytes += skb->len;
787 +static int br2684_regvcc(struct atm_vcc *atmvcc, unsigned long arg)
789 +/* assign a vcc to a dev
790 +Note: we do not have explicit unassign, but look at _push()
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;
800 + if (copy_from_user(&be, (void *) arg, sizeof be)) {
804 + write_lock_irq(&devs_lock);
805 + brdev = br2684_find_dev(&be.ifspec);
806 + if (brdev == NULL) {
808 + "br2684: tried to attach to non-existant device\n");
812 + if (atmvcc->push == NULL) {
816 + if (!list_empty(&brdev->brvccs)) { /* Only 1 VCC/dev right now */
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) {
827 + brvcc = kmalloc(sizeof(struct br2684_vcc), GFP_KERNEL);
832 + memset(brvcc, 0, sizeof(struct br2684_vcc));
833 + DPRINTK("br2684_regvcc vcc=%p, encaps=%d, brvcc=%p\n", atmvcc, be.encaps,
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);
841 + brdev->net_dev.dev_addr[2] = 1;
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;
851 + atmvcc->push = br2684_push;
852 + skb_queue_head_init(©);
853 + skb_migrate(&atmvcc->recvq, ©);
854 + while ((skb = skb_dequeue(©))) {
855 + BRPRIV(skb->dev)->stats.rx_bytes -= skb->len;
856 + BRPRIV(skb->dev)->stats.rx_packets--;
857 + br2684_push(atmvcc, skb);
861 + write_unlock_irq(&devs_lock);
866 +static int br2684_create(unsigned long arg)
869 + struct br2684_dev *brdev;
870 + struct atm_newif_br2684 ni;
872 + DPRINTK("br2684_create\n");
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.
880 + if (copy_from_user(&ni, (void *) arg, sizeof ni)) {
884 + if (ni.media != BR2684_MEDIA_ETHERNET || ni.mtu != 1500) {
888 + if ((brdev = kmalloc(sizeof(struct br2684_dev), GFP_KERNEL)) == NULL) {
892 + memset(brdev, 0, sizeof(struct br2684_dev));
893 + INIT_LIST_HEAD(&brdev->brvccs);
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);
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';
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 */
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;
922 + /* open, stop, do_ioctl ? */
923 + err = register_netdev(&brdev->net_dev);
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);
937 + * This handles ioctls actually performed on our vcc - we must return
938 + * -ENOIOCTLCMD for any unrecognized ioctl
940 +static int br2684_ioctl(struct atm_vcc *atmvcc, unsigned int cmd,
945 + case ATM_SETBACKEND:
946 + case ATM_NEWBACKENDIF: {
949 + err = get_user(b, (atm_backend_t *) arg);
953 + if (b != ATM_BACKEND_BR2684)
954 + return -ENOIOCTLCMD;
955 + if (!capable(CAP_NET_ADMIN))
957 + if (cmd == ATM_SETBACKEND)
958 + return br2684_regvcc(atmvcc, arg);
960 + return br2684_create(arg);
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))
969 + err = br2684_setfilt(atmvcc, arg);
972 +#endif /* CONFIG_ATM_BR2684_IPFILTER */
974 + return -ENOIOCTLCMD;
977 +/* Never put more than 256 bytes in at once */
978 +static int br2684_proc_engine(loff_t pos, char *buf)
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);
986 + return sprintf(buf, "dev %.16s: num=%d, mac=%02X:%02X:"
987 + "%02X:%02X:%02X:%02X (%s)\n", brdev->net_dev.name,
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);
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 */
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));
1019 +#endif /* CONFIG_ATM_BR2684_IPFILTER */
1025 +static ssize_t br2684_proc_read(struct file *file, char *buf, size_t count,
1028 + unsigned long page;
1029 + int len = 0, x, left;
1030 + page = get_free_page(GFP_KERNEL);
1033 + left = PAGE_SIZE - 256;
1036 + read_lock(&devs_lock);
1038 + x = br2684_proc_engine(*pos, &((char *) page)[len]);
1043 + * This should only happen if the user passed in
1044 + * a "count" too small for even one line
1057 + read_unlock(&devs_lock);
1058 + if (len > 0 && copy_to_user(buf, (char *) page, len))
1064 +static struct file_operations br2684_proc_operations = {
1065 + read: br2684_proc_read,
1068 +extern struct proc_dir_entry *atm_proc_root; /* from proc.c */
1070 +extern int (*br2684_ioctl_hook)(struct atm_vcc *, unsigned int, unsigned long);
1072 +/* the following avoids some spurious warnings from the compiler */
1073 +#define UNUSED __attribute__((unused))
1075 +static int __init UNUSED br2684_init(void)
1077 + struct proc_dir_entry *p;
1078 + if ((p = create_proc_entry("br2684", 0, atm_proc_root)) == NULL)
1080 + p->proc_fops = &br2684_proc_operations;
1081 + br2684_ioctl_hook = br2684_ioctl;
1085 +static void __exit UNUSED br2684_exit(void)
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);
1098 +module_init(br2684_init);
1099 +module_exit(br2684_exit);
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
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);
1115 +#if defined(CONFIG_ATM_BR2684) || defined(CONFIG_ATM_BR2684_MODULE)
1116 +int (*br2684_ioctl_hook)(struct atm_vcc *, unsigned int, unsigned long);
1118 +#ifdef CONFIG_ATM_BR2684_MODULE
1119 +EXPORT_SYMBOL(br2684_ioctl_hook);
1122 #include "resources.h" /* atm_find_dev */
1123 #include "common.h" /* prototypes */
1124 #include "protocols.h" /* atm_init_<transport> */
1125 @@ -774,6 +786,20 @@
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);
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);
1143 if (get_user(buf,&((struct atmif_sioc *) arg)->arg)) {
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
1150 +/* net/atm/pppoatm.c - RFC2364 PPP over ATM/AAL5 */
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 */
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.
1163 + * This driver provides the encapsulation and framing for sending
1164 + * and receiving PPP frames in ATM AAL5 PDUs.
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
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>
1197 +#define DPRINTK(format, args...) \
1198 + printk(KERN_DEBUG "pppoatm: " format, ##args)
1200 +#define DPRINTK(format, args...)
1203 +enum pppoatm_encaps {
1204 + e_autodetect = PPPOATM_ENCAPS_AUTODETECT,
1205 + e_vc = PPPOATM_ENCAPS_VC,
1206 + e_llc = PPPOATM_ENCAPS_LLC,
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;
1221 + * Header used for LLC Encapsulated PPP (4 bytes) followed by the LCP protocol
1222 + * ID (0xC021) used in autodetection
1224 +static const unsigned char pppllc[6] = { 0xFE, 0xFE, 0x03, 0xCF, 0xC0, 0x21 };
1225 +#define LLC_LEN (4)
1227 +static inline struct pppoatm_vcc *atmvcc_to_pvcc(const struct atm_vcc *atmvcc)
1229 + return (struct pppoatm_vcc *) (atmvcc->user_back);
1232 +static inline struct pppoatm_vcc *chan_to_pvcc(const struct ppp_channel *chan)
1234 + return (struct pppoatm_vcc *) (chan->private);
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
1242 +static void pppoatm_wakeup_sender(unsigned long arg)
1244 + ppp_output_wakeup((struct ppp_channel *) arg);
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
1252 +static void pppoatm_pop(struct atm_vcc *atmvcc, struct sk_buff *skb)
1254 + struct pppoatm_vcc *pvcc = atmvcc_to_pvcc(atmvcc);
1255 + pvcc->old_pop(atmvcc, skb);
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.
1264 + tasklet_schedule(&pvcc->wakeup_tasklet);
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
1271 +static void pppoatm_unassign_vcc(struct atm_vcc *atmvcc)
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;
1281 + /* Gee, I hope we have the big kernel lock here... */
1282 + MOD_DEC_USE_COUNT;
1285 +/* Called when an AAL5 PDU comes in */
1286 +static void pppoatm_push(struct atm_vcc *atmvcc, struct sk_buff *skb)
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 */
1296 + atm_return(atmvcc, skb->truesize);
1297 + switch (pvcc->encaps) {
1299 + if (skb->len < LLC_LEN ||
1300 + memcmp(skb->data, pppllc, LLC_LEN))
1302 + skb_pull(skb, LLC_LEN);
1304 + case e_autodetect:
1305 + if (pvcc->chan.ppp == NULL) { /* Not bound yet! */
1309 + if (skb->len >= sizeof(pppllc) &&
1310 + !memcmp(skb->data, pppllc, sizeof(pppllc))) {
1311 + pvcc->encaps = e_llc;
1312 + skb_pull(skb, LLC_LEN);
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;
1322 + DPRINTK("(unit %d): Couldn't autodetect yet "
1323 + "(skb: %02X %02X %02X %02X %02X %02X)\n",
1325 + skb->data[0], skb->data[1], skb->data[2],
1326 + skb->data[3], skb->data[4], skb->data[5]);
1331 + ppp_input(&pvcc->chan, skb);
1335 + ppp_input_error(&pvcc->chan, 0);
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.
1347 +#define DROP_PACKET 1
1348 +static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb)
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 */
1358 + if (skb_headroom(skb) < LLC_LEN) {
1359 + struct sk_buff *n;
1360 + n = skb_realloc_headroom(skb, LLC_LEN);
1362 + !atm_may_send(pvcc->atmvcc, n->truesize)) {
1367 + if ((skb = n) == NULL)
1368 + return DROP_PACKET;
1369 + } else if (!atm_may_send(pvcc->atmvcc, skb->truesize))
1371 + memcpy(skb_push(skb, LLC_LEN), pppllc, LLC_LEN);
1374 + if (!atm_may_send(pvcc->atmvcc, skb->truesize))
1377 + case e_autodetect:
1378 + DPRINTK("(unit %d): Trying to send without setting encaps!\n",
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;
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
1396 + if ((pvcc->flags & SC_COMP_PROT) && skb_headroom(skb) > 0 &&
1397 + skb->data[-1] == '\0')
1398 + (void) skb_push(skb, 1);
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)
1407 + case PPPIOCGFLAGS:
1408 + return put_user(chan_to_pvcc(chan)->flags, (int *) arg)
1410 + case PPPIOCSFLAGS:
1411 + return get_user(chan_to_pvcc(chan)->flags, (int *) arg)
1417 +static /*const*/ struct ppp_channel_ops pppoatm_ops = {
1418 + start_xmit: pppoatm_send,
1419 + ioctl: pppoatm_devppp_ioctl,
1422 +static int pppoatm_assign_vcc(struct atm_vcc *atmvcc, unsigned long arg)
1424 + struct atm_backend_ppp be;
1425 + struct pppoatm_vcc *pvcc;
1428 + * Each PPPoATM instance has its own tasklet - this is just a
1429 + * prototypical one used to initialize them
1431 + static const DECLARE_TASKLET(tasklet_proto, pppoatm_wakeup_sender, 0);
1432 + if (copy_from_user(&be, (void *) arg, sizeof be))
1434 + if (be.encaps != PPPOATM_ENCAPS_AUTODETECT &&
1435 + be.encaps != PPPOATM_ENCAPS_VC && be.encaps != PPPOATM_ENCAPS_LLC)
1437 + MOD_INC_USE_COUNT;
1438 + pvcc = kmalloc(sizeof(*pvcc), GFP_KERNEL);
1439 + if (pvcc == NULL) {
1440 + MOD_DEC_USE_COUNT;
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) {
1458 + atmvcc->user_back = pvcc;
1459 + atmvcc->push = pppoatm_push;
1460 + atmvcc->pop = pppoatm_pop;
1465 + * This handles ioctls actually performed on our vcc - we must return
1466 + * -ENOIOCTLCMD for any unrecognized ioctl
1468 +static int pppoatm_ioctl(struct atm_vcc *atmvcc, unsigned int cmd,
1469 + unsigned long arg)
1472 + if (cmd != ATM_SETBACKEND && atmvcc->push != pppoatm_push)
1473 + return -ENOIOCTLCMD;
1475 + case ATM_SETBACKEND: {
1477 + MOD_INC_USE_COUNT;
1478 + err = get_user(b, (atm_backend_t *) arg);
1479 + MOD_DEC_USE_COUNT;
1482 + if (b != ATM_BACKEND_PPP)
1483 + return -ENOIOCTLCMD;
1484 + if (!capable(CAP_NET_ADMIN))
1486 + return pppoatm_assign_vcc(atmvcc, arg);
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),
1495 + MOD_DEC_USE_COUNT;
1496 + return err ? -EFAULT : 0;
1498 + return -ENOIOCTLCMD;
1501 +/* the following avoids some spurious warnings from the compiler */
1502 +#define UNUSED __attribute__((unused))
1504 +extern int (*pppoatm_ioctl_hook)(struct atm_vcc *,
1505 + unsigned int, unsigned long);
1507 +static int __init UNUSED pppoatm_init(void)
1509 + pppoatm_ioctl_hook = pppoatm_ioctl;
1513 +static void __exit UNUSED pppoatm_exit(void)
1515 + pppoatm_ioctl_hook = NULL;
1518 +module_init(pppoatm_init);
1519 +module_exit(pppoatm_exit);
1521 +MODULE_AUTHOR("Mitchell Blank Jr <mitch@sfgoth.com>");
1522 +MODULE_DESCRIPTION("RFC2364 PPP over ATM/AAL5");