Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
linux-davinci
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
linux
linux-davinci
Commits
c46920da
Commit
c46920da
authored
Nov 21, 2008
by
David S. Miller
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'for-david' of
git://git.kernel.org/pub/scm/linux/kernel/git/chris/linux-2.6
parents
f5f4cf08
6476a907
Changes
14
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
1379 additions
and
2066 deletions
+1379
-2066
Documentation/DocBook/Makefile
Documentation/DocBook/Makefile
+1
-1
Documentation/DocBook/networking.tmpl
Documentation/DocBook/networking.tmpl
+0
-3
Documentation/DocBook/wanbook.tmpl
Documentation/DocBook/wanbook.tmpl
+0
-99
Documentation/networking/generic-hdlc.txt
Documentation/networking/generic-hdlc.txt
+4
-4
drivers/net/wan/Makefile
drivers/net/wan/Makefile
+1
-1
drivers/net/wan/c101.c
drivers/net/wan/c101.c
+3
-3
drivers/net/wan/hd64570.c
drivers/net/wan/hd64570.c
+55
-199
drivers/net/wan/hd64572.c
drivers/net/wan/hd64572.c
+640
-0
drivers/net/wan/hdlc_ppp.c
drivers/net/wan/hdlc_ppp.c
+601
-47
drivers/net/wan/n2.c
drivers/net/wan/n2.c
+3
-6
drivers/net/wan/pc300too.c
drivers/net/wan/pc300too.c
+46
-73
drivers/net/wan/pci200syn.c
drivers/net/wan/pci200syn.c
+25
-52
drivers/net/wan/syncppp.c
drivers/net/wan/syncppp.c
+0
-1476
include/net/syncppp.h
include/net/syncppp.h
+0
-102
No files found.
Documentation/DocBook/Makefile
View file @
c46920da
...
...
@@ -6,7 +6,7 @@
# To add a new book the only step required is to add the book to the
# list of DOCBOOKS.
DOCBOOKS
:=
wanbook.xml
z8530book.xml mcabook.xml
\
DOCBOOKS
:=
z8530book.xml mcabook.xml
\
kernel-hacking.xml kernel-locking.xml deviceiobook.xml
\
procfs-guide.xml writing_usb_driver.xml networking.xml
\
kernel-api.xml filesystems.xml lsm.xml usb.xml kgdb.xml
\
...
...
Documentation/DocBook/networking.tmpl
View file @
c46920da
...
...
@@ -98,9 +98,6 @@
X!Enet/core/wireless.c
</sect1>
-->
<sect1><title>
Synchronous PPP
</title>
!Edrivers/net/wan/syncppp.c
</sect1>
</chapter>
</book>
Documentation/DocBook/wanbook.tmpl
deleted
100644 → 0
View file @
f5f4cf08
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
<book
id=
"WANGuide"
>
<bookinfo>
<title>
Synchronous PPP and Cisco HDLC Programming Guide
</title>
<authorgroup>
<author>
<firstname>
Alan
</firstname>
<surname>
Cox
</surname>
<affiliation>
<address>
<email>
alan@lxorguk.ukuu.org.uk
</email>
</address>
</affiliation>
</author>
</authorgroup>
<copyright>
<year>
2000
</year>
<holder>
Alan Cox
</holder>
</copyright>
<legalnotice>
<para>
This documentation is free software; you can redistribute
it and/or modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later
version.
</para>
<para>
This program is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
</para>
<para>
You should have received a copy of the GNU General Public
License along with this program; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
MA 02111-1307 USA
</para>
<para>
For more details see the file COPYING in the source
distribution of Linux.
</para>
</legalnotice>
</bookinfo>
<toc></toc>
<chapter
id=
"intro"
>
<title>
Introduction
</title>
<para>
The syncppp drivers in Linux provide a fairly complete
implementation of Cisco HDLC and a minimal implementation of
PPP. The longer term goal is to switch the PPP layer to the
generic PPP interface that is new in Linux 2.3.x. The API should
remain unchanged when this is done, but support will then be
available for IPX, compression and other PPP features
</para>
</chapter>
<chapter
id=
"bugs"
>
<title>
Known Bugs And Assumptions
</title>
<para>
<variablelist>
<varlistentry><term>
PPP is minimal
</term>
<listitem>
<para>
The current PPP implementation is very basic, although sufficient
for most wan usages.
</para>
</listitem></varlistentry>
<varlistentry><term>
Cisco HDLC Quirks
</term>
<listitem>
<para>
Currently we do not end all packets with the correct Cisco multicast
or unicast flags. Nothing appears to mind too much but this should
be corrected.
</para>
</listitem></varlistentry>
</variablelist>
</para>
</chapter>
<chapter
id=
"pubfunctions"
>
<title>
Public Functions Provided
</title>
!Edrivers/net/wan/syncppp.c
</chapter>
</book>
Documentation/networking/generic-hdlc.txt
View file @
c46920da
...
...
@@ -3,15 +3,15 @@ Krzysztof Halasa <khc@pm.waw.pl>
Generic HDLC layer currently supports:
1. Frame Relay (ANSI, CCITT, Cisco and no LMI)
.
1. Frame Relay (ANSI, CCITT, Cisco and no LMI)
- Normal (routed) and Ethernet-bridged (Ethernet device emulation)
interfaces can share a single PVC.
- ARP support (no InARP support in the kernel - there is an
experimental InARP user-space daemon available on:
http://www.kernel.org/pub/linux/utils/net/hdlc/).
2. raw HDLC - either IP (IPv4) interface or Ethernet device emulation
.
3. Cisco HDLC
.
4. PPP
(uses syncppp.c).
2. raw HDLC - either IP (IPv4) interface or Ethernet device emulation
3. Cisco HDLC
4. PPP
5. X.25 (uses X.25 routines).
Generic HDLC is a protocol driver only - it needs a low-level driver
...
...
drivers/net/wan/Makefile
View file @
c46920da
...
...
@@ -14,7 +14,7 @@ obj-$(CONFIG_HDLC_RAW) += hdlc_raw.o
obj-$(CONFIG_HDLC_RAW_ETH)
+=
hdlc_raw_eth.o
obj-$(CONFIG_HDLC_CISCO)
+=
hdlc_cisco.o
obj-$(CONFIG_HDLC_FR)
+=
hdlc_fr.o
obj-$(CONFIG_HDLC_PPP)
+=
hdlc_ppp.o
syncppp.o
obj-$(CONFIG_HDLC_PPP)
+=
hdlc_ppp.o
obj-$(CONFIG_HDLC_X25)
+=
hdlc_x25.o
pc300-y
:=
pc300_drv.o
...
...
drivers/net/wan/c101.c
View file @
c46920da
...
...
@@ -88,7 +88,7 @@ static card_t **new_card = &first_card;
/* EDA address register must be set in EDAL, EDAH order - 8 bit ISA bus */
#define sca_outw(value, reg, card) do { \
writeb(value & 0xFF, (card)->win0base + C101_SCA + (reg)); \
writeb((value >> 8 ) & 0xFF, (card)->win0base + C101_SCA + (reg
+
1));\
writeb((value >> 8 ) & 0xFF, (card)->win0base + C101_SCA + (reg
+
1));\
} while(0)
#define port_to_card(port) (port)
...
...
@@ -113,7 +113,7 @@ static inline void openwin(card_t *card, u8 page)
}
#include "hd6457
x
.c"
#include "hd6457
0
.c"
static
inline
void
set_carrier
(
port_t
*
port
)
...
...
@@ -381,7 +381,7 @@ static int __init c101_run(unsigned long irq, unsigned long winbase)
return
result
;
}
sca_init_
sync_
port
(
card
);
/* Set up C101 memory */
sca_init_port
(
card
);
/* Set up C101 memory */
set_carrier
(
card
);
printk
(
KERN_INFO
"%s: Moxa C101 on IRQ%u,"
...
...
drivers/net/wan/hd6457
x
.c
→
drivers/net/wan/hd6457
0
.c
View file @
c46920da
/*
* Hitachi SCA HD64570
and HD64572 common
driver for Linux
* Hitachi SCA HD64570 driver for Linux
*
* Copyright (C) 1998-2003 Krzysztof Halasa <khc@pm.waw.pl>
*
...
...
@@ -7,9 +7,7 @@
* under the terms of version 2 of the GNU General Public License
* as published by the Free Software Foundation.
*
* Sources of information:
* Hitachi HD64570 SCA User's Manual
* Hitachi HD64572 SCA-II User's Manual
* Source of information: Hitachi HD64570 SCA User's Manual
*
* We use the following SCA memory map:
*
...
...
@@ -26,33 +24,26 @@
* tx_ring_buffers * HDLC_MAX_MRU = logical channel #0 TX buffers (if used)
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/types.h>
#include <linux/bitops.h>
#include <linux/errno.h>
#include <linux/fcntl.h>
#include <linux/
interrupt
.h>
#include <linux/
hdlc
.h>
#include <linux/in.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/bitops.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/
hdlc
.h>
#i
f (!defined (__HD64570_H) && !defined (__HD64572_H)) || \
(defined (__HD64570_H) && defined (__HD64572_H))
#
error Either hd64570.h or hd64572.h must be included
#
endif
#include <linux/slab.h>
#include <linux/
string
.h>
#include <linux/types.h>
#i
nclude <asm/io.h>
#include <asm/system.h>
#
include <asm/uaccess.h>
#
include "hd64570.h"
#define get_msci(port) (phy_node(port) ? MSCI1_OFFSET : MSCI0_OFFSET)
#define get_dmac_rx(port) (phy_node(port) ? DMAC1RX_OFFSET : DMAC0RX_OFFSET)
...
...
@@ -62,16 +53,6 @@
#define SCA_INTR_DMAC_RX(node) (node ? 0x20 : 0x02)
#define SCA_INTR_DMAC_TX(node) (node ? 0x40 : 0x04)
#ifdef __HD64570_H
/* HD64570 */
#define sca_outa(value, reg, card) sca_outw(value, reg, card)
#define sca_ina(reg, card) sca_inw(reg, card)
#define writea(value, ptr) writew(value, ptr)
#else
/* HD64572 */
#define sca_outa(value, reg, card) sca_outl(value, reg, card)
#define sca_ina(reg, card) sca_inl(reg, card)
#define writea(value, ptr) writel(value, ptr)
#endif
static
inline
struct
net_device
*
port_to_dev
(
port_t
*
port
)
{
...
...
@@ -81,8 +62,6 @@ static inline struct net_device *port_to_dev(port_t *port)
static
inline
int
sca_intr_status
(
card_t
*
card
)
{
u8
result
=
0
;
#ifdef __HD64570_H
/* HD64570 */
u8
isr0
=
sca_in
(
ISR0
,
card
);
u8
isr1
=
sca_in
(
ISR1
,
card
);
...
...
@@ -93,18 +72,6 @@ static inline int sca_intr_status(card_t *card)
if
(
isr0
&
0x0F
)
result
|=
SCA_INTR_MSCI
(
0
);
if
(
isr0
&
0xF0
)
result
|=
SCA_INTR_MSCI
(
1
);
#else
/* HD64572 */
u32
isr0
=
sca_inl
(
ISR0
,
card
);
if
(
isr0
&
0x0000000F
)
result
|=
SCA_INTR_DMAC_RX
(
0
);
if
(
isr0
&
0x000000F0
)
result
|=
SCA_INTR_DMAC_TX
(
0
);
if
(
isr0
&
0x00000F00
)
result
|=
SCA_INTR_DMAC_RX
(
1
);
if
(
isr0
&
0x0000F000
)
result
|=
SCA_INTR_DMAC_TX
(
1
);
if
(
isr0
&
0x003E0000
)
result
|=
SCA_INTR_MSCI
(
0
);
if
(
isr0
&
0x3E000000
)
result
|=
SCA_INTR_MSCI
(
1
);
#endif
/* HD64570 vs HD64572 */
if
(
!
(
result
&
SCA_INTR_DMAC_TX
(
0
)))
if
(
sca_in
(
DSR_TX
(
0
),
card
)
&
DSR_EOM
)
result
|=
SCA_INTR_DMAC_TX
(
0
);
...
...
@@ -127,7 +94,6 @@ static inline u16 next_desc(port_t *port, u16 desc, int transmit)
}
static
inline
u16
desc_abs_number
(
port_t
*
port
,
u16
desc
,
int
transmit
)
{
u16
rx_buffs
=
port_to_card
(
port
)
->
rx_ring_buffers
;
...
...
@@ -139,28 +105,26 @@ static inline u16 desc_abs_number(port_t *port, u16 desc, int transmit)
}
static
inline
u16
desc_offset
(
port_t
*
port
,
u16
desc
,
int
transmit
)
{
/* Descriptor offset always fits in 16 b
yte
s */
/* Descriptor offset always fits in 16 b
it
s */
return
desc_abs_number
(
port
,
desc
,
transmit
)
*
sizeof
(
pkt_desc
);
}
static
inline
pkt_desc
__iomem
*
desc_address
(
port_t
*
port
,
u16
desc
,
int
transmit
)
static
inline
pkt_desc
__iomem
*
desc_address
(
port_t
*
port
,
u16
desc
,
int
transmit
)
{
#ifdef PAGE0_ALWAYS_MAPPED
return
(
pkt_desc
__iomem
*
)(
win0base
(
port_to_card
(
port
))
+
desc_offset
(
port
,
desc
,
transmit
));
+
desc_offset
(
port
,
desc
,
transmit
));
#else
return
(
pkt_desc
__iomem
*
)(
winbase
(
port_to_card
(
port
))
+
desc_offset
(
port
,
desc
,
transmit
));
+
desc_offset
(
port
,
desc
,
transmit
));
#endif
}
static
inline
u32
buffer_offset
(
port_t
*
port
,
u16
desc
,
int
transmit
)
{
return
port_to_card
(
port
)
->
buff_offset
+
...
...
@@ -186,7 +150,7 @@ static inline void sca_set_carrier(port_t *port)
}
static
void
sca_init_
sync_
port
(
port_t
*
port
)
static
void
sca_init_port
(
port_t
*
port
)
{
card_t
*
card
=
port_to_card
(
port
);
int
transmit
,
i
;
...
...
@@ -195,7 +159,7 @@ static void sca_init_sync_port(port_t *port)
port
->
txin
=
0
;
port
->
txlast
=
0
;
#if
!defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED)
#if
ndef PAGE0_ALWAYS_MAPPED
openwin
(
card
,
0
);
#endif
...
...
@@ -209,7 +173,7 @@ static void sca_init_sync_port(port_t *port)
u16
chain_off
=
desc_offset
(
port
,
i
+
1
,
transmit
);
u32
buff_off
=
buffer_offset
(
port
,
i
,
transmit
);
write
a
(
chain_off
,
&
desc
->
cp
);
write
w
(
chain_off
,
&
desc
->
cp
);
writel
(
buff_off
,
&
desc
->
bp
);
writew
(
0
,
&
desc
->
len
);
writeb
(
0
,
&
desc
->
stat
);
...
...
@@ -222,16 +186,14 @@ static void sca_init_sync_port(port_t *port)
sca_out
(
DCR_ABORT
,
transmit
?
DCR_TX
(
phy_node
(
port
))
:
DCR_RX
(
phy_node
(
port
)),
card
);
#ifdef __HD64570_H
sca_out
(
0
,
dmac
+
CPB
,
card
);
/* pointer base */
#endif
/* current desc addr */
sca_outa
(
desc_offset
(
port
,
0
,
transmit
),
dmac
+
CDAL
,
card
);
sca_out
(
0
,
dmac
+
CPB
,
card
);
/* pointer base */
sca_outw
(
desc_offset
(
port
,
0
,
transmit
),
dmac
+
CDAL
,
card
);
if
(
!
transmit
)
sca_out
a
(
desc_offset
(
port
,
buffs
-
1
,
transmit
),
sca_out
w
(
desc_offset
(
port
,
buffs
-
1
,
transmit
),
dmac
+
EDAL
,
card
);
else
sca_out
a
(
desc_offset
(
port
,
0
,
transmit
),
dmac
+
EDAL
,
sca_out
w
(
desc_offset
(
port
,
0
,
transmit
),
dmac
+
EDAL
,
card
);
/* clear frame end interrupt counter */
...
...
@@ -258,7 +220,6 @@ static void sca_init_sync_port(port_t *port)
}
#ifdef NEED_SCA_MSCI_INTR
/* MSCI interrupt service */
static
inline
void
sca_msci_intr
(
port_t
*
port
)
...
...
@@ -282,17 +243,15 @@ static inline void sca_msci_intr(port_t *port)
#endif
static
inline
void
sca_rx
(
card_t
*
card
,
port_t
*
port
,
pkt_desc
__iomem
*
desc
,
u16
rxin
)
static
inline
void
sca_rx
(
card_t
*
card
,
port_t
*
port
,
pkt_desc
__iomem
*
desc
,
u16
rxin
)
{
struct
net_device
*
dev
=
port_to_dev
(
port
);
struct
sk_buff
*
skb
;
u16
len
;
u32
buff
;
#ifndef ALL_PAGES_ALWAYS_MAPPED
u32
maxlen
;
u8
page
;
#endif
len
=
readw
(
&
desc
->
len
);
skb
=
dev_alloc_skb
(
len
);
...
...
@@ -302,7 +261,6 @@ static inline void sca_rx(card_t *card, port_t *port, pkt_desc __iomem *desc, u1
}
buff
=
buffer_offset
(
port
,
rxin
,
0
);
#ifndef ALL_PAGES_ALWAYS_MAPPED
page
=
buff
/
winsize
(
card
);
buff
=
buff
%
winsize
(
card
);
maxlen
=
winsize
(
card
)
-
buff
;
...
...
@@ -314,12 +272,10 @@ static inline void sca_rx(card_t *card, port_t *port, pkt_desc __iomem *desc, u1
openwin
(
card
,
page
+
1
);
memcpy_fromio
(
skb
->
data
+
maxlen
,
winbase
(
card
),
len
-
maxlen
);
}
else
#endif
memcpy_fromio
(
skb
->
data
,
winbase
(
card
)
+
buff
,
len
);
memcpy_fromio
(
skb
->
data
,
winbase
(
card
)
+
buff
,
len
);
#if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED)
/* select pkt_desc table page back */
openwin
(
card
,
0
);
#ifndef PAGE0_ALWAYS_MAPPED
openwin
(
card
,
0
);
/* select pkt_desc table page back */
#endif
skb_put
(
skb
,
len
);
#ifdef DEBUG_PKT
...
...
@@ -333,7 +289,6 @@ static inline void sca_rx(card_t *card, port_t *port, pkt_desc __iomem *desc, u1
}
/* Receive DMA interrupt service */
static
inline
void
sca_rx_intr
(
port_t
*
port
)
{
...
...
@@ -353,7 +308,7 @@ static inline void sca_rx_intr(port_t *port)
while
(
1
)
{
u32
desc_off
=
desc_offset
(
port
,
port
->
rxin
,
0
);
pkt_desc
__iomem
*
desc
;
u32
cda
=
sca_in
a
(
dmac
+
CDAL
,
card
);
u32
cda
=
sca_in
w
(
dmac
+
CDAL
,
card
);
if
((
cda
>=
desc_off
)
&&
(
cda
<
desc_off
+
sizeof
(
pkt_desc
)))
break
;
/* No frame received */
...
...
@@ -377,7 +332,7 @@ static inline void sca_rx_intr(port_t *port)
sca_rx
(
card
,
port
,
desc
,
port
->
rxin
);
/* Set new error descriptor address */
sca_out
a
(
desc_off
,
dmac
+
EDAL
,
card
);
sca_out
w
(
desc_off
,
dmac
+
EDAL
,
card
);
port
->
rxin
=
next_desc
(
port
,
port
->
rxin
,
0
);
}
...
...
@@ -386,7 +341,6 @@ static inline void sca_rx_intr(port_t *port)
}
/* Transmit DMA interrupt service */
static
inline
void
sca_tx_intr
(
port_t
*
port
)
{
...
...
@@ -407,7 +361,7 @@ static inline void sca_tx_intr(port_t *port)
pkt_desc
__iomem
*
desc
;
u32
desc_off
=
desc_offset
(
port
,
port
->
txlast
,
1
);
u32
cda
=
sca_in
a
(
dmac
+
CDAL
,
card
);
u32
cda
=
sca_in
w
(
dmac
+
CDAL
,
card
);
if
((
cda
>=
desc_off
)
&&
(
cda
<
desc_off
+
sizeof
(
pkt_desc
)))
break
;
/* Transmitter is/will_be sending this frame */
...
...
@@ -423,17 +377,13 @@ static inline void sca_tx_intr(port_t *port)
}
static
irqreturn_t
sca_intr
(
int
irq
,
void
*
dev_id
)
{
card_t
*
card
=
dev_id
;
int
i
;
u8
stat
;
int
handled
=
0
;
#ifndef ALL_PAGES_ALWAYS_MAPPED
u8
page
=
sca_get_page
(
card
);
#endif
while
((
stat
=
sca_intr_status
(
card
))
!=
0
)
{
handled
=
1
;
...
...
@@ -452,14 +402,11 @@ static irqreturn_t sca_intr(int irq, void* dev_id)
}
}
#ifndef ALL_PAGES_ALWAYS_MAPPED
openwin
(
card
,
page
);
/* Restore original page */
#endif
return
IRQ_RETVAL
(
handled
);
}
static
void
sca_set_port
(
port_t
*
port
)
{
card_t
*
card
=
port_to_card
(
port
);
...
...
@@ -497,12 +444,7 @@ static void sca_set_port(port_t *port)
port
->
tmc
=
tmc
;
/* baud divisor - time constant*/
#ifdef __HD64570_H
sca_out
(
port
->
tmc
,
msci
+
TMC
,
card
);
#else
sca_out
(
port
->
tmc
,
msci
+
TMCR
,
card
);
sca_out
(
port
->
tmc
,
msci
+
TMCT
,
card
);
#endif
/* Set BRG bits */
sca_out
(
port
->
rxs
,
msci
+
RXS
,
card
);
...
...
@@ -518,7 +460,6 @@ static void sca_set_port(port_t *port)
}
static
void
sca_open
(
struct
net_device
*
dev
)
{
port_t
*
port
=
dev_to_port
(
dev
);
...
...
@@ -540,11 +481,7 @@ static void sca_open(struct net_device *dev)
switch
(
port
->
parity
)
{
case
PARITY_CRC16_PR0
:
md0
=
MD0_HDLC
|
MD0_CRC_16_0
;
break
;
case
PARITY_CRC16_PR1
:
md0
=
MD0_HDLC
|
MD0_CRC_16
;
break
;
#ifdef __HD64570_H
case
PARITY_CRC16_PR0_CCITT
:
md0
=
MD0_HDLC
|
MD0_CRC_ITU_0
;
break
;
#else
case
PARITY_CRC32_PR1_CCITT
:
md0
=
MD0_HDLC
|
MD0_CRC_ITU32
;
break
;
#endif
case
PARITY_CRC16_PR1_CCITT
:
md0
=
MD0_HDLC
|
MD0_CRC_ITU
;
break
;
default:
md0
=
MD0_HDLC
|
MD0_CRC_NONE
;
}
...
...
@@ -554,35 +491,20 @@ static void sca_open(struct net_device *dev)
sca_out
(
0x00
,
msci
+
MD1
,
card
);
/* no address field check */
sca_out
(
md2
,
msci
+
MD2
,
card
);
sca_out
(
0x7E
,
msci
+
IDL
,
card
);
/* flag character 0x7E */
#ifdef __HD64570_H
sca_out
(
CTL_IDLE
,
msci
+
CTL
,
card
);
#else
/* Skip the rest of underrun frame */
sca_out
(
CTL_IDLE
|
CTL_URCT
|
CTL_URSKP
,
msci
+
CTL
,
card
);
#endif
#ifdef __HD64570_H
/* Allow at least 8 bytes before requesting RX DMA operation */
/* TX with higher priority and possibly with shorter transfers */
sca_out
(
0x07
,
msci
+
RRC
,
card
);
/* +1=RXRDY/DMA activation condition*/
sca_out
(
0x10
,
msci
+
TRC0
,
card
);
/* = TXRDY/DMA activation condition*/
sca_out
(
0x14
,
msci
+
TRC1
,
card
);
/* +1=TXRDY/DMA deactiv condition */
#else
sca_out
(
0x0F
,
msci
+
RNR
,
card
);
/* +1=RX DMA activation condition */
sca_out
(
0x3C
,
msci
+
TFS
,
card
);
/* +1 = TX start */
sca_out
(
0x38
,
msci
+
TCR
,
card
);
/* =Critical TX DMA activ condition */
sca_out
(
0x38
,
msci
+
TNR0
,
card
);
/* =TX DMA activation condition */
sca_out
(
0x3F
,
msci
+
TNR1
,
card
);
/* +1=TX DMA deactivation condition*/
#endif
/* We're using the following interrupts:
- TXINT (DMAC completed all transmisions, underrun or DCD change)
- all DMA interrupts
*/
sca_set_carrier
(
port
);
#ifdef __HD64570_H
/* MSCI TX INT and RX INT A IRQ enable */
sca_out
(
IE0_TXINT
|
IE0_RXINTA
,
msci
+
IE0
,
card
);
sca_out
(
IE1_UDRN
|
IE1_CDCD
,
msci
+
IE1
,
card
);
...
...
@@ -591,21 +513,8 @@ static void sca_open(struct net_device *dev)
/* enable DMA IRQ */
sca_out
(
sca_in
(
IER1
,
card
)
|
(
phy_node
(
port
)
?
0xF0
:
0x0F
),
IER1
,
card
);
#else
/* MSCI TXINT and RXINTA interrupt enable */
sca_outl
(
IE0_TXINT
|
IE0_RXINTA
|
IE0_UDRN
|
IE0_CDCD
,
msci
+
IE0
,
card
);
/* DMA & MSCI IRQ enable */
sca_outl
(
sca_inl
(
IER0
,
card
)
|
(
phy_node
(
port
)
?
0x0A006600
:
0x000A0066
),
IER0
,
card
);
#endif
#ifdef __HD64570_H
sca_out
(
port
->
tmc
,
msci
+
TMC
,
card
);
/* Restore registers */
#else
sca_out
(
port
->
tmc
,
msci
+
TMCR
,
card
);
sca_out
(
port
->
tmc
,
msci
+
TMCT
,
card
);
#endif
sca_out
(
port
->
rxs
,
msci
+
RXS
,
card
);
sca_out
(
port
->
txs
,
msci
+
TXS
,
card
);
sca_out
(
CMD_TX_ENABLE
,
msci
+
CMD
,
card
);
...
...
@@ -615,7 +524,6 @@ static void sca_open(struct net_device *dev)
}
static
void
sca_close
(
struct
net_device
*
dev
)
{
port_t
*
port
=
dev_to_port
(
dev
);
...
...
@@ -623,23 +531,17 @@ static void sca_close(struct net_device *dev)
/* reset channel */
sca_out
(
CMD_RESET
,
get_msci
(
port
)
+
CMD
,
port_to_card
(
port
));
#ifdef __HD64570_H
/* disable MSCI interrupts */
sca_out
(
sca_in
(
IER0
,
card
)
&
(
phy_node
(
port
)
?
0x0F
:
0xF0
),
IER0
,
card
);
/* disable DMA interrupts */
sca_out
(
sca_in
(
IER1
,
card
)
&
(
phy_node
(
port
)
?
0x0F
:
0xF0
),
IER1
,
card
);
#else
/* disable DMA & MSCI IRQ */
sca_outl
(
sca_inl
(
IER0
,
card
)
&
(
phy_node
(
port
)
?
0x00FF00FF
:
0xFF00FF00
),
IER0
,
card
);
#endif
netif_stop_queue
(
dev
);
}
static
int
sca_attach
(
struct
net_device
*
dev
,
unsigned
short
encoding
,
unsigned
short
parity
)
{
...
...
@@ -653,11 +555,7 @@ static int sca_attach(struct net_device *dev, unsigned short encoding,
if
(
parity
!=
PARITY_NONE
&&
parity
!=
PARITY_CRC16_PR0
&&
parity
!=
PARITY_CRC16_PR1
&&
#ifdef __HD64570_H
parity
!=
PARITY_CRC16_PR0_CCITT
&&
#else
parity
!=
PARITY_CRC32_PR1_CCITT
&&
#endif
parity
!=
PARITY_CRC16_PR1_CCITT
)
return
-
EINVAL
;
...
...
@@ -667,34 +565,30 @@ static int sca_attach(struct net_device *dev, unsigned short encoding,
}
#ifdef DEBUG_RINGS
static
void
sca_dump_rings
(
struct
net_device
*
dev
)
{
port_t
*
port
=
dev_to_port
(
dev
);
card_t
*
card
=
port_to_card
(
port
);
u16
cnt
;
#if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED)
u8
page
;
#endif
#ifndef PAGE0_ALWAYS_MAPPED
u8
page
=
sca_get_page
(
card
);
#if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED)
page
=
sca_get_page
(
card
);
openwin
(
card
,
0
);
#endif
printk
(
KERN_DEBUG
"RX ring: CDA=%u EDA=%u DSR=%02X in=%u %sactive"
,
sca_in
a
(
get_dmac_rx
(
port
)
+
CDAL
,
card
),
sca_in
a
(
get_dmac_rx
(
port
)
+
EDAL
,
card
),
sca_in
w
(
get_dmac_rx
(
port
)
+
CDAL
,
card
),
sca_in
w
(
get_dmac_rx
(
port
)
+
EDAL
,
card
),
sca_in
(
DSR_RX
(
phy_node
(
port
)),
card
),
port
->
rxin
,
sca_in
(
DSR_RX
(
phy_node
(
port
)),
card
)
&
DSR_DE
?
""
:
"in"
);
sca_in
(
DSR_RX
(
phy_node
(
port
)),
card
)
&
DSR_DE
?
""
:
"in"
);
for
(
cnt
=
0
;
cnt
<
port_to_card
(
port
)
->
rx_ring_buffers
;
cnt
++
)
printk
(
" %02X"
,
readb
(
&
(
desc_address
(
port
,
cnt
,
0
)
->
stat
)));
printk
(
"
\n
"
KERN_DEBUG
"TX ring: CDA=%u EDA=%u DSR=%02X in=%u "
"last=%u %sactive"
,
sca_in
a
(
get_dmac_tx
(
port
)
+
CDAL
,
card
),
sca_in
a
(
get_dmac_tx
(
port
)
+
EDAL
,
card
),
sca_in
w
(
get_dmac_tx
(
port
)
+
CDAL
,
card
),
sca_in
w
(
get_dmac_tx
(
port
)
+
EDAL
,
card
),
sca_in
(
DSR_TX
(
phy_node
(
port
)),
card
),
port
->
txin
,
port
->
txlast
,
sca_in
(
DSR_TX
(
phy_node
(
port
)),
card
)
&
DSR_DE
?
""
:
"in"
);
...
...
@@ -702,12 +596,8 @@ static void sca_dump_rings(struct net_device *dev)
printk
(
" %02X"
,
readb
(
&
(
desc_address
(
port
,
cnt
,
1
)
->
stat
)));
printk
(
"
\n
"
);
printk
(
KERN_DEBUG
"MSCI: MD: %02x %02x %02x, "
"ST: %02x %02x %02x %02x"
#ifdef __HD64572_H
" %02x"
#endif
", FST: %02x CST: %02x %02x
\n
"
,
printk
(
KERN_DEBUG
"MSCI: MD: %02x %02x %02x, ST: %02x %02x %02x %02x,"
" FST: %02x CST: %02x %02x
\n
"
,
sca_in
(
get_msci
(
port
)
+
MD0
,
card
),
sca_in
(
get_msci
(
port
)
+
MD1
,
card
),
sca_in
(
get_msci
(
port
)
+
MD2
,
card
),
...
...
@@ -715,52 +605,33 @@ static void sca_dump_rings(struct net_device *dev)
sca_in
(
get_msci
(
port
)
+
ST1
,
card
),
sca_in
(
get_msci
(
port
)
+
ST2
,
card
),
sca_in
(
get_msci
(
port
)
+
ST3
,
card
),
#ifdef __HD64572_H
sca_in
(
get_msci
(
port
)
+
ST4
,
card
),
#endif
sca_in
(
get_msci
(
port
)
+
FST
,
card
),
sca_in
(
get_msci
(
port
)
+
CST0
,
card
),
sca_in
(
get_msci
(
port
)
+
CST1
,
card
));
#ifdef __HD64572_H
printk
(
KERN_DEBUG
"ILAR: %02x ISR: %08x %08x
\n
"
,
sca_in
(
ILAR
,
card
),
sca_inl
(
ISR0
,
card
),
sca_inl
(
ISR1
,
card
));
#else
printk
(
KERN_DEBUG
"ISR: %02x %02x %02x
\n
"
,
sca_in
(
ISR0
,
card
),
sca_in
(
ISR1
,
card
),
sca_in
(
ISR2
,
card
));
#endif
#if
!defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED)
#if
ndef PAGE0_ALWAYS_MAPPED
openwin
(
card
,
page
);
/* Restore original page */
#endif
}
#endif
/* DEBUG_RINGS */
static
int
sca_xmit
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
)
{
port_t
*
port
=
dev_to_port
(
dev
);
card_t
*
card
=
port_to_card
(
port
);
pkt_desc
__iomem
*
desc
;
u32
buff
,
len
;
#ifndef ALL_PAGES_ALWAYS_MAPPED
u8
page
;
u32
maxlen
;
#endif
spin_lock_irq
(
&
port
->
lock
);
desc
=
desc_address
(
port
,
port
->
txin
+
1
,
1
);
if
(
readb
(
&
desc
->
stat
))
{
/* allow 1 packet gap */
/* should never happen - previous xmit should stop queue */
#ifdef DEBUG_PKT
printk
(
KERN_DEBUG
"%s: transmitter buffer full
\n
"
,
dev
->
name
);
#endif
netif_stop_queue
(
dev
);
spin_unlock_irq
(
&
port
->
lock
);
return
1
;
/* request packet to be queued */
}
BUG_ON
(
readb
(
&
desc
->
stat
));
/* previous xmit should stop queue */
#ifdef DEBUG_PKT
printk
(
KERN_DEBUG
"%s TX(%i):"
,
dev
->
name
,
skb
->
len
);
...
...
@@ -770,7 +641,6 @@ static int sca_xmit(struct sk_buff *skb, struct net_device *dev)
desc
=
desc_address
(
port
,
port
->
txin
,
1
);
buff
=
buffer_offset
(
port
,
port
->
txin
,
1
);
len
=
skb
->
len
;
#ifndef ALL_PAGES_ALWAYS_MAPPED
page
=
buff
/
winsize
(
card
);
buff
=
buff
%
winsize
(
card
);
maxlen
=
winsize
(
card
)
-
buff
;
...
...
@@ -780,12 +650,10 @@ static int sca_xmit(struct sk_buff *skb, struct net_device *dev)
memcpy_toio
(
winbase
(
card
)
+
buff
,
skb
->
data
,
maxlen
);
openwin
(
card
,
page
+
1
);
memcpy_toio
(
winbase
(
card
),
skb
->
data
+
maxlen
,
len
-
maxlen
);
}
else
#endif
}
else
memcpy_toio
(
winbase
(
card
)
+
buff
,
skb
->
data
,
len
);
#if
!defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED)
#if
ndef PAGE0_ALWAYS_MAPPED
openwin
(
card
,
0
);
/* select pkt_desc table page back */
#endif
writew
(
len
,
&
desc
->
len
);
...
...
@@ -793,7 +661,7 @@ static int sca_xmit(struct sk_buff *skb, struct net_device *dev)
dev
->
trans_start
=
jiffies
;
port
->
txin
=
next_desc
(
port
,
port
->
txin
,
1
);
sca_out
a
(
desc_offset
(
port
,
port
->
txin
,
1
),
sca_out
w
(
desc_offset
(
port
,
port
->
txin
,
1
),
get_dmac_tx
(
port
)
+
EDAL
,
card
);
sca_out
(
DSR_DE
,
DSR_TX
(
phy_node
(
port
)),
card
);
/* Enable TX DMA */
...
...
@@ -809,40 +677,29 @@ static int sca_xmit(struct sk_buff *skb, struct net_device *dev)
}
#ifdef NEED_DETECT_RAM
static
u32
__devinit
sca_detect_ram
(
card_t
*
card
,
u8
__iomem
*
rambase
,
u32
ramsize
)
static
u32
__devinit
sca_detect_ram
(
card_t
*
card
,
u8
__iomem
*
rambase
,
u32
ramsize
)
{
/* Round RAM size to 32 bits, fill from end to start */
u32
i
=
ramsize
&=
~
3
;
#ifndef ALL_PAGES_ALWAYS_MAPPED
u32
size
=
winsize
(
card
);
openwin
(
card
,
(
i
-
4
)
/
size
);
/* select last window */
#endif
do
{
i
-=
4
;
#ifndef ALL_PAGES_ALWAYS_MAPPED
if
((
i
+
4
)
%
size
==
0
)
openwin
(
card
,
i
/
size
);
writel
(
i
^
0x12345678
,
rambase
+
i
%
size
);
#else
writel
(
i
^
0x12345678
,
rambase
+
i
);
#endif
}
while
(
i
>
0
);
}
while
(
i
>
0
);
for
(
i
=
0
;
i
<
ramsize
;
i
+=
4
)
{
#ifndef ALL_PAGES_ALWAYS_MAPPED
if
(
i
%
size
==
0
)
openwin
(
card
,
i
/
size
);
if
(
readl
(
rambase
+
i
%
size
)
!=
(
i
^
0x12345678
))
break
;
#else
if
(
readl
(
rambase
+
i
)
!=
(
i
^
0x12345678
))
break
;
#endif
}
return
i
;
...
...
@@ -850,7 +707,6 @@ static u32 __devinit sca_detect_ram(card_t *card, u8 __iomem *rambase, u32 ramsi
#endif
/* NEED_DETECT_RAM */
static
void
__devinit
sca_init
(
card_t
*
card
,
int
wait_states
)
{
sca_out
(
wait_states
,
WCRL
,
card
);
/* Wait Control */
...
...
drivers/net/wan/hd64572.c
0 → 100644
View file @
c46920da
/*
* Hitachi (now Renesas) SCA-II HD64572 driver for Linux
*
* Copyright (C) 1998-2008 Krzysztof Halasa <khc@pm.waw.pl>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License
* as published by the Free Software Foundation.
*
* Source of information: HD64572 SCA-II User's Manual
*
* We use the following SCA memory map:
*
* Packet buffer descriptor rings - starting from card->rambase:
* rx_ring_buffers * sizeof(pkt_desc) = logical channel #0 RX ring
* tx_ring_buffers * sizeof(pkt_desc) = logical channel #0 TX ring
* rx_ring_buffers * sizeof(pkt_desc) = logical channel #1 RX ring (if used)
* tx_ring_buffers * sizeof(pkt_desc) = logical channel #1 TX ring (if used)
*
* Packet data buffers - starting from card->rambase + buff_offset:
* rx_ring_buffers * HDLC_MAX_MRU = logical channel #0 RX buffers
* tx_ring_buffers * HDLC_MAX_MRU = logical channel #0 TX buffers
* rx_ring_buffers * HDLC_MAX_MRU = logical channel #0 RX buffers (if used)
* tx_ring_buffers * HDLC_MAX_MRU = logical channel #0 TX buffers (if used)
*/
#include <linux/bitops.h>
#include <linux/errno.h>
#include <linux/fcntl.h>
#include <linux/hdlc.h>
#include <linux/in.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/types.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include "hd64572.h"
#define NAPI_WEIGHT 16
#define get_msci(port) (port->chan ? MSCI1_OFFSET : MSCI0_OFFSET)
#define get_dmac_rx(port) (port->chan ? DMAC1RX_OFFSET : DMAC0RX_OFFSET)
#define get_dmac_tx(port) (port->chan ? DMAC1TX_OFFSET : DMAC0TX_OFFSET)
#define sca_in(reg, card) readb(card->scabase + (reg))
#define sca_out(value, reg, card) writeb(value, card->scabase + (reg))
#define sca_inw(reg, card) readw(card->scabase + (reg))
#define sca_outw(value, reg, card) writew(value, card->scabase + (reg))
#define sca_inl(reg, card) readl(card->scabase + (reg))
#define sca_outl(value, reg, card) writel(value, card->scabase + (reg))
static
int
sca_poll
(
struct
napi_struct
*
napi
,
int
budget
);
static
inline
port_t
*
dev_to_port
(
struct
net_device
*
dev
)
{
return
dev_to_hdlc
(
dev
)
->
priv
;
}
static
inline
void
enable_intr
(
port_t
*
port
)
{
/* enable DMIB and MSCI RXINTA interrupts */
sca_outl
(
sca_inl
(
IER0
,
port
->
card
)
|
(
port
->
chan
?
0x08002200
:
0x00080022
),
IER0
,
port
->
card
);
}
static
inline
void
disable_intr
(
port_t
*
port
)
{
sca_outl
(
sca_inl
(
IER0
,
port
->
card
)
&
(
port
->
chan
?
0x00FF00FF
:
0xFF00FF00
),
IER0
,
port
->
card
);
}
static
inline
u16
desc_abs_number
(
port_t
*
port
,
u16
desc
,
int
transmit
)
{
u16
rx_buffs
=
port
->
card
->
rx_ring_buffers
;
u16
tx_buffs
=
port
->
card
->
tx_ring_buffers
;
desc
%=
(
transmit
?
tx_buffs
:
rx_buffs
);
// called with "X + 1" etc.
return
port
->
chan
*
(
rx_buffs
+
tx_buffs
)
+
transmit
*
rx_buffs
+
desc
;
}
static
inline
u16
desc_offset
(
port_t
*
port
,
u16
desc
,
int
transmit
)
{
/* Descriptor offset always fits in 16 bits */
return
desc_abs_number
(
port
,
desc
,
transmit
)
*
sizeof
(
pkt_desc
);
}
static
inline
pkt_desc
__iomem
*
desc_address
(
port_t
*
port
,
u16
desc
,
int
transmit
)
{
return
(
pkt_desc
__iomem
*
)(
port
->
card
->
rambase
+
desc_offset
(
port
,
desc
,
transmit
));
}
static
inline
u32
buffer_offset
(
port_t
*
port
,
u16
desc
,
int
transmit
)
{
return
port
->
card
->
buff_offset
+
desc_abs_number
(
port
,
desc
,
transmit
)
*
(
u32
)
HDLC_MAX_MRU
;
}
static
inline
void
sca_set_carrier
(
port_t
*
port
)
{
if
(
!
(
sca_in
(
get_msci
(
port
)
+
ST3
,
port
->
card
)
&
ST3_DCD
))
{
#ifdef DEBUG_LINK
printk
(
KERN_DEBUG
"%s: sca_set_carrier on
\n
"
,
port
->
netdev
.
name
);
#endif
netif_carrier_on
(
port
->
netdev
);
}
else
{
#ifdef DEBUG_LINK
printk
(
KERN_DEBUG
"%s: sca_set_carrier off
\n
"
,
port
->
netdev
.
name
);
#endif
netif_carrier_off
(
port
->
netdev
);
}
}
static
void
sca_init_port
(
port_t
*
port
)
{
card_t
*
card
=
port
->
card
;
u16
dmac_rx
=
get_dmac_rx
(
port
),
dmac_tx
=
get_dmac_tx
(
port
);
int
transmit
,
i
;
port
->
rxin
=
0
;
port
->
txin
=
0
;
port
->
txlast
=
0
;
for
(
transmit
=
0
;
transmit
<
2
;
transmit
++
)
{
u16
buffs
=
transmit
?
card
->
tx_ring_buffers
:
card
->
rx_ring_buffers
;
for
(
i
=
0
;
i
<
buffs
;
i
++
)
{
pkt_desc
__iomem
*
desc
=
desc_address
(
port
,
i
,
transmit
);
u16
chain_off
=
desc_offset
(
port
,
i
+
1
,
transmit
);
u32
buff_off
=
buffer_offset
(
port
,
i
,
transmit
);
writel
(
chain_off
,
&
desc
->
cp
);
writel
(
buff_off
,
&
desc
->
bp
);
writew
(
0
,
&
desc
->
len
);
writeb
(
0
,
&
desc
->
stat
);
}
}
/* DMA disable - to halt state */
sca_out
(
0
,
DSR_RX
(
port
->
chan
),
card
);
sca_out
(
0
,
DSR_TX
(
port
->
chan
),
card
);
/* software ABORT - to initial state */
sca_out
(
DCR_ABORT
,
DCR_RX
(
port
->
chan
),
card
);
sca_out
(
DCR_ABORT
,
DCR_TX
(
port
->
chan
),
card
);
/* current desc addr */
sca_outl
(
desc_offset
(
port
,
0
,
0
),
dmac_rx
+
CDAL
,
card
);
sca_outl
(
desc_offset
(
port
,
card
->
tx_ring_buffers
-
1
,
0
),
dmac_rx
+
EDAL
,
card
);
sca_outl
(
desc_offset
(
port
,
0
,
1
),
dmac_tx
+
CDAL
,
card
);
sca_outl
(
desc_offset
(
port
,
0
,
1
),
dmac_tx
+
EDAL
,
card
);
/* clear frame end interrupt counter */
sca_out
(
DCR_CLEAR_EOF
,
DCR_RX
(
port
->
chan
),
card
);
sca_out
(
DCR_CLEAR_EOF
,
DCR_TX
(
port
->
chan
),
card
);
/* Receive */
sca_outw
(
HDLC_MAX_MRU
,
dmac_rx
+
BFLL
,
card
);
/* set buffer length */
sca_out
(
0x14
,
DMR_RX
(
port
->
chan
),
card
);
/* Chain mode, Multi-frame */
sca_out
(
DIR_EOME
,
DIR_RX
(
port
->
chan
),
card
);
/* enable interrupts */
sca_out
(
DSR_DE
,
DSR_RX
(
port
->
chan
),
card
);
/* DMA enable */
/* Transmit */
sca_out
(
0x14
,
DMR_TX
(
port
->
chan
),
card
);
/* Chain mode, Multi-frame */
sca_out
(
DIR_EOME
,
DIR_TX
(
port
->
chan
),
card
);
/* enable interrupts */
sca_set_carrier
(
port
);
netif_napi_add
(
port
->
netdev
,
&
port
->
napi
,
sca_poll
,
NAPI_WEIGHT
);
}
/* MSCI interrupt service */
static
inline
void
sca_msci_intr
(
port_t
*
port
)
{
u16
msci
=
get_msci
(
port
);
card_t
*
card
=
port
->
card
;
if
(
sca_in
(
msci
+
ST1
,
card
)
&
ST1_CDCD
)
{
/* Reset MSCI CDCD status bit */
sca_out
(
ST1_CDCD
,
msci
+
ST1
,
card
);
sca_set_carrier
(
port
);
}
}
static
inline
void
sca_rx
(
card_t
*
card
,
port_t
*
port
,
pkt_desc
__iomem
*
desc
,
u16
rxin
)
{
struct
net_device
*
dev
=
port
->
netdev
;
struct
sk_buff
*
skb
;
u16
len
;
u32
buff
;
len
=
readw
(
&
desc
->
len
);
skb
=
dev_alloc_skb
(
len
);
if
(
!
skb
)
{
dev
->
stats
.
rx_dropped
++
;
return
;
}
buff
=
buffer_offset
(
port
,
rxin
,
0
);
memcpy_fromio
(
skb
->
data
,
card
->
rambase
+
buff
,
len
);
skb_put
(
skb
,
len
);
#ifdef DEBUG_PKT
printk
(
KERN_DEBUG
"%s RX(%i):"
,
dev
->
name
,
skb
->
len
);
debug_frame
(
skb
);
#endif
dev
->
stats
.
rx_packets
++
;
dev
->
stats
.
rx_bytes
+=
skb
->
len
;
skb
->
protocol
=
hdlc_type_trans
(
skb
,
dev
);
netif_receive_skb
(
skb
);
}
/* Receive DMA service */
static
inline
int
sca_rx_done
(
port_t
*
port
,
int
budget
)
{
struct
net_device
*
dev
=
port
->
netdev
;
u16
dmac
=
get_dmac_rx
(
port
);
card_t
*
card
=
port
->
card
;
u8
stat
=
sca_in
(
DSR_RX
(
port
->
chan
),
card
);
/* read DMA Status */
int
received
=
0
;
/* Reset DSR status bits */
sca_out
((
stat
&
(
DSR_EOT
|
DSR_EOM
|
DSR_BOF
|
DSR_COF
))
|
DSR_DWE
,
DSR_RX
(
port
->
chan
),
card
);
if
(
stat
&
DSR_BOF
)
/* Dropped one or more frames */
dev
->
stats
.
rx_over_errors
++
;
while
(
received
<
budget
)
{
u32
desc_off
=
desc_offset
(
port
,
port
->
rxin
,
0
);
pkt_desc
__iomem
*
desc
;
u32
cda
=
sca_inl
(
dmac
+
CDAL
,
card
);
if
((
cda
>=
desc_off
)
&&
(
cda
<
desc_off
+
sizeof
(
pkt_desc
)))
break
;
/* No frame received */
desc
=
desc_address
(
port
,
port
->
rxin
,
0
);
stat
=
readb
(
&
desc
->
stat
);
if
(
!
(
stat
&
ST_RX_EOM
))
port
->
rxpart
=
1
;
/* partial frame received */
else
if
((
stat
&
ST_ERROR_MASK
)
||
port
->
rxpart
)
{
dev
->
stats
.
rx_errors
++
;
if
(
stat
&
ST_RX_OVERRUN
)
dev
->
stats
.
rx_fifo_errors
++
;
else
if
((
stat
&
(
ST_RX_SHORT
|
ST_RX_ABORT
|
ST_RX_RESBIT
))
||
port
->
rxpart
)
dev
->
stats
.
rx_frame_errors
++
;
else
if
(
stat
&
ST_RX_CRC
)
dev
->
stats
.
rx_crc_errors
++
;
if
(
stat
&
ST_RX_EOM
)
port
->
rxpart
=
0
;
/* received last fragment */
}
else
{
sca_rx
(
card
,
port
,
desc
,
port
->
rxin
);
received
++
;
}
/* Set new error descriptor address */
sca_outl
(
desc_off
,
dmac
+
EDAL
,
card
);
port
->
rxin
=
(
port
->
rxin
+
1
)
%
card
->
rx_ring_buffers
;
}
/* make sure RX DMA is enabled */
sca_out
(
DSR_DE
,
DSR_RX
(
port
->
chan
),
card
);
return
received
;
}
/* Transmit DMA service */
static
inline
void
sca_tx_done
(
port_t
*
port
)
{
struct
net_device
*
dev
=
port
->
netdev
;
card_t
*
card
=
port
->
card
;
u8
stat
;
spin_lock
(
&
port
->
lock
);
stat
=
sca_in
(
DSR_TX
(
port
->
chan
),
card
);
/* read DMA Status */
/* Reset DSR status bits */
sca_out
((
stat
&
(
DSR_EOT
|
DSR_EOM
|
DSR_BOF
|
DSR_COF
))
|
DSR_DWE
,
DSR_TX
(
port
->
chan
),
card
);
while
(
1
)
{
pkt_desc
__iomem
*
desc
=
desc_address
(
port
,
port
->
txlast
,
1
);
u8
stat
=
readb
(
&
desc
->
stat
);
if
(
!
(
stat
&
ST_TX_OWNRSHP
))
break
;
/* not yet transmitted */
if
(
stat
&
ST_TX_UNDRRUN
)
{
dev
->
stats
.
tx_errors
++
;
dev
->
stats
.
tx_fifo_errors
++
;
}
else
{
dev
->
stats
.
tx_packets
++
;
dev
->
stats
.
tx_bytes
+=
readw
(
&
desc
->
len
);
}
writeb
(
0
,
&
desc
->
stat
);
/* Free descriptor */
port
->
txlast
=
(
port
->
txlast
+
1
)
%
card
->
tx_ring_buffers
;
}
netif_wake_queue
(
dev
);
spin_unlock
(
&
port
->
lock
);
}
static
int
sca_poll
(
struct
napi_struct
*
napi
,
int
budget
)
{
port_t
*
port
=
container_of
(
napi
,
port_t
,
napi
);
u32
isr0
=
sca_inl
(
ISR0
,
port
->
card
);
int
received
=
0
;
if
(
isr0
&
(
port
->
chan
?
0x08000000
:
0x00080000
))
sca_msci_intr
(
port
);
if
(
isr0
&
(
port
->
chan
?
0x00002000
:
0x00000020
))
sca_tx_done
(
port
);
if
(
isr0
&
(
port
->
chan
?
0x00000200
:
0x00000002
))
received
=
sca_rx_done
(
port
,
budget
);
if
(
received
<
budget
)
{
netif_rx_complete
(
port
->
netdev
,
napi
);
enable_intr
(
port
);
}
return
received
;
}
static
irqreturn_t
sca_intr
(
int
irq
,
void
*
dev_id
)
{
card_t
*
card
=
dev_id
;
u32
isr0
=
sca_inl
(
ISR0
,
card
);
int
i
,
handled
=
0
;
for
(
i
=
0
;
i
<
2
;
i
++
)
{
port_t
*
port
=
get_port
(
card
,
i
);
if
(
port
&&
(
isr0
&
(
i
?
0x08002200
:
0x00080022
)))
{
handled
=
1
;
disable_intr
(
port
);
netif_rx_schedule
(
port
->
netdev
,
&
port
->
napi
);
}
}
return
IRQ_RETVAL
(
handled
);
}
static
void
sca_set_port
(
port_t
*
port
)
{
card_t
*
card
=
port
->
card
;
u16
msci
=
get_msci
(
port
);
u8
md2
=
sca_in
(
msci
+
MD2
,
card
);
unsigned
int
tmc
,
br
=
10
,
brv
=
1024
;
if
(
port
->
settings
.
clock_rate
>
0
)
{
/* Try lower br for better accuracy*/
do
{
br
--
;
brv
>>=
1
;
/* brv = 2^9 = 512 max in specs */
/* Baud Rate = CLOCK_BASE / TMC / 2^BR */
tmc
=
CLOCK_BASE
/
brv
/
port
->
settings
.
clock_rate
;
}
while
(
br
>
1
&&
tmc
<=
128
);
if
(
tmc
<
1
)
{
tmc
=
1
;
br
=
0
;
/* For baud=CLOCK_BASE we use tmc=1 br=0 */
brv
=
1
;
}
else
if
(
tmc
>
255
)
tmc
=
256
;
/* tmc=0 means 256 - low baud rates */
port
->
settings
.
clock_rate
=
CLOCK_BASE
/
brv
/
tmc
;
}
else
{
br
=
9
;
/* Minimum clock rate */
tmc
=
256
;
/* 8bit = 0 */
port
->
settings
.
clock_rate
=
CLOCK_BASE
/
(
256
*
512
);
}
port
->
rxs
=
(
port
->
rxs
&
~
CLK_BRG_MASK
)
|
br
;
port
->
txs
=
(
port
->
txs
&
~
CLK_BRG_MASK
)
|
br
;
port
->
tmc
=
tmc
;
/* baud divisor - time constant*/
sca_out
(
port
->
tmc
,
msci
+
TMCR
,
card
);
sca_out
(
port
->
tmc
,
msci
+
TMCT
,
card
);
/* Set BRG bits */
sca_out
(
port
->
rxs
,
msci
+
RXS
,
card
);
sca_out
(
port
->
txs
,
msci
+
TXS
,
card
);
if
(
port
->
settings
.
loopback
)
md2
|=
MD2_LOOPBACK
;
else
md2
&=
~
MD2_LOOPBACK
;
sca_out
(
md2
,
msci
+
MD2
,
card
);
}
static
void
sca_open
(
struct
net_device
*
dev
)
{
port_t
*
port
=
dev_to_port
(
dev
);
card_t
*
card
=
port
->
card
;
u16
msci
=
get_msci
(
port
);
u8
md0
,
md2
;
switch
(
port
->
encoding
)
{
case
ENCODING_NRZ
:
md2
=
MD2_NRZ
;
break
;
case
ENCODING_NRZI
:
md2
=
MD2_NRZI
;
break
;
case
ENCODING_FM_MARK
:
md2
=
MD2_FM_MARK
;
break
;
case
ENCODING_FM_SPACE
:
md2
=
MD2_FM_SPACE
;
break
;
default:
md2
=
MD2_MANCHESTER
;
}
if
(
port
->
settings
.
loopback
)
md2
|=
MD2_LOOPBACK
;
switch
(
port
->
parity
)
{
case
PARITY_CRC16_PR0
:
md0
=
MD0_HDLC
|
MD0_CRC_16_0
;
break
;
case
PARITY_CRC16_PR1
:
md0
=
MD0_HDLC
|
MD0_CRC_16
;
break
;
case
PARITY_CRC32_PR1_CCITT
:
md0
=
MD0_HDLC
|
MD0_CRC_ITU32
;
break
;
case
PARITY_CRC16_PR1_CCITT
:
md0
=
MD0_HDLC
|
MD0_CRC_ITU
;
break
;
default:
md0
=
MD0_HDLC
|
MD0_CRC_NONE
;
}
sca_out
(
CMD_RESET
,
msci
+
CMD
,
card
);
sca_out
(
md0
,
msci
+
MD0
,
card
);
sca_out
(
0x00
,
msci
+
MD1
,
card
);
/* no address field check */
sca_out
(
md2
,
msci
+
MD2
,
card
);
sca_out
(
0x7E
,
msci
+
IDL
,
card
);
/* flag character 0x7E */
/* Skip the rest of underrun frame */
sca_out
(
CTL_IDLE
|
CTL_URCT
|
CTL_URSKP
,
msci
+
CTL
,
card
);
sca_out
(
0x0F
,
msci
+
RNR
,
card
);
/* +1=RX DMA activation condition */
sca_out
(
0x3C
,
msci
+
TFS
,
card
);
/* +1 = TX start */
sca_out
(
0x38
,
msci
+
TCR
,
card
);
/* =Critical TX DMA activ condition */
sca_out
(
0x38
,
msci
+
TNR0
,
card
);
/* =TX DMA activation condition */
sca_out
(
0x3F
,
msci
+
TNR1
,
card
);
/* +1=TX DMA deactivation condition*/
/* We're using the following interrupts:
- RXINTA (DCD changes only)
- DMIB (EOM - single frame transfer complete)
*/
sca_outl
(
IE0_RXINTA
|
IE0_CDCD
,
msci
+
IE0
,
card
);
sca_out
(
port
->
tmc
,
msci
+
TMCR
,
card
);
sca_out
(
port
->
tmc
,
msci
+
TMCT
,
card
);
sca_out
(
port
->
rxs
,
msci
+
RXS
,
card
);
sca_out
(
port
->
txs
,
msci
+
TXS
,
card
);
sca_out
(
CMD_TX_ENABLE
,
msci
+
CMD
,
card
);
sca_out
(
CMD_RX_ENABLE
,
msci
+
CMD
,
card
);
sca_set_carrier
(
port
);
enable_intr
(
port
);
napi_enable
(
&
port
->
napi
);
netif_start_queue
(
dev
);
}
static
void
sca_close
(
struct
net_device
*
dev
)
{
port_t
*
port
=
dev_to_port
(
dev
);
/* reset channel */
sca_out
(
CMD_RESET
,
get_msci
(
port
)
+
CMD
,
port
->
card
);
disable_intr
(
port
);
napi_disable
(
&
port
->
napi
);
netif_stop_queue
(
dev
);
}
static
int
sca_attach
(
struct
net_device
*
dev
,
unsigned
short
encoding
,
unsigned
short
parity
)
{
if
(
encoding
!=
ENCODING_NRZ
&&
encoding
!=
ENCODING_NRZI
&&
encoding
!=
ENCODING_FM_MARK
&&
encoding
!=
ENCODING_FM_SPACE
&&
encoding
!=
ENCODING_MANCHESTER
)
return
-
EINVAL
;
if
(
parity
!=
PARITY_NONE
&&
parity
!=
PARITY_CRC16_PR0
&&
parity
!=
PARITY_CRC16_PR1
&&
parity
!=
PARITY_CRC32_PR1_CCITT
&&
parity
!=
PARITY_CRC16_PR1_CCITT
)
return
-
EINVAL
;
dev_to_port
(
dev
)
->
encoding
=
encoding
;
dev_to_port
(
dev
)
->
parity
=
parity
;
return
0
;
}
#ifdef DEBUG_RINGS
static
void
sca_dump_rings
(
struct
net_device
*
dev
)
{
port_t
*
port
=
dev_to_port
(
dev
);
card_t
*
card
=
port
->
card
;
u16
cnt
;
printk
(
KERN_DEBUG
"RX ring: CDA=%u EDA=%u DSR=%02X in=%u %sactive"
,
sca_inl
(
get_dmac_rx
(
port
)
+
CDAL
,
card
),
sca_inl
(
get_dmac_rx
(
port
)
+
EDAL
,
card
),
sca_in
(
DSR_RX
(
port
->
chan
),
card
),
port
->
rxin
,
sca_in
(
DSR_RX
(
port
->
chan
),
card
)
&
DSR_DE
?
""
:
"in"
);
for
(
cnt
=
0
;
cnt
<
port
->
card
->
rx_ring_buffers
;
cnt
++
)
printk
(
" %02X"
,
readb
(
&
(
desc_address
(
port
,
cnt
,
0
)
->
stat
)));
printk
(
"
\n
"
KERN_DEBUG
"TX ring: CDA=%u EDA=%u DSR=%02X in=%u "
"last=%u %sactive"
,
sca_inl
(
get_dmac_tx
(
port
)
+
CDAL
,
card
),
sca_inl
(
get_dmac_tx
(
port
)
+
EDAL
,
card
),
sca_in
(
DSR_TX
(
port
->
chan
),
card
),
port
->
txin
,
port
->
txlast
,
sca_in
(
DSR_TX
(
port
->
chan
),
card
)
&
DSR_DE
?
""
:
"in"
);
for
(
cnt
=
0
;
cnt
<
port
->
card
->
tx_ring_buffers
;
cnt
++
)
printk
(
" %02X"
,
readb
(
&
(
desc_address
(
port
,
cnt
,
1
)
->
stat
)));
printk
(
"
\n
"
);
printk
(
KERN_DEBUG
"MSCI: MD: %02x %02x %02x,"
" ST: %02x %02x %02x %02x %02x, FST: %02x CST: %02x %02x
\n
"
,
sca_in
(
get_msci
(
port
)
+
MD0
,
card
),
sca_in
(
get_msci
(
port
)
+
MD1
,
card
),
sca_in
(
get_msci
(
port
)
+
MD2
,
card
),
sca_in
(
get_msci
(
port
)
+
ST0
,
card
),
sca_in
(
get_msci
(
port
)
+
ST1
,
card
),
sca_in
(
get_msci
(
port
)
+
ST2
,
card
),
sca_in
(
get_msci
(
port
)
+
ST3
,
card
),
sca_in
(
get_msci
(
port
)
+
ST4
,
card
),
sca_in
(
get_msci
(
port
)
+
FST
,
card
),
sca_in
(
get_msci
(
port
)
+
CST0
,
card
),
sca_in
(
get_msci
(
port
)
+
CST1
,
card
));
printk
(
KERN_DEBUG
"ILAR: %02x ISR: %08x %08x
\n
"
,
sca_in
(
ILAR
,
card
),
sca_inl
(
ISR0
,
card
),
sca_inl
(
ISR1
,
card
));
}
#endif
/* DEBUG_RINGS */
static
int
sca_xmit
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
)
{
port_t
*
port
=
dev_to_port
(
dev
);
card_t
*
card
=
port
->
card
;
pkt_desc
__iomem
*
desc
;
u32
buff
,
len
;
spin_lock_irq
(
&
port
->
lock
);
desc
=
desc_address
(
port
,
port
->
txin
+
1
,
1
);
BUG_ON
(
readb
(
&
desc
->
stat
));
/* previous xmit should stop queue */
#ifdef DEBUG_PKT
printk
(
KERN_DEBUG
"%s TX(%i):"
,
dev
->
name
,
skb
->
len
);
debug_frame
(
skb
);
#endif
desc
=
desc_address
(
port
,
port
->
txin
,
1
);
buff
=
buffer_offset
(
port
,
port
->
txin
,
1
);
len
=
skb
->
len
;
memcpy_toio
(
card
->
rambase
+
buff
,
skb
->
data
,
len
);
writew
(
len
,
&
desc
->
len
);
writeb
(
ST_TX_EOM
,
&
desc
->
stat
);
dev
->
trans_start
=
jiffies
;
port
->
txin
=
(
port
->
txin
+
1
)
%
card
->
tx_ring_buffers
;
sca_outl
(
desc_offset
(
port
,
port
->
txin
,
1
),
get_dmac_tx
(
port
)
+
EDAL
,
card
);
sca_out
(
DSR_DE
,
DSR_TX
(
port
->
chan
),
card
);
/* Enable TX DMA */
desc
=
desc_address
(
port
,
port
->
txin
+
1
,
1
);
if
(
readb
(
&
desc
->
stat
))
/* allow 1 packet gap */
netif_stop_queue
(
dev
);
spin_unlock_irq
(
&
port
->
lock
);
dev_kfree_skb
(
skb
);
return
0
;
}
static
u32
__devinit
sca_detect_ram
(
card_t
*
card
,
u8
__iomem
*
rambase
,
u32
ramsize
)
{
/* Round RAM size to 32 bits, fill from end to start */
u32
i
=
ramsize
&=
~
3
;
do
{
i
-=
4
;
writel
(
i
^
0x12345678
,
rambase
+
i
);
}
while
(
i
>
0
);
for
(
i
=
0
;
i
<
ramsize
;
i
+=
4
)
{
if
(
readl
(
rambase
+
i
)
!=
(
i
^
0x12345678
))
break
;
}
return
i
;
}
static
void
__devinit
sca_init
(
card_t
*
card
,
int
wait_states
)
{
sca_out
(
wait_states
,
WCRL
,
card
);
/* Wait Control */
sca_out
(
wait_states
,
WCRM
,
card
);
sca_out
(
wait_states
,
WCRH
,
card
);
sca_out
(
0
,
DMER
,
card
);
/* DMA Master disable */
sca_out
(
0x03
,
PCR
,
card
);
/* DMA priority */
sca_out
(
0
,
DSR_RX
(
0
),
card
);
/* DMA disable - to halt state */
sca_out
(
0
,
DSR_TX
(
0
),
card
);
sca_out
(
0
,
DSR_RX
(
1
),
card
);
sca_out
(
0
,
DSR_TX
(
1
),
card
);
sca_out
(
DMER_DME
,
DMER
,
card
);
/* DMA Master enable */
}
drivers/net/wan/hdlc_ppp.c
View file @
c46920da
...
...
@@ -2,7 +2,7 @@
* Generic HDLC support routines for Linux
* Point-to-point protocol support
*
* Copyright (C) 1999 - 200
6
Krzysztof Halasa <khc@pm.waw.pl>
* Copyright (C) 1999 - 200
8
Krzysztof Halasa <khc@pm.waw.pl>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License
...
...
@@ -18,87 +18,632 @@
#include <linux/module.h>
#include <linux/pkt_sched.h>
#include <linux/poll.h>
#include <linux/rtnetlink.h>
#include <linux/skbuff.h>
#include <linux/slab.h>
#include <net/syncppp.h>
#include <linux/spinlock.h>
#define DEBUG_CP 0
/* also bytes# to dump */
#define DEBUG_STATE 0
#define DEBUG_HARD_HEADER 0
#define HDLC_ADDR_ALLSTATIONS 0xFF
#define HDLC_CTRL_UI 0x03
#define PID_LCP 0xC021
#define PID_IP 0x0021
#define PID_IPCP 0x8021
#define PID_IPV6 0x0057
#define PID_IPV6CP 0x8057
enum
{
IDX_LCP
=
0
,
IDX_IPCP
,
IDX_IPV6CP
,
IDX_COUNT
};
enum
{
CP_CONF_REQ
=
1
,
CP_CONF_ACK
,
CP_CONF_NAK
,
CP_CONF_REJ
,
CP_TERM_REQ
,
CP_TERM_ACK
,
CP_CODE_REJ
,
LCP_PROTO_REJ
,
LCP_ECHO_REQ
,
LCP_ECHO_REPLY
,
LCP_DISC_REQ
,
CP_CODES
};
#if DEBUG_CP
static
const
char
*
const
code_names
[
CP_CODES
]
=
{
"0"
,
"ConfReq"
,
"ConfAck"
,
"ConfNak"
,
"ConfRej"
,
"TermReq"
,
"TermAck"
,
"CodeRej"
,
"ProtoRej"
,
"EchoReq"
,
"EchoReply"
,
"Discard"
};
static
char
debug_buffer
[
64
+
3
*
DEBUG_CP
];
#endif
enum
{
LCP_OPTION_MRU
=
1
,
LCP_OPTION_ACCM
,
LCP_OPTION_MAGIC
=
5
};
struct
hdlc_header
{
u8
address
;
u8
control
;
__be16
protocol
;
};
struct
cp_header
{
u8
code
;
u8
id
;
__be16
len
;
};
struct
ppp_state
{
struct
ppp_device
pppdev
;
struct
ppp_device
*
syncppp_ptr
;
int
(
*
old_change_mtu
)(
struct
net_device
*
dev
,
int
new_mtu
);
struct
proto
{
struct
net_device
*
dev
;
struct
timer_list
timer
;
unsigned
long
timeout
;
u16
pid
;
/* protocol ID */
u8
state
;
u8
cr_id
;
/* ID of last Configuration-Request */
u8
restart_counter
;
};
struct
ppp
{
struct
proto
protos
[
IDX_COUNT
];
spinlock_t
lock
;
unsigned
long
last_pong
;
unsigned
int
req_timeout
,
cr_retries
,
term_retries
;
unsigned
int
keepalive_interval
,
keepalive_timeout
;
u8
seq
;
/* local sequence number for requests */
u8
echo_id
;
/* ID of last Echo-Request (LCP) */
};
enum
{
CLOSED
=
0
,
STOPPED
,
STOPPING
,
REQ_SENT
,
ACK_RECV
,
ACK_SENT
,
OPENED
,
STATES
,
STATE_MASK
=
0xF
};
enum
{
START
=
0
,
STOP
,
TO_GOOD
,
TO_BAD
,
RCR_GOOD
,
RCR_BAD
,
RCA
,
RCN
,
RTR
,
RTA
,
RUC
,
RXJ_GOOD
,
RXJ_BAD
,
EVENTS
};
enum
{
INV
=
0x10
,
IRC
=
0x20
,
ZRC
=
0x40
,
SCR
=
0x80
,
SCA
=
0x100
,
SCN
=
0x200
,
STR
=
0x400
,
STA
=
0x800
,
SCJ
=
0x1000
};
#if DEBUG_STATE
static
const
char
*
const
state_names
[
STATES
]
=
{
"Closed"
,
"Stopped"
,
"Stopping"
,
"ReqSent"
,
"AckRecv"
,
"AckSent"
,
"Opened"
};
static
const
char
*
const
event_names
[
EVENTS
]
=
{
"Start"
,
"Stop"
,
"TO+"
,
"TO-"
,
"RCR+"
,
"RCR-"
,
"RCA"
,
"RCN"
,
"RTR"
,
"RTA"
,
"RUC"
,
"RXJ+"
,
"RXJ-"
};
#endif
static
struct
sk_buff_head
tx_queue
;
/* used when holding the spin lock */
static
int
ppp_ioctl
(
struct
net_device
*
dev
,
struct
ifreq
*
ifr
);
static
inline
struct
ppp
*
get_ppp
(
struct
net_device
*
dev
)
{
return
(
struct
ppp
*
)
dev_to_hdlc
(
dev
)
->
state
;
}
static
inline
struct
p
pp_state
*
state
(
hdlc_device
*
hdlc
)
static
inline
struct
p
roto
*
get_proto
(
struct
net_device
*
dev
,
u16
pid
)
{
return
(
struct
ppp_state
*
)(
hdlc
->
state
);
struct
ppp
*
ppp
=
get_ppp
(
dev
);
switch
(
pid
)
{
case
PID_LCP
:
return
&
ppp
->
protos
[
IDX_LCP
];
case
PID_IPCP
:
return
&
ppp
->
protos
[
IDX_IPCP
];
case
PID_IPV6CP
:
return
&
ppp
->
protos
[
IDX_IPV6CP
];
default:
return
NULL
;
}
}
static
inline
const
char
*
proto_name
(
u16
pid
)
{
switch
(
pid
)
{
case
PID_LCP
:
return
"LCP"
;
case
PID_IPCP
:
return
"IPCP"
;
case
PID_IPV6CP
:
return
"IPV6CP"
;
default:
return
NULL
;
}
}
static
int
ppp_open
(
struct
net_device
*
dev
)
static
__be16
ppp_type_trans
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
)
{
hdlc_device
*
hdlc
=
dev_to_hdlc
(
dev
);
int
(
*
old_ioctl
)(
struct
net_device
*
,
struct
ifreq
*
,
int
);
int
result
;
struct
hdlc_header
*
data
=
(
struct
hdlc_header
*
)
skb
->
data
;
if
(
skb
->
len
<
sizeof
(
struct
hdlc_header
))
return
htons
(
ETH_P_HDLC
);
if
(
data
->
address
!=
HDLC_ADDR_ALLSTATIONS
||
data
->
control
!=
HDLC_CTRL_UI
)
return
htons
(
ETH_P_HDLC
);
switch
(
data
->
protocol
)
{
case
__constant_htons
(
PID_IP
):
skb_pull
(
skb
,
sizeof
(
struct
hdlc_header
));
return
htons
(
ETH_P_IP
);
dev
->
ml_priv
=
&
state
(
hdlc
)
->
syncppp_ptr
;
state
(
hdlc
)
->
syncppp_ptr
=
&
state
(
hdlc
)
->
pppdev
;
state
(
hdlc
)
->
pppdev
.
dev
=
dev
;
case
__constant_htons
(
PID_IPV6
):
skb_pull
(
skb
,
sizeof
(
struct
hdlc_header
))
;
return
htons
(
ETH_P_IPV6
)
;
old_ioctl
=
dev
->
do_ioctl
;
state
(
hdlc
)
->
old_change_mtu
=
dev
->
change_mtu
;
sppp_attach
(
&
state
(
hdlc
)
->
pppdev
);
/* sppp_attach nukes them. We don't need syncppp's ioctl */
dev
->
do_ioctl
=
old_ioctl
;
state
(
hdlc
)
->
pppdev
.
sppp
.
pp_flags
&=
~
PP_CISCO
;
dev
->
type
=
ARPHRD_PPP
;
result
=
sppp_open
(
dev
);
if
(
result
)
{
sppp_detach
(
dev
);
return
result
;
default:
return
htons
(
ETH_P_HDLC
);
}
}
return
0
;
static
int
ppp_hard_header
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
,
u16
type
,
const
void
*
daddr
,
const
void
*
saddr
,
unsigned
int
len
)
{
struct
hdlc_header
*
data
;
#if DEBUG_HARD_HEADER
printk
(
KERN_DEBUG
"%s: ppp_hard_header() called
\n
"
,
dev
->
name
);
#endif
skb_push
(
skb
,
sizeof
(
struct
hdlc_header
));
data
=
(
struct
hdlc_header
*
)
skb
->
data
;
data
->
address
=
HDLC_ADDR_ALLSTATIONS
;
data
->
control
=
HDLC_CTRL_UI
;
switch
(
type
)
{
case
ETH_P_IP
:
data
->
protocol
=
htons
(
PID_IP
);
break
;
case
ETH_P_IPV6
:
data
->
protocol
=
htons
(
PID_IPV6
);
break
;
case
PID_LCP
:
case
PID_IPCP
:
case
PID_IPV6CP
:
data
->
protocol
=
htons
(
type
);
break
;
default:
/* unknown protocol */
data
->
protocol
=
0
;
}
return
sizeof
(
struct
hdlc_header
);
}
static
void
ppp_tx_flush
(
void
)
{
struct
sk_buff
*
skb
;
while
((
skb
=
skb_dequeue
(
&
tx_queue
))
!=
NULL
)
dev_queue_xmit
(
skb
);
}
static
void
ppp_close
(
struct
net_device
*
dev
)
static
void
ppp_tx_cp
(
struct
net_device
*
dev
,
u16
pid
,
u8
code
,
u8
id
,
unsigned
int
len
,
const
void
*
data
)
{
hdlc_device
*
hdlc
=
dev_to_hdlc
(
dev
);
struct
sk_buff
*
skb
;
struct
cp_header
*
cp
;
unsigned
int
magic_len
=
0
;
static
u32
magic
;
#if DEBUG_CP
int
i
;
char
*
ptr
;
#endif
if
(
pid
==
PID_LCP
&&
(
code
==
LCP_ECHO_REQ
||
code
==
LCP_ECHO_REPLY
))
magic_len
=
sizeof
(
magic
);
skb
=
dev_alloc_skb
(
sizeof
(
struct
hdlc_header
)
+
sizeof
(
struct
cp_header
)
+
magic_len
+
len
);
if
(
!
skb
)
{
printk
(
KERN_WARNING
"%s: out of memory in ppp_tx_cp()
\n
"
,
dev
->
name
);
return
;
}
skb_reserve
(
skb
,
sizeof
(
struct
hdlc_header
));
cp
=
(
struct
cp_header
*
)
skb_put
(
skb
,
sizeof
(
struct
cp_header
));
cp
->
code
=
code
;
cp
->
id
=
id
;
cp
->
len
=
htons
(
sizeof
(
struct
cp_header
)
+
magic_len
+
len
);
if
(
magic_len
)
memcpy
(
skb_put
(
skb
,
magic_len
),
&
magic
,
magic_len
);
if
(
len
)
memcpy
(
skb_put
(
skb
,
len
),
data
,
len
);
#if DEBUG_CP
BUG_ON
(
code
>=
CP_CODES
);
ptr
=
debug_buffer
;
*
ptr
=
'\x0'
;
for
(
i
=
0
;
i
<
min_t
(
unsigned
int
,
magic_len
+
len
,
DEBUG_CP
);
i
++
)
{
sprintf
(
ptr
,
" %02X"
,
skb
->
data
[
sizeof
(
struct
cp_header
)
+
i
]);
ptr
+=
strlen
(
ptr
);
}
printk
(
KERN_DEBUG
"%s: TX %s [%s id 0x%X]%s
\n
"
,
dev
->
name
,
proto_name
(
pid
),
code_names
[
code
],
id
,
debug_buffer
);
#endif
sppp_close
(
dev
);
sppp_detach
(
dev
);
ppp_hard_header
(
skb
,
dev
,
pid
,
NULL
,
NULL
,
0
);
dev
->
change_mtu
=
state
(
hdlc
)
->
old_change_mtu
;
dev
->
mtu
=
HDLC_MAX_MTU
;
dev
->
hard_header_len
=
16
;
skb
->
priority
=
TC_PRIO_CONTROL
;
skb
->
dev
=
dev
;
skb_reset_network_header
(
skb
);
skb_queue_tail
(
&
tx_queue
,
skb
);
}
/* State transition table (compare STD-51)
Events Actions
TO+ = Timeout with counter > 0 irc = Initialize-Restart-Count
TO- = Timeout with counter expired zrc = Zero-Restart-Count
RCR+ = Receive-Configure-Request (Good) scr = Send-Configure-Request
RCR- = Receive-Configure-Request (Bad)
RCA = Receive-Configure-Ack sca = Send-Configure-Ack
RCN = Receive-Configure-Nak/Rej scn = Send-Configure-Nak/Rej
RTR = Receive-Terminate-Request str = Send-Terminate-Request
RTA = Receive-Terminate-Ack sta = Send-Terminate-Ack
RUC = Receive-Unknown-Code scj = Send-Code-Reject
RXJ+ = Receive-Code-Reject (permitted)
or Receive-Protocol-Reject
RXJ- = Receive-Code-Reject (catastrophic)
or Receive-Protocol-Reject
*/
static
int
cp_table
[
EVENTS
][
STATES
]
=
{
/* CLOSED STOPPED STOPPING REQ_SENT ACK_RECV ACK_SENT OPENED
0 1 2 3 4 5 6 */
{
IRC
|
SCR
|
3
,
INV
,
INV
,
INV
,
INV
,
INV
,
INV
},
/* START */
{
INV
,
0
,
0
,
0
,
0
,
0
,
0
},
/* STOP */
{
INV
,
INV
,
STR
|
2
,
SCR
|
3
,
SCR
|
3
,
SCR
|
5
,
INV
},
/* TO+ */
{
INV
,
INV
,
1
,
1
,
1
,
1
,
INV
},
/* TO- */
{
STA
|
0
,
IRC
|
SCR
|
SCA
|
5
,
2
,
SCA
|
5
,
SCA
|
6
,
SCA
|
5
,
SCR
|
SCA
|
5
},
/* RCR+ */
{
STA
|
0
,
IRC
|
SCR
|
SCN
|
3
,
2
,
SCN
|
3
,
SCN
|
4
,
SCN
|
3
,
SCR
|
SCN
|
3
},
/* RCR- */
{
STA
|
0
,
STA
|
1
,
2
,
IRC
|
4
,
SCR
|
3
,
6
,
SCR
|
3
},
/* RCA */
{
STA
|
0
,
STA
|
1
,
2
,
IRC
|
SCR
|
3
,
SCR
|
3
,
IRC
|
SCR
|
5
,
SCR
|
3
},
/* RCN */
{
STA
|
0
,
STA
|
1
,
STA
|
2
,
STA
|
3
,
STA
|
3
,
STA
|
3
,
ZRC
|
STA
|
2
},
/* RTR */
{
0
,
1
,
1
,
3
,
3
,
5
,
SCR
|
3
},
/* RTA */
{
SCJ
|
0
,
SCJ
|
1
,
SCJ
|
2
,
SCJ
|
3
,
SCJ
|
4
,
SCJ
|
5
,
SCJ
|
6
},
/* RUC */
{
0
,
1
,
2
,
3
,
3
,
5
,
6
},
/* RXJ+ */
{
0
,
1
,
1
,
1
,
1
,
1
,
IRC
|
STR
|
2
},
/* RXJ- */
};
static
__be16
ppp_type_trans
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
)
/* SCA: RCR+ must supply id, len and data
SCN: RCR- must supply code, id, len and data
STA: RTR must supply id
SCJ: RUC must supply CP packet len and data */
static
void
ppp_cp_event
(
struct
net_device
*
dev
,
u16
pid
,
u16
event
,
u8
code
,
u8
id
,
unsigned
int
len
,
void
*
data
)
{
return
__constant_htons
(
ETH_P_WAN_PPP
);
int
old_state
,
action
;
struct
ppp
*
ppp
=
get_ppp
(
dev
);
struct
proto
*
proto
=
get_proto
(
dev
,
pid
);
old_state
=
proto
->
state
;
BUG_ON
(
old_state
>=
STATES
);
BUG_ON
(
event
>=
EVENTS
);
#if DEBUG_STATE
printk
(
KERN_DEBUG
"%s: %s ppp_cp_event(%s) %s ...
\n
"
,
dev
->
name
,
proto_name
(
pid
),
event_names
[
event
],
state_names
[
proto
->
state
]);
#endif
action
=
cp_table
[
event
][
old_state
];
proto
->
state
=
action
&
STATE_MASK
;
if
(
action
&
(
SCR
|
STR
))
/* set Configure-Req/Terminate-Req timer */
mod_timer
(
&
proto
->
timer
,
proto
->
timeout
=
jiffies
+
ppp
->
req_timeout
*
HZ
);
if
(
action
&
ZRC
)
proto
->
restart_counter
=
0
;
if
(
action
&
IRC
)
proto
->
restart_counter
=
(
proto
->
state
==
STOPPING
)
?
ppp
->
term_retries
:
ppp
->
cr_retries
;
if
(
action
&
SCR
)
/* send Configure-Request */
ppp_tx_cp
(
dev
,
pid
,
CP_CONF_REQ
,
proto
->
cr_id
=
++
ppp
->
seq
,
0
,
NULL
);
if
(
action
&
SCA
)
/* send Configure-Ack */
ppp_tx_cp
(
dev
,
pid
,
CP_CONF_ACK
,
id
,
len
,
data
);
if
(
action
&
SCN
)
/* send Configure-Nak/Reject */
ppp_tx_cp
(
dev
,
pid
,
code
,
id
,
len
,
data
);
if
(
action
&
STR
)
/* send Terminate-Request */
ppp_tx_cp
(
dev
,
pid
,
CP_TERM_REQ
,
++
ppp
->
seq
,
0
,
NULL
);
if
(
action
&
STA
)
/* send Terminate-Ack */
ppp_tx_cp
(
dev
,
pid
,
CP_TERM_ACK
,
id
,
0
,
NULL
);
if
(
action
&
SCJ
)
/* send Code-Reject */
ppp_tx_cp
(
dev
,
pid
,
CP_CODE_REJ
,
++
ppp
->
seq
,
len
,
data
);
if
(
old_state
!=
OPENED
&&
proto
->
state
==
OPENED
)
{
printk
(
KERN_INFO
"%s: %s up
\n
"
,
dev
->
name
,
proto_name
(
pid
));
if
(
pid
==
PID_LCP
)
{
netif_dormant_off
(
dev
);
ppp_cp_event
(
dev
,
PID_IPCP
,
START
,
0
,
0
,
0
,
NULL
);
ppp_cp_event
(
dev
,
PID_IPV6CP
,
START
,
0
,
0
,
0
,
NULL
);
ppp
->
last_pong
=
jiffies
;
mod_timer
(
&
proto
->
timer
,
proto
->
timeout
=
jiffies
+
ppp
->
keepalive_interval
*
HZ
);
}
}
if
(
old_state
==
OPENED
&&
proto
->
state
!=
OPENED
)
{
printk
(
KERN_INFO
"%s: %s down
\n
"
,
dev
->
name
,
proto_name
(
pid
));
if
(
pid
==
PID_LCP
)
{
netif_dormant_on
(
dev
);
ppp_cp_event
(
dev
,
PID_IPCP
,
STOP
,
0
,
0
,
0
,
NULL
);
ppp_cp_event
(
dev
,
PID_IPV6CP
,
STOP
,
0
,
0
,
0
,
NULL
);
}
}
if
(
old_state
!=
CLOSED
&&
proto
->
state
==
CLOSED
)
del_timer
(
&
proto
->
timer
);
#if DEBUG_STATE
printk
(
KERN_DEBUG
"%s: %s ppp_cp_event(%s) ... %s
\n
"
,
dev
->
name
,
proto_name
(
pid
),
event_names
[
event
],
state_names
[
proto
->
state
]);
#endif
}
static
void
ppp_cp_parse_cr
(
struct
net_device
*
dev
,
u16
pid
,
u8
id
,
unsigned
int
len
,
u8
*
data
)
{
static
u8
const
valid_accm
[
6
]
=
{
LCP_OPTION_ACCM
,
6
,
0
,
0
,
0
,
0
};
u8
*
opt
,
*
out
;
unsigned
int
nak_len
=
0
,
rej_len
=
0
;
if
(
!
(
out
=
kmalloc
(
len
,
GFP_ATOMIC
)))
{
dev
->
stats
.
rx_dropped
++
;
return
;
/* out of memory, ignore CR packet */
}
for
(
opt
=
data
;
len
;
len
-=
opt
[
1
],
opt
+=
opt
[
1
])
{
if
(
len
<
2
||
len
<
opt
[
1
])
{
dev
->
stats
.
rx_errors
++
;
return
;
/* bad packet, drop silently */
}
if
(
pid
==
PID_LCP
)
switch
(
opt
[
0
])
{
case
LCP_OPTION_MRU
:
continue
;
/* MRU always OK and > 1500 bytes? */
case
LCP_OPTION_ACCM
:
/* async control character map */
if
(
!
memcmp
(
opt
,
valid_accm
,
sizeof
(
valid_accm
)))
continue
;
if
(
!
rej_len
)
{
/* NAK it */
memcpy
(
out
+
nak_len
,
valid_accm
,
sizeof
(
valid_accm
));
nak_len
+=
sizeof
(
valid_accm
);
continue
;
}
break
;
case
LCP_OPTION_MAGIC
:
if
(
opt
[
1
]
!=
6
||
(
!
opt
[
2
]
&&
!
opt
[
3
]
&&
!
opt
[
4
]
&&
!
opt
[
5
]))
break
;
/* reject invalid magic number */
continue
;
}
/* reject this option */
memcpy
(
out
+
rej_len
,
opt
,
opt
[
1
]);
rej_len
+=
opt
[
1
];
}
if
(
rej_len
)
ppp_cp_event
(
dev
,
pid
,
RCR_BAD
,
CP_CONF_REJ
,
id
,
rej_len
,
out
);
else
if
(
nak_len
)
ppp_cp_event
(
dev
,
pid
,
RCR_BAD
,
CP_CONF_NAK
,
id
,
nak_len
,
out
);
else
ppp_cp_event
(
dev
,
pid
,
RCR_GOOD
,
CP_CONF_ACK
,
id
,
len
,
data
);
kfree
(
out
);
}
static
int
ppp_rx
(
struct
sk_buff
*
skb
)
{
struct
hdlc_header
*
hdr
=
(
struct
hdlc_header
*
)
skb
->
data
;
struct
net_device
*
dev
=
skb
->
dev
;
struct
ppp
*
ppp
=
get_ppp
(
dev
);
struct
proto
*
proto
;
struct
cp_header
*
cp
;
unsigned
long
flags
;
unsigned
int
len
;
u16
pid
;
#if DEBUG_CP
int
i
;
char
*
ptr
;
#endif
spin_lock_irqsave
(
&
ppp
->
lock
,
flags
);
/* Check HDLC header */
if
(
skb
->
len
<
sizeof
(
struct
hdlc_header
))
goto
rx_error
;
cp
=
(
struct
cp_header
*
)
skb_pull
(
skb
,
sizeof
(
struct
hdlc_header
));
if
(
hdr
->
address
!=
HDLC_ADDR_ALLSTATIONS
||
hdr
->
control
!=
HDLC_CTRL_UI
)
goto
rx_error
;
pid
=
ntohs
(
hdr
->
protocol
);
proto
=
get_proto
(
dev
,
pid
);
if
(
!
proto
)
{
if
(
ppp
->
protos
[
IDX_LCP
].
state
==
OPENED
)
ppp_tx_cp
(
dev
,
PID_LCP
,
LCP_PROTO_REJ
,
++
ppp
->
seq
,
skb
->
len
+
2
,
&
hdr
->
protocol
);
goto
rx_error
;
}
len
=
ntohs
(
cp
->
len
);
if
(
len
<
sizeof
(
struct
cp_header
)
/* no complete CP header? */
||
skb
->
len
<
len
/* truncated packet? */
)
goto
rx_error
;
skb_pull
(
skb
,
sizeof
(
struct
cp_header
));
len
-=
sizeof
(
struct
cp_header
);
/* HDLC and CP headers stripped from skb */
#if DEBUG_CP
if
(
cp
->
code
<
CP_CODES
)
sprintf
(
debug_buffer
,
"[%s id 0x%X]"
,
code_names
[
cp
->
code
],
cp
->
id
);
else
sprintf
(
debug_buffer
,
"[code %u id 0x%X]"
,
cp
->
code
,
cp
->
id
);
ptr
=
debug_buffer
+
strlen
(
debug_buffer
);
for
(
i
=
0
;
i
<
min_t
(
unsigned
int
,
len
,
DEBUG_CP
);
i
++
)
{
sprintf
(
ptr
,
" %02X"
,
skb
->
data
[
i
]);
ptr
+=
strlen
(
ptr
);
}
printk
(
KERN_DEBUG
"%s: RX %s %s
\n
"
,
dev
->
name
,
proto_name
(
pid
),
debug_buffer
);
#endif
/* LCP only */
if
(
pid
==
PID_LCP
)
switch
(
cp
->
code
)
{
case
LCP_PROTO_REJ
:
pid
=
ntohs
(
*
(
__be16
*
)
skb
->
data
);
if
(
pid
==
PID_LCP
||
pid
==
PID_IPCP
||
pid
==
PID_IPV6CP
)
ppp_cp_event
(
dev
,
pid
,
RXJ_BAD
,
0
,
0
,
0
,
NULL
);
goto
out
;
case
LCP_ECHO_REQ
:
/* send Echo-Reply */
if
(
len
>=
4
&&
proto
->
state
==
OPENED
)
ppp_tx_cp
(
dev
,
PID_LCP
,
LCP_ECHO_REPLY
,
cp
->
id
,
len
-
4
,
skb
->
data
+
4
);
goto
out
;
case
LCP_ECHO_REPLY
:
if
(
cp
->
id
==
ppp
->
echo_id
)
ppp
->
last_pong
=
jiffies
;
goto
out
;
case
LCP_DISC_REQ
:
/* discard */
goto
out
;
}
/* LCP, IPCP and IPV6CP */
switch
(
cp
->
code
)
{
case
CP_CONF_REQ
:
ppp_cp_parse_cr
(
dev
,
pid
,
cp
->
id
,
len
,
skb
->
data
);
goto
out
;
case
CP_CONF_ACK
:
if
(
cp
->
id
==
proto
->
cr_id
)
ppp_cp_event
(
dev
,
pid
,
RCA
,
0
,
0
,
0
,
NULL
);
goto
out
;
case
CP_CONF_REJ
:
case
CP_CONF_NAK
:
if
(
cp
->
id
==
proto
->
cr_id
)
ppp_cp_event
(
dev
,
pid
,
RCN
,
0
,
0
,
0
,
NULL
);
goto
out
;
case
CP_TERM_REQ
:
ppp_cp_event
(
dev
,
pid
,
RTR
,
0
,
cp
->
id
,
0
,
NULL
);
goto
out
;
case
CP_TERM_ACK
:
ppp_cp_event
(
dev
,
pid
,
RTA
,
0
,
0
,
0
,
NULL
);
goto
out
;
case
CP_CODE_REJ
:
ppp_cp_event
(
dev
,
pid
,
RXJ_BAD
,
0
,
0
,
0
,
NULL
);
goto
out
;
default:
len
+=
sizeof
(
struct
cp_header
);
if
(
len
>
dev
->
mtu
)
len
=
dev
->
mtu
;
ppp_cp_event
(
dev
,
pid
,
RUC
,
0
,
0
,
len
,
cp
);
goto
out
;
}
goto
out
;
rx_error:
dev
->
stats
.
rx_errors
++
;
out:
spin_unlock_irqrestore
(
&
ppp
->
lock
,
flags
);
dev_kfree_skb_any
(
skb
);
ppp_tx_flush
();
return
NET_RX_DROP
;
}
static
void
ppp_timer
(
unsigned
long
arg
)
{
struct
proto
*
proto
=
(
struct
proto
*
)
arg
;
struct
ppp
*
ppp
=
get_ppp
(
proto
->
dev
);
unsigned
long
flags
;
spin_lock_irqsave
(
&
ppp
->
lock
,
flags
);
switch
(
proto
->
state
)
{
case
STOPPING
:
case
REQ_SENT
:
case
ACK_RECV
:
case
ACK_SENT
:
if
(
proto
->
restart_counter
)
{
ppp_cp_event
(
proto
->
dev
,
proto
->
pid
,
TO_GOOD
,
0
,
0
,
0
,
NULL
);
proto
->
restart_counter
--
;
}
else
ppp_cp_event
(
proto
->
dev
,
proto
->
pid
,
TO_BAD
,
0
,
0
,
0
,
NULL
);
break
;
case
OPENED
:
if
(
proto
->
pid
!=
PID_LCP
)
break
;
if
(
time_after
(
jiffies
,
ppp
->
last_pong
+
ppp
->
keepalive_timeout
*
HZ
))
{
printk
(
KERN_INFO
"%s: Link down
\n
"
,
proto
->
dev
->
name
);
ppp_cp_event
(
proto
->
dev
,
PID_LCP
,
STOP
,
0
,
0
,
0
,
NULL
);
ppp_cp_event
(
proto
->
dev
,
PID_LCP
,
START
,
0
,
0
,
0
,
NULL
);
}
else
{
/* send keep-alive packet */
ppp
->
echo_id
=
++
ppp
->
seq
;
ppp_tx_cp
(
proto
->
dev
,
PID_LCP
,
LCP_ECHO_REQ
,
ppp
->
echo_id
,
0
,
NULL
);
proto
->
timer
.
expires
=
jiffies
+
ppp
->
keepalive_interval
*
HZ
;
add_timer
(
&
proto
->
timer
);
}
break
;
}
spin_unlock_irqrestore
(
&
ppp
->
lock
,
flags
);
ppp_tx_flush
();
}
static
void
ppp_start
(
struct
net_device
*
dev
)
{
struct
ppp
*
ppp
=
get_ppp
(
dev
);
int
i
;
for
(
i
=
0
;
i
<
IDX_COUNT
;
i
++
)
{
struct
proto
*
proto
=
&
ppp
->
protos
[
i
];
proto
->
dev
=
dev
;
init_timer
(
&
proto
->
timer
);
proto
->
timer
.
function
=
ppp_timer
;
proto
->
timer
.
data
=
(
unsigned
long
)
proto
;
proto
->
state
=
CLOSED
;
}
ppp
->
protos
[
IDX_LCP
].
pid
=
PID_LCP
;
ppp
->
protos
[
IDX_IPCP
].
pid
=
PID_IPCP
;
ppp
->
protos
[
IDX_IPV6CP
].
pid
=
PID_IPV6CP
;
ppp_cp_event
(
dev
,
PID_LCP
,
START
,
0
,
0
,
0
,
NULL
);
}
static
void
ppp_stop
(
struct
net_device
*
dev
)
{
ppp_cp_event
(
dev
,
PID_LCP
,
STOP
,
0
,
0
,
0
,
NULL
);
}
static
struct
hdlc_proto
proto
=
{
.
open
=
ppp_open
,
.
close
=
ppp_close
,
.
start
=
ppp_start
,
.
stop
=
ppp_stop
,
.
type_trans
=
ppp_type_trans
,
.
ioctl
=
ppp_ioctl
,
.
netif_rx
=
ppp_rx
,
.
module
=
THIS_MODULE
,
};
static
const
struct
header_ops
ppp_header_ops
=
{
.
create
=
ppp_hard_header
,
};
static
int
ppp_ioctl
(
struct
net_device
*
dev
,
struct
ifreq
*
ifr
)
{
hdlc_device
*
hdlc
=
dev_to_hdlc
(
dev
);
struct
ppp
*
ppp
;
int
result
;
switch
(
ifr
->
ifr_settings
.
type
)
{
...
...
@@ -109,25 +654,35 @@ static int ppp_ioctl(struct net_device *dev, struct ifreq *ifr)
return
0
;
/* return protocol only, no settable parameters */
case
IF_PROTO_PPP
:
if
(
!
capable
(
CAP_NET_ADMIN
))
if
(
!
capable
(
CAP_NET_ADMIN
))
return
-
EPERM
;
if
(
dev
->
flags
&
IFF_UP
)
if
(
dev
->
flags
&
IFF_UP
)
return
-
EBUSY
;
/* no settable parameters */
result
=
hdlc
->
attach
(
dev
,
ENCODING_NRZ
,
PARITY_CRC16_PR1_CCITT
);
result
=
hdlc
->
attach
(
dev
,
ENCODING_NRZ
,
PARITY_CRC16_PR1_CCITT
);
if
(
result
)
return
result
;
result
=
attach_hdlc_protocol
(
dev
,
&
proto
,
sizeof
(
struct
ppp_state
));
result
=
attach_hdlc_protocol
(
dev
,
&
proto
,
sizeof
(
struct
ppp
));
if
(
result
)
return
result
;
ppp
=
get_ppp
(
dev
);
spin_lock_init
(
&
ppp
->
lock
);
ppp
->
req_timeout
=
2
;
ppp
->
cr_retries
=
10
;
ppp
->
term_retries
=
2
;
ppp
->
keepalive_interval
=
10
;
ppp
->
keepalive_timeout
=
60
;
dev
->
hard_start_xmit
=
hdlc
->
xmit
;
dev
->
hard_header_len
=
sizeof
(
struct
hdlc_header
);
dev
->
header_ops
=
&
ppp_header_ops
;
dev
->
type
=
ARPHRD_PPP
;
netif_dormant_o
ff
(
dev
);
netif_dormant_o
n
(
dev
);
return
0
;
}
...
...
@@ -137,12 +692,11 @@ static int ppp_ioctl(struct net_device *dev, struct ifreq *ifr)
static
int
__init
mod_init
(
void
)
{
skb_queue_head_init
(
&
tx_queue
);
register_hdlc_protocol
(
&
proto
);
return
0
;
}
static
void
__exit
mod_exit
(
void
)
{
unregister_hdlc_protocol
(
&
proto
);
...
...
drivers/net/wan/n2.c
View file @
c46920da
...
...
@@ -53,7 +53,7 @@ static const char* devname = "RISCom/N2";
#define NEED_SCA_MSCI_INTR
#define MAX_TX_BUFFERS 10
static
char
*
hw
=
NULL
;
/* pointer to hw=xxx command line string */
static
char
*
hw
;
/* pointer to hw=xxx command line string */
/* RISCom/N2 Board Registers */
...
...
@@ -145,7 +145,6 @@ static card_t **new_card = &first_card;
&(card)->ports[port] : NULL)
static
__inline__
u8
sca_get_page
(
card_t
*
card
)
{
return
inb
(
card
->
io
+
N2_PSR
)
&
PSR_PAGEBITS
;
...
...
@@ -159,9 +158,7 @@ static __inline__ void openwin(card_t *card, u8 page)
}
#include "hd6457x.c"
#include "hd64570.c"
static
void
n2_set_iface
(
port_t
*
port
)
...
...
@@ -478,7 +475,7 @@ static int __init n2_run(unsigned long io, unsigned long irq,
n2_destroy_card
(
card
);
return
-
ENOBUFS
;
}
sca_init_
sync_
port
(
port
);
/* Set up SCA memory */
sca_init_port
(
port
);
/* Set up SCA memory */
printk
(
KERN_INFO
"%s: RISCom/N2 node %d
\n
"
,
dev
->
name
,
port
->
phy_node
);
...
...
drivers/net/wan/pc300too.c
View file @
c46920da
/*
* Cyclades PC300 synchronous serial card driver for Linux
*
* Copyright (C) 2000-200
7
Krzysztof Halasa <khc@pm.waw.pl>
* Copyright (C) 2000-200
8
Krzysztof Halasa <khc@pm.waw.pl>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License
...
...
@@ -11,7 +11,7 @@
*
* Sources of information:
* Hitachi HD64572 SCA-II User's Manual
* Cyclades PC300 Linux driver
*
Original
Cyclades PC300 Linux driver
*
* This driver currently supports only PC300/RSV (V.24/V.35) and
* PC300/X21 cards.
...
...
@@ -37,17 +37,11 @@
#include "hd64572.h"
static
const
char
*
version
=
"Cyclades PC300 driver version: 1.17"
;
static
const
char
*
devname
=
"PC300"
;
#undef DEBUG_PKT
#define DEBUG_RINGS
#define PC300_PLX_SIZE 0x80
/* PLX control window size (128 B) */
#define PC300_SCA_SIZE 0x400
/* SCA window size (1 KB) */
#define ALL_PAGES_ALWAYS_MAPPED
#define NEED_DETECT_RAM
#define NEED_SCA_MSCI_INTR
#define MAX_TX_BUFFERS 10
static
int
pci_clock_freq
=
33000000
;
...
...
@@ -81,7 +75,8 @@ typedef struct {
typedef
struct
port_s
{
struct
net_device
*
dev
;
struct
napi_struct
napi
;
struct
net_device
*
netdev
;
struct
card_s
*
card
;
spinlock_t
lock
;
/* TX lock */
sync_serial_settings
settings
;
...
...
@@ -93,7 +88,7 @@ typedef struct port_s {
u16
txin
;
/* tx ring buffer 'in' and 'last' pointers */
u16
txlast
;
u8
rxs
,
txs
,
tmc
;
/* SCA registers */
u8
phy_node
;
/* physical port # - 0 or 1 */
u8
chan
;
/* physical port # - 0 or 1 */
}
port_t
;
...
...
@@ -114,21 +109,10 @@ typedef struct card_s {
}
card_t
;
#define sca_in(reg, card) readb(card->scabase + (reg))
#define sca_out(value, reg, card) writeb(value, card->scabase + (reg))
#define sca_inw(reg, card) readw(card->scabase + (reg))
#define sca_outw(value, reg, card) writew(value, card->scabase + (reg))
#define sca_inl(reg, card) readl(card->scabase + (reg))
#define sca_outl(value, reg, card) writel(value, card->scabase + (reg))
#define port_to_card(port) (port->card)
#define log_node(port) (port->phy_node)
#define phy_node(port) (port->phy_node)
#define winbase(card) (card->rambase)
#define get_port(card, port) ((port) < (card)->n_ports ? \
(&(card)->ports[port]) : (NULL))
#include "hd6457
x
.c"
#include "hd6457
2
.c"
static
void
pc300_set_iface
(
port_t
*
port
)
...
...
@@ -139,8 +123,8 @@ static void pc300_set_iface(port_t *port)
u8
rxs
=
port
->
rxs
&
CLK_BRG_MASK
;
u8
txs
=
port
->
txs
&
CLK_BRG_MASK
;
sca_out
(
EXS_TES1
,
(
p
hy_node
(
port
)
?
MSCI1_OFFSET
:
MSCI0_OFFSET
)
+
EXS
,
port
_to_card
(
port
)
);
sca_out
(
EXS_TES1
,
(
p
ort
->
chan
?
MSCI1_OFFSET
:
MSCI0_OFFSET
)
+
EXS
,
port
->
card
);
switch
(
port
->
settings
.
clock_type
)
{
case
CLOCK_INT
:
rxs
|=
CLK_BRG
;
/* BRG output */
...
...
@@ -172,10 +156,10 @@ static void pc300_set_iface(port_t *port)
if
(
port
->
card
->
type
==
PC300_RSV
)
{
if
(
port
->
iface
==
IF_IFACE_V35
)
writel
(
card
->
init_ctrl_value
|
PC300_CHMEDIA_MASK
(
port
->
phy_node
),
init_ctrl
);
PC300_CHMEDIA_MASK
(
port
->
chan
),
init_ctrl
);
else
writel
(
card
->
init_ctrl_value
&
~
PC300_CHMEDIA_MASK
(
port
->
phy_node
),
init_ctrl
);
~
PC300_CHMEDIA_MASK
(
port
->
chan
),
init_ctrl
);
}
}
...
...
@@ -280,10 +264,8 @@ static void pc300_pci_remove_one(struct pci_dev *pdev)
card_t
*
card
=
pci_get_drvdata
(
pdev
);
for
(
i
=
0
;
i
<
2
;
i
++
)
if
(
card
->
ports
[
i
].
card
)
{
struct
net_device
*
dev
=
port_to_dev
(
&
card
->
ports
[
i
]);
unregister_hdlc_device
(
dev
);
}
if
(
card
->
ports
[
i
].
card
)
unregister_hdlc_device
(
card
->
ports
[
i
].
netdev
);
if
(
card
->
irq
)
free_irq
(
card
->
irq
,
card
);
...
...
@@ -298,10 +280,10 @@ static void pc300_pci_remove_one(struct pci_dev *pdev)
pci_release_regions
(
pdev
);
pci_disable_device
(
pdev
);
pci_set_drvdata
(
pdev
,
NULL
);
if
(
card
->
ports
[
0
].
dev
)
free_netdev
(
card
->
ports
[
0
].
dev
);
if
(
card
->
ports
[
1
].
dev
)
free_netdev
(
card
->
ports
[
1
].
dev
);
if
(
card
->
ports
[
0
].
net
dev
)
free_netdev
(
card
->
ports
[
0
].
net
dev
);
if
(
card
->
ports
[
1
].
net
dev
)
free_netdev
(
card
->
ports
[
1
].
net
dev
);
kfree
(
card
);
}
...
...
@@ -318,12 +300,6 @@ static int __devinit pc300_pci_init_one(struct pci_dev *pdev,
u32
scaphys
;
/* SCA memory base */
u32
plxphys
;
/* PLX registers memory base */
#ifndef MODULE
static
int
printed_version
;
if
(
!
printed_version
++
)
printk
(
KERN_INFO
"%s
\n
"
,
version
);
#endif
i
=
pci_enable_device
(
pdev
);
if
(
i
)
return
i
;
...
...
@@ -343,27 +319,6 @@ static int __devinit pc300_pci_init_one(struct pci_dev *pdev,
}
pci_set_drvdata
(
pdev
,
card
);
if
(
pdev
->
device
==
PCI_DEVICE_ID_PC300_TE_1
||
pdev
->
device
==
PCI_DEVICE_ID_PC300_TE_2
)
card
->
type
=
PC300_TE
;
/* not fully supported */
else
if
(
card
->
init_ctrl_value
&
PC300_CTYPE_MASK
)
card
->
type
=
PC300_X21
;
else
card
->
type
=
PC300_RSV
;
if
(
pdev
->
device
==
PCI_DEVICE_ID_PC300_RX_1
||
pdev
->
device
==
PCI_DEVICE_ID_PC300_TE_1
)
card
->
n_ports
=
1
;
else
card
->
n_ports
=
2
;
for
(
i
=
0
;
i
<
card
->
n_ports
;
i
++
)
if
(
!
(
card
->
ports
[
i
].
dev
=
alloc_hdlcdev
(
&
card
->
ports
[
i
])))
{
printk
(
KERN_ERR
"pc300: unable to allocate memory
\n
"
);
pc300_pci_remove_one
(
pdev
);
return
-
ENOMEM
;
}
if
(
pci_resource_len
(
pdev
,
0
)
!=
PC300_PLX_SIZE
||
pci_resource_len
(
pdev
,
2
)
!=
PC300_SCA_SIZE
||
pci_resource_len
(
pdev
,
3
)
<
16384
)
{
...
...
@@ -372,13 +327,13 @@ static int __devinit pc300_pci_init_one(struct pci_dev *pdev,
return
-
EFAULT
;
}
plxphys
=
pci_resource_start
(
pdev
,
0
)
&
PCI_BASE_ADDRESS_MEM_MASK
;
plxphys
=
pci_resource_start
(
pdev
,
0
)
&
PCI_BASE_ADDRESS_MEM_MASK
;
card
->
plxbase
=
ioremap
(
plxphys
,
PC300_PLX_SIZE
);
scaphys
=
pci_resource_start
(
pdev
,
2
)
&
PCI_BASE_ADDRESS_MEM_MASK
;
scaphys
=
pci_resource_start
(
pdev
,
2
)
&
PCI_BASE_ADDRESS_MEM_MASK
;
card
->
scabase
=
ioremap
(
scaphys
,
PC300_SCA_SIZE
);
ramphys
=
pci_resource_start
(
pdev
,
3
)
&
PCI_BASE_ADDRESS_MEM_MASK
;
ramphys
=
pci_resource_start
(
pdev
,
3
)
&
PCI_BASE_ADDRESS_MEM_MASK
;
card
->
rambase
=
pci_ioremap_bar
(
pdev
,
3
);
if
(
card
->
plxbase
==
NULL
||
...
...
@@ -393,6 +348,27 @@ static int __devinit pc300_pci_init_one(struct pci_dev *pdev,
card
->
init_ctrl_value
=
readl
(
&
((
plx9050
__iomem
*
)
card
->
scabase
)
->
init_ctrl
);
pci_write_config_dword
(
pdev
,
PCI_BASE_ADDRESS_0
,
plxphys
);
if
(
pdev
->
device
==
PCI_DEVICE_ID_PC300_TE_1
||
pdev
->
device
==
PCI_DEVICE_ID_PC300_TE_2
)
card
->
type
=
PC300_TE
;
/* not fully supported */
else
if
(
card
->
init_ctrl_value
&
PC300_CTYPE_MASK
)
card
->
type
=
PC300_X21
;
else
card
->
type
=
PC300_RSV
;
if
(
pdev
->
device
==
PCI_DEVICE_ID_PC300_RX_1
||
pdev
->
device
==
PCI_DEVICE_ID_PC300_TE_1
)
card
->
n_ports
=
1
;
else
card
->
n_ports
=
2
;
for
(
i
=
0
;
i
<
card
->
n_ports
;
i
++
)
if
(
!
(
card
->
ports
[
i
].
netdev
=
alloc_hdlcdev
(
&
card
->
ports
[
i
])))
{
printk
(
KERN_ERR
"pc300: unable to allocate memory
\n
"
);
pc300_pci_remove_one
(
pdev
);
return
-
ENOMEM
;
}
/* Reset PLX */
p
=
&
card
->
plxbase
->
init_ctrl
;
writel
(
card
->
init_ctrl_value
|
0x40000000
,
p
);
...
...
@@ -446,7 +422,7 @@ static int __devinit pc300_pci_init_one(struct pci_dev *pdev,
writew
(
0x0041
,
&
card
->
plxbase
->
intr_ctrl_stat
);
/* Allocate IRQ */
if
(
request_irq
(
pdev
->
irq
,
sca_intr
,
IRQF_SHARED
,
devname
,
card
))
{
if
(
request_irq
(
pdev
->
irq
,
sca_intr
,
IRQF_SHARED
,
"pc300"
,
card
))
{
printk
(
KERN_WARNING
"pc300: could not allocate IRQ%d.
\n
"
,
pdev
->
irq
);
pc300_pci_remove_one
(
pdev
);
...
...
@@ -463,9 +439,9 @@ static int __devinit pc300_pci_init_one(struct pci_dev *pdev,
for
(
i
=
0
;
i
<
card
->
n_ports
;
i
++
)
{
port_t
*
port
=
&
card
->
ports
[
i
];
struct
net_device
*
dev
=
port
_to_dev
(
port
)
;
struct
net_device
*
dev
=
port
->
netdev
;
hdlc_device
*
hdlc
=
dev_to_hdlc
(
dev
);
port
->
phy_node
=
i
;
port
->
chan
=
i
;
spin_lock_init
(
&
port
->
lock
);
dev
->
irq
=
card
->
irq
;
...
...
@@ -484,6 +460,7 @@ static int __devinit pc300_pci_init_one(struct pci_dev *pdev,
else
port
->
iface
=
IF_IFACE_V35
;
sca_init_port
(
port
);
if
(
register_hdlc_device
(
dev
))
{
printk
(
KERN_ERR
"pc300: unable to register hdlc "
"device
\n
"
);
...
...
@@ -491,10 +468,9 @@ static int __devinit pc300_pci_init_one(struct pci_dev *pdev,
pc300_pci_remove_one
(
pdev
);
return
-
ENOBUFS
;
}
sca_init_sync_port
(
port
);
/* Set up SCA memory */
printk
(
KERN_INFO
"%s: PC300
node
%d
\n
"
,
dev
->
name
,
port
->
phy_node
);
printk
(
KERN_INFO
"%s: PC300
channel
%d
\n
"
,
dev
->
name
,
port
->
chan
);
}
return
0
;
}
...
...
@@ -524,9 +500,6 @@ static struct pci_driver pc300_pci_driver = {
static
int
__init
pc300_init_module
(
void
)
{
#ifdef MODULE
printk
(
KERN_INFO
"%s
\n
"
,
version
);
#endif
if
(
pci_clock_freq
<
1000000
||
pci_clock_freq
>
80000000
)
{
printk
(
KERN_ERR
"pc300: Invalid PCI clock frequency
\n
"
);
return
-
EINVAL
;
...
...
drivers/net/wan/pci200syn.c
View file @
c46920da
/*
* Goramo PCI200SYN synchronous serial card driver for Linux
*
* Copyright (C) 2002-200
3
Krzysztof Halasa <khc@pm.waw.pl>
* Copyright (C) 2002-200
8
Krzysztof Halasa <khc@pm.waw.pl>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License
...
...
@@ -33,17 +33,11 @@
#include "hd64572.h"
static
const
char
*
version
=
"Goramo PCI200SYN driver version: 1.16"
;
static
const
char
*
devname
=
"PCI200SYN"
;
#undef DEBUG_PKT
#define DEBUG_RINGS
#define PCI200SYN_PLX_SIZE 0x80
/* PLX control window size (128b) */
#define PCI200SYN_SCA_SIZE 0x400
/* SCA window size (1Kb) */
#define ALL_PAGES_ALWAYS_MAPPED
#define NEED_DETECT_RAM
#define NEED_SCA_MSCI_INTR
#define MAX_TX_BUFFERS 10
static
int
pci_clock_freq
=
33000000
;
...
...
@@ -68,7 +62,8 @@ typedef struct {
typedef
struct
port_s
{
struct
net_device
*
dev
;
struct
napi_struct
napi
;
struct
net_device
*
netdev
;
struct
card_s
*
card
;
spinlock_t
lock
;
/* TX lock */
sync_serial_settings
settings
;
...
...
@@ -79,7 +74,7 @@ typedef struct port_s {
u16
txin
;
/* tx ring buffer 'in' and 'last' pointers */
u16
txlast
;
u8
rxs
,
txs
,
tmc
;
/* SCA registers */
u8
phy_node
;
/* physical port # - 0 or 1 */
u8
chan
;
/* physical port # - 0 or 1 */
}
port_t
;
...
...
@@ -97,17 +92,6 @@ typedef struct card_s {
}
card_t
;
#define sca_in(reg, card) readb(card->scabase + (reg))
#define sca_out(value, reg, card) writeb(value, card->scabase + (reg))
#define sca_inw(reg, card) readw(card->scabase + (reg))
#define sca_outw(value, reg, card) writew(value, card->scabase + (reg))
#define sca_inl(reg, card) readl(card->scabase + (reg))
#define sca_outl(value, reg, card) writel(value, card->scabase + (reg))
#define port_to_card(port) (port->card)
#define log_node(port) (port->phy_node)
#define phy_node(port) (port->phy_node)
#define winbase(card) (card->rambase)
#define get_port(card, port) (&card->ports[port])
#define sca_flush(card) (sca_in(IER0, card));
...
...
@@ -127,7 +111,7 @@ static inline void new_memcpy_toio(char __iomem *dest, char *src, int length)
#undef memcpy_toio
#define memcpy_toio new_memcpy_toio
#include "hd6457
x
.c"
#include "hd6457
2
.c"
static
void
pci200_set_iface
(
port_t
*
port
)
...
...
@@ -137,8 +121,8 @@ static void pci200_set_iface(port_t *port)
u8
rxs
=
port
->
rxs
&
CLK_BRG_MASK
;
u8
txs
=
port
->
txs
&
CLK_BRG_MASK
;
sca_out
(
EXS_TES1
,
(
p
hy_node
(
port
)
?
MSCI1_OFFSET
:
MSCI0_OFFSET
)
+
EXS
,
port
_to_card
(
port
)
);
sca_out
(
EXS_TES1
,
(
p
ort
->
chan
?
MSCI1_OFFSET
:
MSCI0_OFFSET
)
+
EXS
,
port
->
card
);
switch
(
port
->
settings
.
clock_type
)
{
case
CLOCK_INT
:
rxs
|=
CLK_BRG
;
/* BRG output */
...
...
@@ -180,7 +164,7 @@ static int pci200_open(struct net_device *dev)
sca_open
(
dev
);
pci200_set_iface
(
port
);
sca_flush
(
port
_to_card
(
port
)
);
sca_flush
(
port
->
card
);
return
0
;
}
...
...
@@ -189,7 +173,7 @@ static int pci200_open(struct net_device *dev)
static
int
pci200_close
(
struct
net_device
*
dev
)
{
sca_close
(
dev
);
sca_flush
(
port_to_card
(
dev_to_port
(
dev
))
);
sca_flush
(
dev_to_port
(
dev
)
->
card
);
hdlc_close
(
dev
);
return
0
;
}
...
...
@@ -242,7 +226,7 @@ static int pci200_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
memcpy
(
&
port
->
settings
,
&
new_line
,
size
);
/* Update settings */
pci200_set_iface
(
port
);
sca_flush
(
port
_to_card
(
port
)
);
sca_flush
(
port
->
card
);
return
0
;
default:
...
...
@@ -258,10 +242,8 @@ static void pci200_pci_remove_one(struct pci_dev *pdev)
card_t
*
card
=
pci_get_drvdata
(
pdev
);
for
(
i
=
0
;
i
<
2
;
i
++
)
if
(
card
->
ports
[
i
].
card
)
{
struct
net_device
*
dev
=
port_to_dev
(
&
card
->
ports
[
i
]);
unregister_hdlc_device
(
dev
);
}
if
(
card
->
ports
[
i
].
card
)
unregister_hdlc_device
(
card
->
ports
[
i
].
netdev
);
if
(
card
->
irq
)
free_irq
(
card
->
irq
,
card
);
...
...
@@ -276,10 +258,10 @@ static void pci200_pci_remove_one(struct pci_dev *pdev)
pci_release_regions
(
pdev
);
pci_disable_device
(
pdev
);
pci_set_drvdata
(
pdev
,
NULL
);
if
(
card
->
ports
[
0
].
dev
)
free_netdev
(
card
->
ports
[
0
].
dev
);
if
(
card
->
ports
[
1
].
dev
)
free_netdev
(
card
->
ports
[
1
].
dev
);
if
(
card
->
ports
[
0
].
net
dev
)
free_netdev
(
card
->
ports
[
0
].
net
dev
);
if
(
card
->
ports
[
1
].
net
dev
)
free_netdev
(
card
->
ports
[
1
].
net
dev
);
kfree
(
card
);
}
...
...
@@ -296,12 +278,6 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev,
u32
scaphys
;
/* SCA memory base */
u32
plxphys
;
/* PLX registers memory base */
#ifndef MODULE
static
int
printed_version
;
if
(
!
printed_version
++
)
printk
(
KERN_INFO
"%s
\n
"
,
version
);
#endif
i
=
pci_enable_device
(
pdev
);
if
(
i
)
return
i
;
...
...
@@ -320,9 +296,9 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev,
return
-
ENOBUFS
;
}
pci_set_drvdata
(
pdev
,
card
);
card
->
ports
[
0
].
dev
=
alloc_hdlcdev
(
&
card
->
ports
[
0
]);
card
->
ports
[
1
].
dev
=
alloc_hdlcdev
(
&
card
->
ports
[
1
]);
if
(
!
card
->
ports
[
0
].
dev
||
!
card
->
ports
[
1
].
dev
)
{
card
->
ports
[
0
].
net
dev
=
alloc_hdlcdev
(
&
card
->
ports
[
0
]);
card
->
ports
[
1
].
net
dev
=
alloc_hdlcdev
(
&
card
->
ports
[
1
]);
if
(
!
card
->
ports
[
0
].
netdev
||
!
card
->
ports
[
1
].
net
dev
)
{
printk
(
KERN_ERR
"pci200syn: unable to allocate memory
\n
"
);
pci200_pci_remove_one
(
pdev
);
return
-
ENOMEM
;
...
...
@@ -398,7 +374,7 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev,
writew
(
readw
(
p
)
|
0x0040
,
p
);
/* Allocate IRQ */
if
(
request_irq
(
pdev
->
irq
,
sca_intr
,
IRQF_SHARED
,
devname
,
card
))
{
if
(
request_irq
(
pdev
->
irq
,
sca_intr
,
IRQF_SHARED
,
"pci200syn"
,
card
))
{
printk
(
KERN_WARNING
"pci200syn: could not allocate IRQ%d.
\n
"
,
pdev
->
irq
);
pci200_pci_remove_one
(
pdev
);
...
...
@@ -410,9 +386,9 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev,
for
(
i
=
0
;
i
<
2
;
i
++
)
{
port_t
*
port
=
&
card
->
ports
[
i
];
struct
net_device
*
dev
=
port
_to_dev
(
port
)
;
struct
net_device
*
dev
=
port
->
netdev
;
hdlc_device
*
hdlc
=
dev_to_hdlc
(
dev
);
port
->
phy_node
=
i
;
port
->
chan
=
i
;
spin_lock_init
(
&
port
->
lock
);
dev
->
irq
=
card
->
irq
;
...
...
@@ -426,6 +402,7 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev,
hdlc
->
xmit
=
sca_xmit
;
port
->
settings
.
clock_type
=
CLOCK_EXT
;
port
->
card
=
card
;
sca_init_port
(
port
);
if
(
register_hdlc_device
(
dev
))
{
printk
(
KERN_ERR
"pci200syn: unable to register hdlc "
"device
\n
"
);
...
...
@@ -433,10 +410,9 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev,
pci200_pci_remove_one
(
pdev
);
return
-
ENOBUFS
;
}
sca_init_sync_port
(
port
);
/* Set up SCA memory */
printk
(
KERN_INFO
"%s: PCI200SYN
node
%d
\n
"
,
dev
->
name
,
port
->
phy_node
);
printk
(
KERN_INFO
"%s: PCI200SYN
channel
%d
\n
"
,
dev
->
name
,
port
->
chan
);
}
sca_flush
(
card
);
...
...
@@ -464,9 +440,6 @@ static struct pci_driver pci200_pci_driver = {
static
int
__init
pci200_init_module
(
void
)
{
#ifdef MODULE
printk
(
KERN_INFO
"%s
\n
"
,
version
);
#endif
if
(
pci_clock_freq
<
1000000
||
pci_clock_freq
>
80000000
)
{
printk
(
KERN_ERR
"pci200syn: Invalid PCI clock frequency
\n
"
);
return
-
EINVAL
;
...
...
drivers/net/wan/syncppp.c
deleted
100644 → 0
View file @
f5f4cf08
/*
* NET3: A (fairly minimal) implementation of synchronous PPP for Linux
* as well as a CISCO HDLC implementation. See the copyright
* message below for the original source.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the license, or (at your option) any later version.
*
* Note however. This code is also used in a different form by FreeBSD.
* Therefore when making any non OS specific change please consider
* contributing it back to the original author under the terms
* below in addition.
* -- Alan
*
* Port for Linux-2.1 by Jan "Yenya" Kasprzak <kas@fi.muni.cz>
*/
/*
* Synchronous PPP/Cisco link level subroutines.
* Keepalive protocol implemented in both Cisco and PPP modes.
*
* Copyright (C) 1994 Cronyx Ltd.
* Author: Serge Vakulenko, <vak@zebub.msk.su>
*
* This software is distributed with NO WARRANTIES, not even the implied
* warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* Authors grant any other persons or organisations permission to use
* or modify this software as long as this message is kept with the software,
* all derivative works or modified versions.
*
* Version 1.9, Wed Oct 4 18:58:15 MSK 1995
*
* $Id: syncppp.c,v 1.18 2000/04/11 05:25:31 asj Exp $
*/
#undef DEBUG
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/if_arp.h>
#include <linux/skbuff.h>
#include <linux/route.h>
#include <linux/netdevice.h>
#include <linux/inetdevice.h>
#include <linux/random.h>
#include <linux/pkt_sched.h>
#include <linux/spinlock.h>
#include <linux/rcupdate.h>
#include <net/net_namespace.h>
#include <net/syncppp.h>
#include <asm/byteorder.h>
#include <asm/uaccess.h>
#define MAXALIVECNT 6
/* max. alive packets */
#define PPP_ALLSTATIONS 0xff
/* All-Stations broadcast address */
#define PPP_UI 0x03
/* Unnumbered Information */
#define PPP_IP 0x0021
/* Internet Protocol */
#define PPP_ISO 0x0023
/* ISO OSI Protocol */
#define PPP_XNS 0x0025
/* Xerox NS Protocol */
#define PPP_IPX 0x002b
/* Novell IPX Protocol */
#define PPP_LCP 0xc021
/* Link Control Protocol */
#define PPP_IPCP 0x8021
/* Internet Protocol Control Protocol */
#define LCP_CONF_REQ 1
/* PPP LCP configure request */
#define LCP_CONF_ACK 2
/* PPP LCP configure acknowledge */
#define LCP_CONF_NAK 3
/* PPP LCP configure negative ack */
#define LCP_CONF_REJ 4
/* PPP LCP configure reject */
#define LCP_TERM_REQ 5
/* PPP LCP terminate request */
#define LCP_TERM_ACK 6
/* PPP LCP terminate acknowledge */
#define LCP_CODE_REJ 7
/* PPP LCP code reject */
#define LCP_PROTO_REJ 8
/* PPP LCP protocol reject */
#define LCP_ECHO_REQ 9
/* PPP LCP echo request */
#define LCP_ECHO_REPLY 10
/* PPP LCP echo reply */
#define LCP_DISC_REQ 11
/* PPP LCP discard request */
#define LCP_OPT_MRU 1
/* maximum receive unit */
#define LCP_OPT_ASYNC_MAP 2
/* async control character map */
#define LCP_OPT_AUTH_PROTO 3
/* authentication protocol */
#define LCP_OPT_QUAL_PROTO 4
/* quality protocol */
#define LCP_OPT_MAGIC 5
/* magic number */
#define LCP_OPT_RESERVED 6
/* reserved */
#define LCP_OPT_PROTO_COMP 7
/* protocol field compression */
#define LCP_OPT_ADDR_COMP 8
/* address/control field compression */
#define IPCP_CONF_REQ LCP_CONF_REQ
/* PPP IPCP configure request */
#define IPCP_CONF_ACK LCP_CONF_ACK
/* PPP IPCP configure acknowledge */
#define IPCP_CONF_NAK LCP_CONF_NAK
/* PPP IPCP configure negative ack */
#define IPCP_CONF_REJ LCP_CONF_REJ
/* PPP IPCP configure reject */
#define IPCP_TERM_REQ LCP_TERM_REQ
/* PPP IPCP terminate request */
#define IPCP_TERM_ACK LCP_TERM_ACK
/* PPP IPCP terminate acknowledge */
#define IPCP_CODE_REJ LCP_CODE_REJ
/* PPP IPCP code reject */
#define CISCO_MULTICAST 0x8f
/* Cisco multicast address */
#define CISCO_UNICAST 0x0f
/* Cisco unicast address */
#define CISCO_KEEPALIVE 0x8035
/* Cisco keepalive protocol */
#define CISCO_ADDR_REQ 0
/* Cisco address request */
#define CISCO_ADDR_REPLY 1
/* Cisco address reply */
#define CISCO_KEEPALIVE_REQ 2
/* Cisco keepalive request */
struct
ppp_header
{
u8
address
;
u8
control
;
__be16
protocol
;
};
#define PPP_HEADER_LEN sizeof (struct ppp_header)
struct
lcp_header
{
u8
type
;
u8
ident
;
__be16
len
;
};
#define LCP_HEADER_LEN sizeof (struct lcp_header)
struct
cisco_packet
{
__be32
type
;
__be32
par1
;
__be32
par2
;
__be16
rel
;
__be16
time0
;
__be16
time1
;
};
#define CISCO_PACKET_LEN 18
#define CISCO_BIG_PACKET_LEN 20
static
struct
sppp
*
spppq
;
static
struct
timer_list
sppp_keepalive_timer
;
static
DEFINE_SPINLOCK
(
spppq_lock
);
/* global xmit queue for sending packets while spinlock is held */
static
struct
sk_buff_head
tx_queue
;
static
void
sppp_keepalive
(
unsigned
long
dummy
);
static
void
sppp_cp_send
(
struct
sppp
*
sp
,
u16
proto
,
u8
type
,
u8
ident
,
u16
len
,
void
*
data
);
static
void
sppp_cisco_send
(
struct
sppp
*
sp
,
int
type
,
u32
par1
,
u32
par2
);
static
void
sppp_lcp_input
(
struct
sppp
*
sp
,
struct
sk_buff
*
m
);
static
void
sppp_cisco_input
(
struct
sppp
*
sp
,
struct
sk_buff
*
m
);
static
void
sppp_ipcp_input
(
struct
sppp
*
sp
,
struct
sk_buff
*
m
);
static
void
sppp_lcp_open
(
struct
sppp
*
sp
);
static
void
sppp_ipcp_open
(
struct
sppp
*
sp
);
static
int
sppp_lcp_conf_parse_options
(
struct
sppp
*
sp
,
struct
lcp_header
*
h
,
int
len
,
u32
*
magic
);
static
void
sppp_cp_timeout
(
unsigned
long
arg
);
static
char
*
sppp_lcp_type_name
(
u8
type
);
static
char
*
sppp_ipcp_type_name
(
u8
type
);
static
void
sppp_print_bytes
(
u8
*
p
,
u16
len
);
static
int
debug
;
/* Flush global outgoing packet queue to dev_queue_xmit().
*
* dev_queue_xmit() must be called with interrupts enabled
* which means it can't be called with spinlocks held.
* If a packet needs to be sent while a spinlock is held,
* then put the packet into tx_queue, and call sppp_flush_xmit()
* after spinlock is released.
*/
static
void
sppp_flush_xmit
(
void
)
{
struct
sk_buff
*
skb
;
while
((
skb
=
skb_dequeue
(
&
tx_queue
))
!=
NULL
)
dev_queue_xmit
(
skb
);
}
/*
* Interface down stub
*/
static
void
if_down
(
struct
net_device
*
dev
)
{
struct
sppp
*
sp
=
(
struct
sppp
*
)
sppp_of
(
dev
);
sp
->
pp_link_state
=
SPPP_LINK_DOWN
;
}
/*
* Timeout routine activations.
*/
static
void
sppp_set_timeout
(
struct
sppp
*
p
,
int
s
)
{
if
(
!
(
p
->
pp_flags
&
PP_TIMO
))
{
init_timer
(
&
p
->
pp_timer
);
p
->
pp_timer
.
function
=
sppp_cp_timeout
;
p
->
pp_timer
.
expires
=
jiffies
+
s
*
HZ
;
p
->
pp_timer
.
data
=
(
unsigned
long
)
p
;
p
->
pp_flags
|=
PP_TIMO
;
add_timer
(
&
p
->
pp_timer
);
}
}
static
void
sppp_clear_timeout
(
struct
sppp
*
p
)
{
if
(
p
->
pp_flags
&
PP_TIMO
)
{
del_timer
(
&
p
->
pp_timer
);
p
->
pp_flags
&=
~
PP_TIMO
;
}
}
/**
* sppp_input - receive and process a WAN PPP frame
* @skb: The buffer to process
* @dev: The device it arrived on
*
* This can be called directly by cards that do not have
* timing constraints but is normally called from the network layer
* after interrupt servicing to process frames queued via netif_rx().
*
* We process the options in the card. If the frame is destined for
* the protocol stacks then it requeues the frame for the upper level
* protocol. If it is a control from it is processed and discarded
* here.
*/
static
void
sppp_input
(
struct
net_device
*
dev
,
struct
sk_buff
*
skb
)
{
struct
ppp_header
*
h
;
struct
sppp
*
sp
=
(
struct
sppp
*
)
sppp_of
(
dev
);
unsigned
long
flags
;
skb
->
dev
=
dev
;
skb_reset_mac_header
(
skb
);
if
(
!
pskb_may_pull
(
skb
,
PPP_HEADER_LEN
))
{
/* Too small packet, drop it. */
if
(
sp
->
pp_flags
&
PP_DEBUG
)
printk
(
KERN_DEBUG
"%s: input packet is too small, %d bytes
\n
"
,
dev
->
name
,
skb
->
len
);
kfree_skb
(
skb
);
return
;
}
/* Get PPP header. */
h
=
(
struct
ppp_header
*
)
skb
->
data
;
skb_pull
(
skb
,
sizeof
(
struct
ppp_header
));
spin_lock_irqsave
(
&
sp
->
lock
,
flags
);
switch
(
h
->
address
)
{
default:
/* Invalid PPP packet. */
goto
invalid
;
case
PPP_ALLSTATIONS
:
if
(
h
->
control
!=
PPP_UI
)
goto
invalid
;
if
(
sp
->
pp_flags
&
PP_CISCO
)
{
if
(
sp
->
pp_flags
&
PP_DEBUG
)
printk
(
KERN_WARNING
"%s: PPP packet in Cisco mode <0x%x 0x%x 0x%x>
\n
"
,
dev
->
name
,
h
->
address
,
h
->
control
,
ntohs
(
h
->
protocol
));
goto
drop
;
}
switch
(
ntohs
(
h
->
protocol
))
{
default:
if
(
sp
->
lcp
.
state
==
LCP_STATE_OPENED
)
sppp_cp_send
(
sp
,
PPP_LCP
,
LCP_PROTO_REJ
,
++
sp
->
pp_seq
,
skb
->
len
+
2
,
&
h
->
protocol
);
if
(
sp
->
pp_flags
&
PP_DEBUG
)
printk
(
KERN_WARNING
"%s: invalid input protocol <0x%x 0x%x 0x%x>
\n
"
,
dev
->
name
,
h
->
address
,
h
->
control
,
ntohs
(
h
->
protocol
));
goto
drop
;
case
PPP_LCP
:
sppp_lcp_input
(
sp
,
skb
);
goto
drop
;
case
PPP_IPCP
:
if
(
sp
->
lcp
.
state
==
LCP_STATE_OPENED
)
sppp_ipcp_input
(
sp
,
skb
);
else
printk
(
KERN_DEBUG
"IPCP when still waiting LCP finish.
\n
"
);
goto
drop
;
case
PPP_IP
:
if
(
sp
->
ipcp
.
state
==
IPCP_STATE_OPENED
)
{
if
(
sp
->
pp_flags
&
PP_DEBUG
)
printk
(
KERN_DEBUG
"Yow an IP frame.
\n
"
);
skb
->
protocol
=
htons
(
ETH_P_IP
);
netif_rx
(
skb
);
goto
done
;
}
break
;
#ifdef IPX
case
PPP_IPX
:
/* IPX IPXCP not implemented yet */
if
(
sp
->
lcp
.
state
==
LCP_STATE_OPENED
)
{
skb
->
protocol
=
htons
(
ETH_P_IPX
);
netif_rx
(
skb
);
goto
done
;
}
break
;
#endif
}
break
;
case
CISCO_MULTICAST
:
case
CISCO_UNICAST
:
/* Don't check the control field here (RFC 1547). */
if
(
!
(
sp
->
pp_flags
&
PP_CISCO
))
{
if
(
sp
->
pp_flags
&
PP_DEBUG
)
printk
(
KERN_WARNING
"%s: Cisco packet in PPP mode <0x%x 0x%x 0x%x>
\n
"
,
dev
->
name
,
h
->
address
,
h
->
control
,
ntohs
(
h
->
protocol
));
goto
drop
;
}
switch
(
ntohs
(
h
->
protocol
))
{
default:
goto
invalid
;
case
CISCO_KEEPALIVE
:
sppp_cisco_input
(
sp
,
skb
);
goto
drop
;
#ifdef CONFIG_INET
case
ETH_P_IP
:
skb
->
protocol
=
htons
(
ETH_P_IP
);
netif_rx
(
skb
);
goto
done
;
#endif
#ifdef CONFIG_IPX
case
ETH_P_IPX
:
skb
->
protocol
=
htons
(
ETH_P_IPX
);
netif_rx
(
skb
);
goto
done
;
#endif
}
break
;
}
goto
drop
;
invalid:
if
(
sp
->
pp_flags
&
PP_DEBUG
)
printk
(
KERN_WARNING
"%s: invalid input packet <0x%x 0x%x 0x%x>
\n
"
,
dev
->
name
,
h
->
address
,
h
->
control
,
ntohs
(
h
->
protocol
));
drop:
kfree_skb
(
skb
);
done:
spin_unlock_irqrestore
(
&
sp
->
lock
,
flags
);
sppp_flush_xmit
();
return
;
}
/*
* Handle transmit packets.
*/
static
int
sppp_hard_header
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
,
__u16
type
,
const
void
*
daddr
,
const
void
*
saddr
,
unsigned
int
len
)
{
struct
sppp
*
sp
=
(
struct
sppp
*
)
sppp_of
(
dev
);
struct
ppp_header
*
h
;
skb_push
(
skb
,
sizeof
(
struct
ppp_header
));
h
=
(
struct
ppp_header
*
)
skb
->
data
;
if
(
sp
->
pp_flags
&
PP_CISCO
)
{
h
->
address
=
CISCO_UNICAST
;
h
->
control
=
0
;
}
else
{
h
->
address
=
PPP_ALLSTATIONS
;
h
->
control
=
PPP_UI
;
}
if
(
sp
->
pp_flags
&
PP_CISCO
)
{
h
->
protocol
=
htons
(
type
);
}
else
switch
(
type
)
{
case
ETH_P_IP
:
h
->
protocol
=
htons
(
PPP_IP
);
break
;
case
ETH_P_IPX
:
h
->
protocol
=
htons
(
PPP_IPX
);
break
;
}
return
sizeof
(
struct
ppp_header
);
}
static
const
struct
header_ops
sppp_header_ops
=
{
.
create
=
sppp_hard_header
,
};
/*
* Send keepalive packets, every 10 seconds.
*/
static
void
sppp_keepalive
(
unsigned
long
dummy
)
{
struct
sppp
*
sp
;
unsigned
long
flags
;
spin_lock_irqsave
(
&
spppq_lock
,
flags
);
for
(
sp
=
spppq
;
sp
;
sp
=
sp
->
pp_next
)
{
struct
net_device
*
dev
=
sp
->
pp_if
;
/* Keepalive mode disabled or channel down? */
if
(
!
(
sp
->
pp_flags
&
PP_KEEPALIVE
)
||
!
(
dev
->
flags
&
IFF_UP
))
continue
;
spin_lock
(
&
sp
->
lock
);
/* No keepalive in PPP mode if LCP not opened yet. */
if
(
!
(
sp
->
pp_flags
&
PP_CISCO
)
&&
sp
->
lcp
.
state
!=
LCP_STATE_OPENED
)
{
spin_unlock
(
&
sp
->
lock
);
continue
;
}
if
(
sp
->
pp_alivecnt
==
MAXALIVECNT
)
{
/* No keepalive packets got. Stop the interface. */
printk
(
KERN_WARNING
"%s: protocol down
\n
"
,
dev
->
name
);
if_down
(
dev
);
if
(
!
(
sp
->
pp_flags
&
PP_CISCO
))
{
/* Shut down the PPP link. */
sp
->
lcp
.
magic
=
jiffies
;
sp
->
lcp
.
state
=
LCP_STATE_CLOSED
;
sp
->
ipcp
.
state
=
IPCP_STATE_CLOSED
;
sppp_clear_timeout
(
sp
);
/* Initiate negotiation. */
sppp_lcp_open
(
sp
);
}
}
if
(
sp
->
pp_alivecnt
<=
MAXALIVECNT
)
++
sp
->
pp_alivecnt
;
if
(
sp
->
pp_flags
&
PP_CISCO
)
sppp_cisco_send
(
sp
,
CISCO_KEEPALIVE_REQ
,
++
sp
->
pp_seq
,
sp
->
pp_rseq
);
else
if
(
sp
->
lcp
.
state
==
LCP_STATE_OPENED
)
{
__be32
nmagic
=
htonl
(
sp
->
lcp
.
magic
);
sp
->
lcp
.
echoid
=
++
sp
->
pp_seq
;
sppp_cp_send
(
sp
,
PPP_LCP
,
LCP_ECHO_REQ
,
sp
->
lcp
.
echoid
,
4
,
&
nmagic
);
}
spin_unlock
(
&
sp
->
lock
);
}
spin_unlock_irqrestore
(
&
spppq_lock
,
flags
);
sppp_flush_xmit
();
sppp_keepalive_timer
.
expires
=
jiffies
+
10
*
HZ
;
add_timer
(
&
sppp_keepalive_timer
);
}
/*
* Handle incoming PPP Link Control Protocol packets.
*/
static
void
sppp_lcp_input
(
struct
sppp
*
sp
,
struct
sk_buff
*
skb
)
{
struct
lcp_header
*
h
;
struct
net_device
*
dev
=
sp
->
pp_if
;
int
len
=
skb
->
len
;
u8
*
p
,
opt
[
6
];
u32
rmagic
=
0
;
if
(
!
pskb_may_pull
(
skb
,
sizeof
(
struct
lcp_header
)))
{
if
(
sp
->
pp_flags
&
PP_DEBUG
)
printk
(
KERN_WARNING
"%s: invalid lcp packet length: %d bytes
\n
"
,
dev
->
name
,
len
);
return
;
}
h
=
(
struct
lcp_header
*
)
skb
->
data
;
skb_pull
(
skb
,
sizeof
(
struct
lcp_header
*
));
if
(
sp
->
pp_flags
&
PP_DEBUG
)
{
char
state
=
'?'
;
switch
(
sp
->
lcp
.
state
)
{
case
LCP_STATE_CLOSED
:
state
=
'C'
;
break
;
case
LCP_STATE_ACK_RCVD
:
state
=
'R'
;
break
;
case
LCP_STATE_ACK_SENT
:
state
=
'S'
;
break
;
case
LCP_STATE_OPENED
:
state
=
'O'
;
break
;
}
printk
(
KERN_WARNING
"%s: lcp input(%c): %d bytes <%s id=%xh len=%xh"
,
dev
->
name
,
state
,
len
,
sppp_lcp_type_name
(
h
->
type
),
h
->
ident
,
ntohs
(
h
->
len
));
if
(
len
>
4
)
sppp_print_bytes
((
u8
*
)
(
h
+
1
),
len
-
4
);
printk
(
">
\n
"
);
}
if
(
len
>
ntohs
(
h
->
len
))
len
=
ntohs
(
h
->
len
);
switch
(
h
->
type
)
{
default:
/* Unknown packet type -- send Code-Reject packet. */
sppp_cp_send
(
sp
,
PPP_LCP
,
LCP_CODE_REJ
,
++
sp
->
pp_seq
,
skb
->
len
,
h
);
break
;
case
LCP_CONF_REQ
:
if
(
len
<
4
)
{
if
(
sp
->
pp_flags
&
PP_DEBUG
)
printk
(
KERN_DEBUG
"%s: invalid lcp configure request packet length: %d bytes
\n
"
,
dev
->
name
,
len
);
break
;
}
if
(
len
>
4
&&
!
sppp_lcp_conf_parse_options
(
sp
,
h
,
len
,
&
rmagic
))
goto
badreq
;
if
(
rmagic
==
sp
->
lcp
.
magic
)
{
/* Local and remote magics equal -- loopback? */
if
(
sp
->
pp_loopcnt
>=
MAXALIVECNT
*
5
)
{
printk
(
KERN_WARNING
"%s: loopback
\n
"
,
dev
->
name
);
sp
->
pp_loopcnt
=
0
;
if
(
dev
->
flags
&
IFF_UP
)
{
if_down
(
dev
);
}
}
else
if
(
sp
->
pp_flags
&
PP_DEBUG
)
printk
(
KERN_DEBUG
"%s: conf req: magic glitch
\n
"
,
dev
->
name
);
++
sp
->
pp_loopcnt
;
/* MUST send Conf-Nack packet. */
rmagic
=
~
sp
->
lcp
.
magic
;
opt
[
0
]
=
LCP_OPT_MAGIC
;
opt
[
1
]
=
sizeof
(
opt
);
opt
[
2
]
=
rmagic
>>
24
;
opt
[
3
]
=
rmagic
>>
16
;
opt
[
4
]
=
rmagic
>>
8
;
opt
[
5
]
=
rmagic
;
sppp_cp_send
(
sp
,
PPP_LCP
,
LCP_CONF_NAK
,
h
->
ident
,
sizeof
(
opt
),
&
opt
);
badreq:
switch
(
sp
->
lcp
.
state
)
{
case
LCP_STATE_OPENED
:
/* Initiate renegotiation. */
sppp_lcp_open
(
sp
);
/* fall through... */
case
LCP_STATE_ACK_SENT
:
/* Go to closed state. */
sp
->
lcp
.
state
=
LCP_STATE_CLOSED
;
sp
->
ipcp
.
state
=
IPCP_STATE_CLOSED
;
}
break
;
}
/* Send Configure-Ack packet. */
sp
->
pp_loopcnt
=
0
;
if
(
sp
->
lcp
.
state
!=
LCP_STATE_OPENED
)
{
sppp_cp_send
(
sp
,
PPP_LCP
,
LCP_CONF_ACK
,
h
->
ident
,
len
-
4
,
h
+
1
);
}
/* Change the state. */
switch
(
sp
->
lcp
.
state
)
{
case
LCP_STATE_CLOSED
:
sp
->
lcp
.
state
=
LCP_STATE_ACK_SENT
;
break
;
case
LCP_STATE_ACK_RCVD
:
sp
->
lcp
.
state
=
LCP_STATE_OPENED
;
sppp_ipcp_open
(
sp
);
break
;
case
LCP_STATE_OPENED
:
/* Remote magic changed -- close session. */
sp
->
lcp
.
state
=
LCP_STATE_CLOSED
;
sp
->
ipcp
.
state
=
IPCP_STATE_CLOSED
;
/* Initiate renegotiation. */
sppp_lcp_open
(
sp
);
/* Send ACK after our REQ in attempt to break loop */
sppp_cp_send
(
sp
,
PPP_LCP
,
LCP_CONF_ACK
,
h
->
ident
,
len
-
4
,
h
+
1
);
sp
->
lcp
.
state
=
LCP_STATE_ACK_SENT
;
break
;
}
break
;
case
LCP_CONF_ACK
:
if
(
h
->
ident
!=
sp
->
lcp
.
confid
)
break
;
sppp_clear_timeout
(
sp
);
if
((
sp
->
pp_link_state
!=
SPPP_LINK_UP
)
&&
(
dev
->
flags
&
IFF_UP
))
{
/* Coming out of loopback mode. */
sp
->
pp_link_state
=
SPPP_LINK_UP
;
printk
(
KERN_INFO
"%s: protocol up
\n
"
,
dev
->
name
);
}
switch
(
sp
->
lcp
.
state
)
{
case
LCP_STATE_CLOSED
:
sp
->
lcp
.
state
=
LCP_STATE_ACK_RCVD
;
sppp_set_timeout
(
sp
,
5
);
break
;
case
LCP_STATE_ACK_SENT
:
sp
->
lcp
.
state
=
LCP_STATE_OPENED
;
sppp_ipcp_open
(
sp
);
break
;
}
break
;
case
LCP_CONF_NAK
:
if
(
h
->
ident
!=
sp
->
lcp
.
confid
)
break
;
p
=
(
u8
*
)
(
h
+
1
);
if
(
len
>=
10
&&
p
[
0
]
==
LCP_OPT_MAGIC
&&
p
[
1
]
>=
4
)
{
rmagic
=
(
u32
)
p
[
2
]
<<
24
|
(
u32
)
p
[
3
]
<<
16
|
p
[
4
]
<<
8
|
p
[
5
];
if
(
rmagic
==
~
sp
->
lcp
.
magic
)
{
int
newmagic
;
if
(
sp
->
pp_flags
&
PP_DEBUG
)
printk
(
KERN_DEBUG
"%s: conf nak: magic glitch
\n
"
,
dev
->
name
);
get_random_bytes
(
&
newmagic
,
sizeof
(
newmagic
));
sp
->
lcp
.
magic
+=
newmagic
;
}
else
sp
->
lcp
.
magic
=
rmagic
;
}
if
(
sp
->
lcp
.
state
!=
LCP_STATE_ACK_SENT
)
{
/* Go to closed state. */
sp
->
lcp
.
state
=
LCP_STATE_CLOSED
;
sp
->
ipcp
.
state
=
IPCP_STATE_CLOSED
;
}
/* The link will be renegotiated after timeout,
* to avoid endless req-nack loop. */
sppp_clear_timeout
(
sp
);
sppp_set_timeout
(
sp
,
2
);
break
;
case
LCP_CONF_REJ
:
if
(
h
->
ident
!=
sp
->
lcp
.
confid
)
break
;
sppp_clear_timeout
(
sp
);
/* Initiate renegotiation. */
sppp_lcp_open
(
sp
);
if
(
sp
->
lcp
.
state
!=
LCP_STATE_ACK_SENT
)
{
/* Go to closed state. */
sp
->
lcp
.
state
=
LCP_STATE_CLOSED
;
sp
->
ipcp
.
state
=
IPCP_STATE_CLOSED
;
}
break
;
case
LCP_TERM_REQ
:
sppp_clear_timeout
(
sp
);
/* Send Terminate-Ack packet. */
sppp_cp_send
(
sp
,
PPP_LCP
,
LCP_TERM_ACK
,
h
->
ident
,
0
,
NULL
);
/* Go to closed state. */
sp
->
lcp
.
state
=
LCP_STATE_CLOSED
;
sp
->
ipcp
.
state
=
IPCP_STATE_CLOSED
;
/* Initiate renegotiation. */
sppp_lcp_open
(
sp
);
break
;
case
LCP_TERM_ACK
:
case
LCP_CODE_REJ
:
case
LCP_PROTO_REJ
:
/* Ignore for now. */
break
;
case
LCP_DISC_REQ
:
/* Discard the packet. */
break
;
case
LCP_ECHO_REQ
:
if
(
sp
->
lcp
.
state
!=
LCP_STATE_OPENED
)
break
;
if
(
len
<
8
)
{
if
(
sp
->
pp_flags
&
PP_DEBUG
)
printk
(
KERN_WARNING
"%s: invalid lcp echo request packet length: %d bytes
\n
"
,
dev
->
name
,
len
);
break
;
}
if
(
ntohl
(
*
(
__be32
*
)(
h
+
1
))
==
sp
->
lcp
.
magic
)
{
/* Line loopback mode detected. */
printk
(
KERN_WARNING
"%s: loopback
\n
"
,
dev
->
name
);
if_down
(
dev
);
/* Shut down the PPP link. */
sp
->
lcp
.
state
=
LCP_STATE_CLOSED
;
sp
->
ipcp
.
state
=
IPCP_STATE_CLOSED
;
sppp_clear_timeout
(
sp
);
/* Initiate negotiation. */
sppp_lcp_open
(
sp
);
break
;
}
*
(
__be32
*
)(
h
+
1
)
=
htonl
(
sp
->
lcp
.
magic
);
sppp_cp_send
(
sp
,
PPP_LCP
,
LCP_ECHO_REPLY
,
h
->
ident
,
len
-
4
,
h
+
1
);
break
;
case
LCP_ECHO_REPLY
:
if
(
h
->
ident
!=
sp
->
lcp
.
echoid
)
break
;
if
(
len
<
8
)
{
if
(
sp
->
pp_flags
&
PP_DEBUG
)
printk
(
KERN_WARNING
"%s: invalid lcp echo reply packet length: %d bytes
\n
"
,
dev
->
name
,
len
);
break
;
}
if
(
ntohl
(
*
(
__be32
*
)(
h
+
1
))
!=
sp
->
lcp
.
magic
)
sp
->
pp_alivecnt
=
0
;
break
;
}
}
/*
* Handle incoming Cisco keepalive protocol packets.
*/
static
void
sppp_cisco_input
(
struct
sppp
*
sp
,
struct
sk_buff
*
skb
)
{
struct
cisco_packet
*
h
;
struct
net_device
*
dev
=
sp
->
pp_if
;
if
(
!
pskb_may_pull
(
skb
,
sizeof
(
struct
cisco_packet
))
||
(
skb
->
len
!=
CISCO_PACKET_LEN
&&
skb
->
len
!=
CISCO_BIG_PACKET_LEN
))
{
if
(
sp
->
pp_flags
&
PP_DEBUG
)
printk
(
KERN_WARNING
"%s: invalid cisco packet length: %d bytes
\n
"
,
dev
->
name
,
skb
->
len
);
return
;
}
h
=
(
struct
cisco_packet
*
)
skb
->
data
;
skb_pull
(
skb
,
sizeof
(
struct
cisco_packet
*
));
if
(
sp
->
pp_flags
&
PP_DEBUG
)
printk
(
KERN_WARNING
"%s: cisco input: %d bytes <%xh %xh %xh %xh %xh-%xh>
\n
"
,
dev
->
name
,
skb
->
len
,
ntohl
(
h
->
type
),
h
->
par1
,
h
->
par2
,
h
->
rel
,
h
->
time0
,
h
->
time1
);
switch
(
ntohl
(
h
->
type
))
{
default:
if
(
sp
->
pp_flags
&
PP_DEBUG
)
printk
(
KERN_WARNING
"%s: unknown cisco packet type: 0x%x
\n
"
,
dev
->
name
,
ntohl
(
h
->
type
));
break
;
case
CISCO_ADDR_REPLY
:
/* Reply on address request, ignore */
break
;
case
CISCO_KEEPALIVE_REQ
:
sp
->
pp_alivecnt
=
0
;
sp
->
pp_rseq
=
ntohl
(
h
->
par1
);
if
(
sp
->
pp_seq
==
sp
->
pp_rseq
)
{
/* Local and remote sequence numbers are equal.
* Probably, the line is in loopback mode. */
int
newseq
;
if
(
sp
->
pp_loopcnt
>=
MAXALIVECNT
)
{
printk
(
KERN_WARNING
"%s: loopback
\n
"
,
dev
->
name
);
sp
->
pp_loopcnt
=
0
;
if
(
dev
->
flags
&
IFF_UP
)
{
if_down
(
dev
);
}
}
++
sp
->
pp_loopcnt
;
/* Generate new local sequence number */
get_random_bytes
(
&
newseq
,
sizeof
(
newseq
));
sp
->
pp_seq
^=
newseq
;
break
;
}
sp
->
pp_loopcnt
=
0
;
if
(
sp
->
pp_link_state
==
SPPP_LINK_DOWN
&&
(
dev
->
flags
&
IFF_UP
))
{
sp
->
pp_link_state
=
SPPP_LINK_UP
;
printk
(
KERN_INFO
"%s: protocol up
\n
"
,
dev
->
name
);
}
break
;
case
CISCO_ADDR_REQ
:
/* Stolen from net/ipv4/devinet.c -- SIOCGIFADDR ioctl */
{
__be32
addr
=
0
,
mask
=
htonl
(
~
0U
);
/* FIXME: is the mask correct? */
#ifdef CONFIG_INET
struct
in_device
*
in_dev
;
struct
in_ifaddr
*
ifa
;
rcu_read_lock
();
if
((
in_dev
=
__in_dev_get_rcu
(
dev
))
!=
NULL
)
{
for
(
ifa
=
in_dev
->
ifa_list
;
ifa
!=
NULL
;
ifa
=
ifa
->
ifa_next
)
{
if
(
strcmp
(
dev
->
name
,
ifa
->
ifa_label
)
==
0
)
{
addr
=
ifa
->
ifa_local
;
mask
=
ifa
->
ifa_mask
;
break
;
}
}
}
rcu_read_unlock
();
#endif
sppp_cisco_send
(
sp
,
CISCO_ADDR_REPLY
,
ntohl
(
addr
),
ntohl
(
mask
));
break
;
}
}
}
/*
* Send PPP LCP packet.
*/
static
void
sppp_cp_send
(
struct
sppp
*
sp
,
u16
proto
,
u8
type
,
u8
ident
,
u16
len
,
void
*
data
)
{
struct
ppp_header
*
h
;
struct
lcp_header
*
lh
;
struct
sk_buff
*
skb
;
struct
net_device
*
dev
=
sp
->
pp_if
;
skb
=
alloc_skb
(
dev
->
hard_header_len
+
PPP_HEADER_LEN
+
LCP_HEADER_LEN
+
len
,
GFP_ATOMIC
);
if
(
skb
==
NULL
)
return
;
skb_reserve
(
skb
,
dev
->
hard_header_len
);
h
=
(
struct
ppp_header
*
)
skb_put
(
skb
,
sizeof
(
struct
ppp_header
));
h
->
address
=
PPP_ALLSTATIONS
;
/* broadcast address */
h
->
control
=
PPP_UI
;
/* Unnumbered Info */
h
->
protocol
=
htons
(
proto
);
/* Link Control Protocol */
lh
=
(
struct
lcp_header
*
)
skb_put
(
skb
,
sizeof
(
struct
lcp_header
));
lh
->
type
=
type
;
lh
->
ident
=
ident
;
lh
->
len
=
htons
(
LCP_HEADER_LEN
+
len
);
if
(
len
)
memcpy
(
skb_put
(
skb
,
len
),
data
,
len
);
if
(
sp
->
pp_flags
&
PP_DEBUG
)
{
printk
(
KERN_WARNING
"%s: %s output <%s id=%xh len=%xh"
,
dev
->
name
,
proto
==
PPP_LCP
?
"lcp"
:
"ipcp"
,
proto
==
PPP_LCP
?
sppp_lcp_type_name
(
lh
->
type
)
:
sppp_ipcp_type_name
(
lh
->
type
),
lh
->
ident
,
ntohs
(
lh
->
len
));
if
(
len
)
sppp_print_bytes
((
u8
*
)
(
lh
+
1
),
len
);
printk
(
">
\n
"
);
}
/* Control is high priority so it doesn't get queued behind data */
skb
->
priority
=
TC_PRIO_CONTROL
;
skb
->
dev
=
dev
;
skb_queue_tail
(
&
tx_queue
,
skb
);
}
/*
* Send Cisco keepalive packet.
*/
static
void
sppp_cisco_send
(
struct
sppp
*
sp
,
int
type
,
u32
par1
,
u32
par2
)
{
struct
ppp_header
*
h
;
struct
cisco_packet
*
ch
;
struct
sk_buff
*
skb
;
struct
net_device
*
dev
=
sp
->
pp_if
;
u32
t
=
jiffies
*
1000
/
HZ
;
skb
=
alloc_skb
(
dev
->
hard_header_len
+
PPP_HEADER_LEN
+
CISCO_PACKET_LEN
,
GFP_ATOMIC
);
if
(
skb
==
NULL
)
return
;
skb_reserve
(
skb
,
dev
->
hard_header_len
);
h
=
(
struct
ppp_header
*
)
skb_put
(
skb
,
sizeof
(
struct
ppp_header
));
h
->
address
=
CISCO_MULTICAST
;
h
->
control
=
0
;
h
->
protocol
=
htons
(
CISCO_KEEPALIVE
);
ch
=
(
struct
cisco_packet
*
)
skb_put
(
skb
,
CISCO_PACKET_LEN
);
ch
->
type
=
htonl
(
type
);
ch
->
par1
=
htonl
(
par1
);
ch
->
par2
=
htonl
(
par2
);
ch
->
rel
=
htons
(
0xffff
);
ch
->
time0
=
htons
((
u16
)
(
t
>>
16
));
ch
->
time1
=
htons
((
u16
)
t
);
if
(
sp
->
pp_flags
&
PP_DEBUG
)
printk
(
KERN_WARNING
"%s: cisco output: <%xh %xh %xh %xh %xh-%xh>
\n
"
,
dev
->
name
,
ntohl
(
ch
->
type
),
ch
->
par1
,
ch
->
par2
,
ch
->
rel
,
ch
->
time0
,
ch
->
time1
);
skb
->
priority
=
TC_PRIO_CONTROL
;
skb
->
dev
=
dev
;
skb_queue_tail
(
&
tx_queue
,
skb
);
}
/**
* sppp_close - close down a synchronous PPP or Cisco HDLC link
* @dev: The network device to drop the link of
*
* This drops the logical interface to the channel. It is not
* done politely as we assume we will also be dropping DTR. Any
* timeouts are killed.
*/
int
sppp_close
(
struct
net_device
*
dev
)
{
struct
sppp
*
sp
=
(
struct
sppp
*
)
sppp_of
(
dev
);
unsigned
long
flags
;
spin_lock_irqsave
(
&
sp
->
lock
,
flags
);
sp
->
pp_link_state
=
SPPP_LINK_DOWN
;
sp
->
lcp
.
state
=
LCP_STATE_CLOSED
;
sp
->
ipcp
.
state
=
IPCP_STATE_CLOSED
;
sppp_clear_timeout
(
sp
);
spin_unlock_irqrestore
(
&
sp
->
lock
,
flags
);
return
0
;
}
EXPORT_SYMBOL
(
sppp_close
);
/**
* sppp_open - open a synchronous PPP or Cisco HDLC link
* @dev: Network device to activate
*
* Close down any existing synchronous session and commence
* from scratch. In the PPP case this means negotiating LCP/IPCP
* and friends, while for Cisco HDLC we simply need to start sending
* keepalives
*/
int
sppp_open
(
struct
net_device
*
dev
)
{
struct
sppp
*
sp
=
(
struct
sppp
*
)
sppp_of
(
dev
);
unsigned
long
flags
;
sppp_close
(
dev
);
spin_lock_irqsave
(
&
sp
->
lock
,
flags
);
if
(
!
(
sp
->
pp_flags
&
PP_CISCO
))
{
sppp_lcp_open
(
sp
);
}
sp
->
pp_link_state
=
SPPP_LINK_DOWN
;
spin_unlock_irqrestore
(
&
sp
->
lock
,
flags
);
sppp_flush_xmit
();
return
0
;
}
EXPORT_SYMBOL
(
sppp_open
);
/**
* sppp_reopen - notify of physical link loss
* @dev: Device that lost the link
*
* This function informs the synchronous protocol code that
* the underlying link died (for example a carrier drop on X.21)
*
* We increment the magic numbers to ensure that if the other end
* failed to notice we will correctly start a new session. It happens
* do to the nature of telco circuits is that you can lose carrier on
* one endonly.
*
* Having done this we go back to negotiating. This function may
* be called from an interrupt context.
*/
int
sppp_reopen
(
struct
net_device
*
dev
)
{
struct
sppp
*
sp
=
(
struct
sppp
*
)
sppp_of
(
dev
);
unsigned
long
flags
;
sppp_close
(
dev
);
spin_lock_irqsave
(
&
sp
->
lock
,
flags
);
if
(
!
(
sp
->
pp_flags
&
PP_CISCO
))
{
sp
->
lcp
.
magic
=
jiffies
;
++
sp
->
pp_seq
;
sp
->
lcp
.
state
=
LCP_STATE_CLOSED
;
sp
->
ipcp
.
state
=
IPCP_STATE_CLOSED
;
/* Give it a moment for the line to settle then go */
sppp_set_timeout
(
sp
,
1
);
}
sp
->
pp_link_state
=
SPPP_LINK_DOWN
;
spin_unlock_irqrestore
(
&
sp
->
lock
,
flags
);
return
0
;
}
EXPORT_SYMBOL
(
sppp_reopen
);
/**
* sppp_change_mtu - Change the link MTU
* @dev: Device to change MTU on
* @new_mtu: New MTU
*
* Change the MTU on the link. This can only be called with
* the link down. It returns an error if the link is up or
* the mtu is out of range.
*/
static
int
sppp_change_mtu
(
struct
net_device
*
dev
,
int
new_mtu
)
{
if
(
new_mtu
<
128
||
new_mtu
>
PPP_MTU
||
(
dev
->
flags
&
IFF_UP
))
return
-
EINVAL
;
dev
->
mtu
=
new_mtu
;
return
0
;
}
/**
* sppp_do_ioctl - Ioctl handler for ppp/hdlc
* @dev: Device subject to ioctl
* @ifr: Interface request block from the user
* @cmd: Command that is being issued
*
* This function handles the ioctls that may be issued by the user
* to control the settings of a PPP/HDLC link. It does both busy
* and security checks. This function is intended to be wrapped by
* callers who wish to add additional ioctl calls of their own.
*/
int
sppp_do_ioctl
(
struct
net_device
*
dev
,
struct
ifreq
*
ifr
,
int
cmd
)
{
struct
sppp
*
sp
=
(
struct
sppp
*
)
sppp_of
(
dev
);
if
(
dev
->
flags
&
IFF_UP
)
return
-
EBUSY
;
if
(
!
capable
(
CAP_NET_ADMIN
))
return
-
EPERM
;
switch
(
cmd
)
{
case
SPPPIOCCISCO
:
sp
->
pp_flags
|=
PP_CISCO
;
dev
->
type
=
ARPHRD_HDLC
;
break
;
case
SPPPIOCPPP
:
sp
->
pp_flags
&=~
PP_CISCO
;
dev
->
type
=
ARPHRD_PPP
;
break
;
case
SPPPIOCDEBUG
:
sp
->
pp_flags
&=~
PP_DEBUG
;
if
(
ifr
->
ifr_flags
)
sp
->
pp_flags
|=
PP_DEBUG
;
break
;
case
SPPPIOCGFLAGS
:
if
(
copy_to_user
(
ifr
->
ifr_data
,
&
sp
->
pp_flags
,
sizeof
(
sp
->
pp_flags
)))
return
-
EFAULT
;
break
;
case
SPPPIOCSFLAGS
:
if
(
copy_from_user
(
&
sp
->
pp_flags
,
ifr
->
ifr_data
,
sizeof
(
sp
->
pp_flags
)))
return
-
EFAULT
;
break
;
default:
return
-
EINVAL
;
}
return
0
;
}
EXPORT_SYMBOL
(
sppp_do_ioctl
);
/**
* sppp_attach - attach synchronous PPP/HDLC to a device
* @pd: PPP device to initialise
*
* This initialises the PPP/HDLC support on an interface. At the
* time of calling the dev element must point to the network device
* that this interface is attached to. The interface should not yet
* be registered.
*/
void
sppp_attach
(
struct
ppp_device
*
pd
)
{
struct
net_device
*
dev
=
pd
->
dev
;
struct
sppp
*
sp
=
&
pd
->
sppp
;
unsigned
long
flags
;
/* Make sure embedding is safe for sppp_of */
BUG_ON
(
sppp_of
(
dev
)
!=
sp
);
spin_lock_irqsave
(
&
spppq_lock
,
flags
);
/* Initialize keepalive handler. */
if
(
!
spppq
)
{
init_timer
(
&
sppp_keepalive_timer
);
sppp_keepalive_timer
.
expires
=
jiffies
+
10
*
HZ
;
sppp_keepalive_timer
.
function
=
sppp_keepalive
;
add_timer
(
&
sppp_keepalive_timer
);
}
/* Insert new entry into the keepalive list. */
sp
->
pp_next
=
spppq
;
spppq
=
sp
;
spin_unlock_irqrestore
(
&
spppq_lock
,
flags
);
sp
->
pp_loopcnt
=
0
;
sp
->
pp_alivecnt
=
0
;
sp
->
pp_seq
=
0
;
sp
->
pp_rseq
=
0
;
sp
->
pp_flags
=
PP_KEEPALIVE
|
PP_CISCO
|
debug
;
/*PP_DEBUG;*/
sp
->
lcp
.
magic
=
0
;
sp
->
lcp
.
state
=
LCP_STATE_CLOSED
;
sp
->
ipcp
.
state
=
IPCP_STATE_CLOSED
;
sp
->
pp_if
=
dev
;
spin_lock_init
(
&
sp
->
lock
);
/*
* Device specific setup. All but interrupt handler and
* hard_start_xmit.
*/
dev
->
header_ops
=
&
sppp_header_ops
;
dev
->
tx_queue_len
=
10
;
dev
->
type
=
ARPHRD_HDLC
;
dev
->
addr_len
=
0
;
dev
->
hard_header_len
=
sizeof
(
struct
ppp_header
);
dev
->
mtu
=
PPP_MTU
;
/*
* These 4 are callers but MUST also call sppp_ functions
*/
dev
->
do_ioctl
=
sppp_do_ioctl
;
#if 0
dev->get_stats = NULL; /* Let the driver override these */
dev->open = sppp_open;
dev->stop = sppp_close;
#endif
dev
->
change_mtu
=
sppp_change_mtu
;
dev
->
flags
=
IFF_MULTICAST
|
IFF_POINTOPOINT
|
IFF_NOARP
;
}
EXPORT_SYMBOL
(
sppp_attach
);
/**
* sppp_detach - release PPP resources from a device
* @dev: Network device to release
*
* Stop and free up any PPP/HDLC resources used by this
* interface. This must be called before the device is
* freed.
*/
void
sppp_detach
(
struct
net_device
*
dev
)
{
struct
sppp
**
q
,
*
p
,
*
sp
=
(
struct
sppp
*
)
sppp_of
(
dev
);
unsigned
long
flags
;
spin_lock_irqsave
(
&
spppq_lock
,
flags
);
/* Remove the entry from the keepalive list. */
for
(
q
=
&
spppq
;
(
p
=
*
q
);
q
=
&
p
->
pp_next
)
if
(
p
==
sp
)
{
*
q
=
p
->
pp_next
;
break
;
}
/* Stop keepalive handler. */
if
(
!
spppq
)
del_timer
(
&
sppp_keepalive_timer
);
sppp_clear_timeout
(
sp
);
spin_unlock_irqrestore
(
&
spppq_lock
,
flags
);
}
EXPORT_SYMBOL
(
sppp_detach
);
/*
* Analyze the LCP Configure-Request options list
* for the presence of unknown options.
* If the request contains unknown options, build and
* send Configure-reject packet, containing only unknown options.
*/
static
int
sppp_lcp_conf_parse_options
(
struct
sppp
*
sp
,
struct
lcp_header
*
h
,
int
len
,
u32
*
magic
)
{
u8
*
buf
,
*
r
,
*
p
;
int
rlen
;
len
-=
4
;
buf
=
r
=
kmalloc
(
len
,
GFP_ATOMIC
);
if
(
!
buf
)
return
(
0
);
p
=
(
void
*
)
(
h
+
1
);
for
(
rlen
=
0
;
len
>
1
&&
p
[
1
];
len
-=
p
[
1
],
p
+=
p
[
1
])
{
switch
(
*
p
)
{
case
LCP_OPT_MAGIC
:
/* Magic number -- extract. */
if
(
len
>=
6
&&
p
[
1
]
==
6
)
{
*
magic
=
(
u32
)
p
[
2
]
<<
24
|
(
u32
)
p
[
3
]
<<
16
|
p
[
4
]
<<
8
|
p
[
5
];
continue
;
}
break
;
case
LCP_OPT_ASYNC_MAP
:
/* Async control character map -- check to be zero. */
if
(
len
>=
6
&&
p
[
1
]
==
6
&&
!
p
[
2
]
&&
!
p
[
3
]
&&
!
p
[
4
]
&&
!
p
[
5
])
continue
;
break
;
case
LCP_OPT_MRU
:
/* Maximum receive unit -- always OK. */
continue
;
default:
/* Others not supported. */
break
;
}
/* Add the option to rejected list. */
memcpy
(
r
,
p
,
p
[
1
]);
r
+=
p
[
1
];
rlen
+=
p
[
1
];
}
if
(
rlen
)
sppp_cp_send
(
sp
,
PPP_LCP
,
LCP_CONF_REJ
,
h
->
ident
,
rlen
,
buf
);
kfree
(
buf
);
return
(
rlen
==
0
);
}
static
void
sppp_ipcp_input
(
struct
sppp
*
sp
,
struct
sk_buff
*
skb
)
{
struct
lcp_header
*
h
;
struct
net_device
*
dev
=
sp
->
pp_if
;
int
len
=
skb
->
len
;
if
(
!
pskb_may_pull
(
skb
,
sizeof
(
struct
lcp_header
)))
{
if
(
sp
->
pp_flags
&
PP_DEBUG
)
printk
(
KERN_WARNING
"%s: invalid ipcp packet length: %d bytes
\n
"
,
dev
->
name
,
len
);
return
;
}
h
=
(
struct
lcp_header
*
)
skb
->
data
;
skb_pull
(
skb
,
sizeof
(
struct
lcp_header
));
if
(
sp
->
pp_flags
&
PP_DEBUG
)
{
printk
(
KERN_WARNING
"%s: ipcp input: %d bytes <%s id=%xh len=%xh"
,
dev
->
name
,
len
,
sppp_ipcp_type_name
(
h
->
type
),
h
->
ident
,
ntohs
(
h
->
len
));
if
(
len
>
4
)
sppp_print_bytes
((
u8
*
)
(
h
+
1
),
len
-
4
);
printk
(
">
\n
"
);
}
if
(
len
>
ntohs
(
h
->
len
))
len
=
ntohs
(
h
->
len
);
switch
(
h
->
type
)
{
default:
/* Unknown packet type -- send Code-Reject packet. */
sppp_cp_send
(
sp
,
PPP_IPCP
,
IPCP_CODE_REJ
,
++
sp
->
pp_seq
,
len
,
h
);
break
;
case
IPCP_CONF_REQ
:
if
(
len
<
4
)
{
if
(
sp
->
pp_flags
&
PP_DEBUG
)
printk
(
KERN_WARNING
"%s: invalid ipcp configure request packet length: %d bytes
\n
"
,
dev
->
name
,
len
);
return
;
}
if
(
len
>
4
)
{
sppp_cp_send
(
sp
,
PPP_IPCP
,
LCP_CONF_REJ
,
h
->
ident
,
len
-
4
,
h
+
1
);
switch
(
sp
->
ipcp
.
state
)
{
case
IPCP_STATE_OPENED
:
/* Initiate renegotiation. */
sppp_ipcp_open
(
sp
);
/* fall through... */
case
IPCP_STATE_ACK_SENT
:
/* Go to closed state. */
sp
->
ipcp
.
state
=
IPCP_STATE_CLOSED
;
}
}
else
{
/* Send Configure-Ack packet. */
sppp_cp_send
(
sp
,
PPP_IPCP
,
IPCP_CONF_ACK
,
h
->
ident
,
0
,
NULL
);
/* Change the state. */
if
(
sp
->
ipcp
.
state
==
IPCP_STATE_ACK_RCVD
)
sp
->
ipcp
.
state
=
IPCP_STATE_OPENED
;
else
sp
->
ipcp
.
state
=
IPCP_STATE_ACK_SENT
;
}
break
;
case
IPCP_CONF_ACK
:
if
(
h
->
ident
!=
sp
->
ipcp
.
confid
)
break
;
sppp_clear_timeout
(
sp
);
switch
(
sp
->
ipcp
.
state
)
{
case
IPCP_STATE_CLOSED
:
sp
->
ipcp
.
state
=
IPCP_STATE_ACK_RCVD
;
sppp_set_timeout
(
sp
,
5
);
break
;
case
IPCP_STATE_ACK_SENT
:
sp
->
ipcp
.
state
=
IPCP_STATE_OPENED
;
break
;
}
break
;
case
IPCP_CONF_NAK
:
case
IPCP_CONF_REJ
:
if
(
h
->
ident
!=
sp
->
ipcp
.
confid
)
break
;
sppp_clear_timeout
(
sp
);
/* Initiate renegotiation. */
sppp_ipcp_open
(
sp
);
if
(
sp
->
ipcp
.
state
!=
IPCP_STATE_ACK_SENT
)
/* Go to closed state. */
sp
->
ipcp
.
state
=
IPCP_STATE_CLOSED
;
break
;
case
IPCP_TERM_REQ
:
/* Send Terminate-Ack packet. */
sppp_cp_send
(
sp
,
PPP_IPCP
,
IPCP_TERM_ACK
,
h
->
ident
,
0
,
NULL
);
/* Go to closed state. */
sp
->
ipcp
.
state
=
IPCP_STATE_CLOSED
;
/* Initiate renegotiation. */
sppp_ipcp_open
(
sp
);
break
;
case
IPCP_TERM_ACK
:
/* Ignore for now. */
case
IPCP_CODE_REJ
:
/* Ignore for now. */
break
;
}
}
static
void
sppp_lcp_open
(
struct
sppp
*
sp
)
{
char
opt
[
6
];
if
(
!
sp
->
lcp
.
magic
)
sp
->
lcp
.
magic
=
jiffies
;
opt
[
0
]
=
LCP_OPT_MAGIC
;
opt
[
1
]
=
sizeof
(
opt
);
opt
[
2
]
=
sp
->
lcp
.
magic
>>
24
;
opt
[
3
]
=
sp
->
lcp
.
magic
>>
16
;
opt
[
4
]
=
sp
->
lcp
.
magic
>>
8
;
opt
[
5
]
=
sp
->
lcp
.
magic
;
sp
->
lcp
.
confid
=
++
sp
->
pp_seq
;
sppp_cp_send
(
sp
,
PPP_LCP
,
LCP_CONF_REQ
,
sp
->
lcp
.
confid
,
sizeof
(
opt
),
&
opt
);
sppp_set_timeout
(
sp
,
2
);
}
static
void
sppp_ipcp_open
(
struct
sppp
*
sp
)
{
sp
->
ipcp
.
confid
=
++
sp
->
pp_seq
;
sppp_cp_send
(
sp
,
PPP_IPCP
,
IPCP_CONF_REQ
,
sp
->
ipcp
.
confid
,
0
,
NULL
);
sppp_set_timeout
(
sp
,
2
);
}
/*
* Process PPP control protocol timeouts.
*/
static
void
sppp_cp_timeout
(
unsigned
long
arg
)
{
struct
sppp
*
sp
=
(
struct
sppp
*
)
arg
;
unsigned
long
flags
;
spin_lock_irqsave
(
&
sp
->
lock
,
flags
);
sp
->
pp_flags
&=
~
PP_TIMO
;
if
(
!
(
sp
->
pp_if
->
flags
&
IFF_UP
)
||
(
sp
->
pp_flags
&
PP_CISCO
))
{
spin_unlock_irqrestore
(
&
sp
->
lock
,
flags
);
return
;
}
switch
(
sp
->
lcp
.
state
)
{
case
LCP_STATE_CLOSED
:
/* No ACK for Configure-Request, retry. */
sppp_lcp_open
(
sp
);
break
;
case
LCP_STATE_ACK_RCVD
:
/* ACK got, but no Configure-Request for peer, retry. */
sppp_lcp_open
(
sp
);
sp
->
lcp
.
state
=
LCP_STATE_CLOSED
;
break
;
case
LCP_STATE_ACK_SENT
:
/* ACK sent but no ACK for Configure-Request, retry. */
sppp_lcp_open
(
sp
);
break
;
case
LCP_STATE_OPENED
:
/* LCP is already OK, try IPCP. */
switch
(
sp
->
ipcp
.
state
)
{
case
IPCP_STATE_CLOSED
:
/* No ACK for Configure-Request, retry. */
sppp_ipcp_open
(
sp
);
break
;
case
IPCP_STATE_ACK_RCVD
:
/* ACK got, but no Configure-Request for peer, retry. */
sppp_ipcp_open
(
sp
);
sp
->
ipcp
.
state
=
IPCP_STATE_CLOSED
;
break
;
case
IPCP_STATE_ACK_SENT
:
/* ACK sent but no ACK for Configure-Request, retry. */
sppp_ipcp_open
(
sp
);
break
;
case
IPCP_STATE_OPENED
:
/* IPCP is OK. */
break
;
}
break
;
}
spin_unlock_irqrestore
(
&
sp
->
lock
,
flags
);
sppp_flush_xmit
();
}
static
char
*
sppp_lcp_type_name
(
u8
type
)
{
static
char
buf
[
8
];
switch
(
type
)
{
case
LCP_CONF_REQ
:
return
(
"conf-req"
);
case
LCP_CONF_ACK
:
return
(
"conf-ack"
);
case
LCP_CONF_NAK
:
return
(
"conf-nack"
);
case
LCP_CONF_REJ
:
return
(
"conf-rej"
);
case
LCP_TERM_REQ
:
return
(
"term-req"
);
case
LCP_TERM_ACK
:
return
(
"term-ack"
);
case
LCP_CODE_REJ
:
return
(
"code-rej"
);
case
LCP_PROTO_REJ
:
return
(
"proto-rej"
);
case
LCP_ECHO_REQ
:
return
(
"echo-req"
);
case
LCP_ECHO_REPLY
:
return
(
"echo-reply"
);
case
LCP_DISC_REQ
:
return
(
"discard-req"
);
}
sprintf
(
buf
,
"%xh"
,
type
);
return
(
buf
);
}
static
char
*
sppp_ipcp_type_name
(
u8
type
)
{
static
char
buf
[
8
];
switch
(
type
)
{
case
IPCP_CONF_REQ
:
return
(
"conf-req"
);
case
IPCP_CONF_ACK
:
return
(
"conf-ack"
);
case
IPCP_CONF_NAK
:
return
(
"conf-nack"
);
case
IPCP_CONF_REJ
:
return
(
"conf-rej"
);
case
IPCP_TERM_REQ
:
return
(
"term-req"
);
case
IPCP_TERM_ACK
:
return
(
"term-ack"
);
case
IPCP_CODE_REJ
:
return
(
"code-rej"
);
}
sprintf
(
buf
,
"%xh"
,
type
);
return
(
buf
);
}
static
void
sppp_print_bytes
(
u_char
*
p
,
u16
len
)
{
printk
(
" %x"
,
*
p
++
);
while
(
--
len
>
0
)
printk
(
"-%x"
,
*
p
++
);
}
/**
* sppp_rcv - receive and process a WAN PPP frame
* @skb: The buffer to process
* @dev: The device it arrived on
* @p: Unused
* @orig_dev: Unused
*
* Protocol glue. This drives the deferred processing mode the poorer
* cards use. This can be called directly by cards that do not have
* timing constraints but is normally called from the network layer
* after interrupt servicing to process frames queued via netif_rx.
*/
static
int
sppp_rcv
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
,
struct
packet_type
*
p
,
struct
net_device
*
orig_dev
)
{
if
(
dev_net
(
dev
)
!=
&
init_net
)
{
kfree_skb
(
skb
);
return
0
;
}
if
((
skb
=
skb_share_check
(
skb
,
GFP_ATOMIC
))
==
NULL
)
return
NET_RX_DROP
;
sppp_input
(
dev
,
skb
);
return
0
;
}
static
struct
packet_type
sppp_packet_type
=
{
.
type
=
__constant_htons
(
ETH_P_WAN_PPP
),
.
func
=
sppp_rcv
,
};
static
char
banner
[]
__initdata
=
KERN_INFO
"Cronyx Ltd, Synchronous PPP and CISCO HDLC (c) 1994
\n
"
KERN_INFO
"Linux port (c) 1998 Building Number Three Ltd & "
"Jan
\"
Yenya
\"
Kasprzak.
\n
"
;
static
int
__init
sync_ppp_init
(
void
)
{
if
(
debug
)
debug
=
PP_DEBUG
;
printk
(
banner
);
skb_queue_head_init
(
&
tx_queue
);
dev_add_pack
(
&
sppp_packet_type
);
return
0
;
}
static
void
__exit
sync_ppp_cleanup
(
void
)
{
dev_remove_pack
(
&
sppp_packet_type
);
}
module_init
(
sync_ppp_init
);
module_exit
(
sync_ppp_cleanup
);
module_param
(
debug
,
int
,
0
);
MODULE_LICENSE
(
"GPL"
);
include/net/syncppp.h
deleted
100644 → 0
View file @
f5f4cf08
/*
* Defines for synchronous PPP/Cisco link level subroutines.
*
* Copyright (C) 1994 Cronyx Ltd.
* Author: Serge Vakulenko, <vak@zebub.msk.su>
*
* This software is distributed with NO WARRANTIES, not even the implied
* warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* Authors grant any other persons or organizations permission to use
* or modify this software as long as this message is kept with the software,
* all derivative works or modified versions.
*
* Version 1.7, Wed Jun 7 22:12:02 MSD 1995
*
*
*
*/
#ifndef _SYNCPPP_H_
#define _SYNCPPP_H_ 1
#ifdef __KERNEL__
struct
slcp
{
u16
state
;
/* state machine */
u32
magic
;
/* local magic number */
u_char
echoid
;
/* id of last keepalive echo request */
u_char
confid
;
/* id of last configuration request */
};
struct
sipcp
{
u16
state
;
/* state machine */
u_char
confid
;
/* id of last configuration request */
};
struct
sppp
{
struct
sppp
*
pp_next
;
/* next interface in keepalive list */
u32
pp_flags
;
/* use Cisco protocol instead of PPP */
u16
pp_alivecnt
;
/* keepalive packets counter */
u16
pp_loopcnt
;
/* loopback detection counter */
u32
pp_seq
;
/* local sequence number */
u32
pp_rseq
;
/* remote sequence number */
struct
slcp
lcp
;
/* LCP params */
struct
sipcp
ipcp
;
/* IPCP params */
struct
timer_list
pp_timer
;
struct
net_device
*
pp_if
;
char
pp_link_state
;
/* Link status */
spinlock_t
lock
;
};
struct
ppp_device
{
struct
net_device
*
dev
;
/* Network device pointer */
struct
sppp
sppp
;
/* Synchronous PPP */
};
static
inline
struct
sppp
*
sppp_of
(
struct
net_device
*
dev
)
{
struct
ppp_device
**
ppp
=
dev
->
ml_priv
;
BUG_ON
((
*
ppp
)
->
dev
!=
dev
);
return
&
(
*
ppp
)
->
sppp
;
}
#define PP_KEEPALIVE 0x01
/* use keepalive protocol */
#define PP_CISCO 0x02
/* use Cisco protocol instead of PPP */
#define PP_TIMO 0x04
/* cp_timeout routine active */
#define PP_DEBUG 0x08
#define PPP_MTU 1500
/* max. transmit unit */
#define LCP_STATE_CLOSED 0
/* LCP state: closed (conf-req sent) */
#define LCP_STATE_ACK_RCVD 1
/* LCP state: conf-ack received */
#define LCP_STATE_ACK_SENT 2
/* LCP state: conf-ack sent */
#define LCP_STATE_OPENED 3
/* LCP state: opened */
#define IPCP_STATE_CLOSED 0
/* IPCP state: closed (conf-req sent) */
#define IPCP_STATE_ACK_RCVD 1
/* IPCP state: conf-ack received */
#define IPCP_STATE_ACK_SENT 2
/* IPCP state: conf-ack sent */
#define IPCP_STATE_OPENED 3
/* IPCP state: opened */
#define SPPP_LINK_DOWN 0
/* link down - no keepalive */
#define SPPP_LINK_UP 1
/* link is up - keepalive ok */
void
sppp_attach
(
struct
ppp_device
*
pd
);
void
sppp_detach
(
struct
net_device
*
dev
);
int
sppp_do_ioctl
(
struct
net_device
*
dev
,
struct
ifreq
*
ifr
,
int
cmd
);
struct
sk_buff
*
sppp_dequeue
(
struct
net_device
*
dev
);
int
sppp_isempty
(
struct
net_device
*
dev
);
void
sppp_flush
(
struct
net_device
*
dev
);
int
sppp_open
(
struct
net_device
*
dev
);
int
sppp_reopen
(
struct
net_device
*
dev
);
int
sppp_close
(
struct
net_device
*
dev
);
#endif
#define SPPPIOCCISCO (SIOCDEVPRIVATE)
#define SPPPIOCPPP (SIOCDEVPRIVATE+1)
#define SPPPIOCDEBUG (SIOCDEVPRIVATE+2)
#define SPPPIOCSFLAGS (SIOCDEVPRIVATE+3)
#define SPPPIOCGFLAGS (SIOCDEVPRIVATE+4)
#endif
/* _SYNCPPP_H_ */
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment