Commit dffdfbce authored by Kai Germaschewski's avatar Kai Germaschewski

Merge zephyr:src/kernel/v2.5/linux-2.5.isdn

into tp1.ruhr-uni-bochum.de:/home/kai/kernel/v2.5/linux-2.5.isdn
parents cbe45702 c25b65fe
...@@ -12,7 +12,8 @@ obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o ...@@ -12,7 +12,8 @@ obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o
# Multipart objects. # Multipart objects.
isdn-objs := isdn_net.o isdn_tty.o \ isdn-objs := isdn_net.o isdn_tty.o \
isdn_v110.o isdn_common.o isdn_v110.o isdn_common.o \
isdn_ciscohdlck.o
# Optional parts of multipart objects. # Optional parts of multipart objects.
......
/*
* Linux ISDN subsystem, CISCO HDLC network interfaces
*
* Copyright 1994-1998 by Fritz Elfert (fritz@isdn4linux.de)
* 1995,96 by Thinking Objects Software GmbH Wuerzburg
* 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
* 1999-2002 by Kai Germaschewski <kai@germaschewski.name>
* 2001 by Bjoern A. Zeeb <i4l@zabbadoz.net>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
* For info on the protocol, see http://i4l.zabbadoz.net/i4l/cisco-hdlc.txt
*/
#include "isdn_common.h"
#include "isdn_net.h"
#include "isdn_ciscohdlck.h"
#include <linux/inetdevice.h>
/*
* CISCO HDLC keepalive specific stuff
*/
static struct sk_buff*
isdn_net_ciscohdlck_alloc_skb(isdn_net_local *lp, int len)
{
unsigned short hl = isdn_slot_hdrlen(lp->isdn_slot);
struct sk_buff *skb;
skb = alloc_skb(hl + len, GFP_ATOMIC);
if (!skb) {
printk("isdn out of mem at %s:%d!\n", __FILE__, __LINE__);
return 0;
}
skb_reserve(skb, hl);
return skb;
}
/* cisco hdlck device private ioctls */
static int
isdn_ciscohdlck_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
isdn_net_local *lp = (isdn_net_local *) dev->priv;
unsigned long len = 0;
unsigned long expires = 0;
int tmp = 0;
int period = lp->cisco_keepalive_period;
char debserint = lp->cisco_debserint;
int rc = 0;
if (lp->p_encap != ISDN_NET_ENCAP_CISCOHDLCK)
return -EINVAL;
switch (cmd) {
/* get/set keepalive period */
case SIOCGKEEPPERIOD:
len = (unsigned long)sizeof(lp->cisco_keepalive_period);
if (copy_to_user((char *)ifr->ifr_ifru.ifru_data,
(int *)&lp->cisco_keepalive_period, len))
rc = -EFAULT;
break;
case SIOCSKEEPPERIOD:
tmp = lp->cisco_keepalive_period;
len = (unsigned long)sizeof(lp->cisco_keepalive_period);
if (copy_from_user((int *)&period,
(char *)ifr->ifr_ifru.ifru_data, len))
rc = -EFAULT;
if ((period > 0) && (period <= 32767))
lp->cisco_keepalive_period = period;
else
rc = -EINVAL;
if (!rc && (tmp != lp->cisco_keepalive_period)) {
expires = (unsigned long)(jiffies +
lp->cisco_keepalive_period * HZ);
mod_timer(&lp->cisco_timer, expires);
printk(KERN_INFO "%s: Keepalive period set "
"to %d seconds.\n",
lp->name, lp->cisco_keepalive_period);
}
break;
/* get/set debugging */
case SIOCGDEBSERINT:
len = (unsigned long)sizeof(lp->cisco_debserint);
if (copy_to_user((char *)ifr->ifr_ifru.ifru_data,
(char *)&lp->cisco_debserint, len))
rc = -EFAULT;
break;
case SIOCSDEBSERINT:
len = (unsigned long)sizeof(lp->cisco_debserint);
if (copy_from_user((char *)&debserint,
(char *)ifr->ifr_ifru.ifru_data, len))
rc = -EFAULT;
if ((debserint >= 0) && (debserint <= 64))
lp->cisco_debserint = debserint;
else
rc = -EINVAL;
break;
default:
rc = -EINVAL;
break;
}
return (rc);
}
/* called via cisco_timer.function */
static void
isdn_net_ciscohdlck_slarp_send_keepalive(unsigned long data)
{
isdn_net_local *lp = (isdn_net_local *) data;
struct sk_buff *skb;
unsigned char *p;
unsigned long last_cisco_myseq = lp->cisco_myseq;
int myseq_diff = 0;
lp->cisco_myseq++;
myseq_diff = (lp->cisco_myseq - lp->cisco_mineseen);
if ((lp->cisco_line_state) && ((myseq_diff >= 3)||(myseq_diff <= -3))) {
/* line up -> down */
lp->cisco_line_state = 0;
printk (KERN_WARNING
"UPDOWN: Line protocol on Interface %s,"
" changed state to down\n", lp->name);
/* should stop routing higher-level data accross */
} else if ((!lp->cisco_line_state) &&
(myseq_diff >= 0) && (myseq_diff <= 2)) {
/* line down -> up */
lp->cisco_line_state = 1;
printk (KERN_WARNING
"UPDOWN: Line protocol on Interface %s,"
" changed state to up\n", lp->name);
/* restart routing higher-level data accross */
}
if (lp->cisco_debserint)
printk (KERN_DEBUG "%s: HDLC "
"myseq %lu, mineseen %lu%c, yourseen %lu, %s\n",
lp->name, last_cisco_myseq, lp->cisco_mineseen,
((last_cisco_myseq == lp->cisco_mineseen) ? '*' : 040),
lp->cisco_yourseq,
((lp->cisco_line_state) ? "line up" : "line down"));
skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14);
if (!skb)
return;
p = skb_put(skb, 4 + 14);
/* cisco header */
p += put_u8 (p, CISCO_ADDR_UNICAST);
p += put_u8 (p, CISCO_CTRL);
p += put_u16(p, CISCO_TYPE_SLARP);
/* slarp keepalive */
p += put_u32(p, CISCO_SLARP_KEEPALIVE);
p += put_u32(p, lp->cisco_myseq);
p += put_u32(p, lp->cisco_yourseq);
p += put_u16(p, 0xffff); // reliablity, always 0xffff
isdn_net_write_super(lp, skb);
lp->cisco_timer.expires = jiffies + lp->cisco_keepalive_period * HZ;
add_timer(&lp->cisco_timer);
}
static void
isdn_net_ciscohdlck_slarp_send_request(isdn_net_local *lp)
{
struct sk_buff *skb;
unsigned char *p;
skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14);
if (!skb)
return;
p = skb_put(skb, 4 + 14);
/* cisco header */
p += put_u8 (p, CISCO_ADDR_UNICAST);
p += put_u8 (p, CISCO_CTRL);
p += put_u16(p, CISCO_TYPE_SLARP);
/* slarp request */
p += put_u32(p, CISCO_SLARP_REQUEST);
p += put_u32(p, 0); // address
p += put_u32(p, 0); // netmask
p += put_u16(p, 0); // unused
isdn_net_write_super(lp, skb);
}
static void
isdn_ciscohdlck_connected(isdn_net_local *lp)
{
lp->cisco_myseq = 0;
lp->cisco_mineseen = 0;
lp->cisco_yourseq = 0;
lp->cisco_keepalive_period = ISDN_TIMER_KEEPINT;
lp->cisco_last_slarp_in = 0;
lp->cisco_line_state = 0;
lp->cisco_debserint = 0;
if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK) {
/* send slarp request because interface/seq.no.s reset */
isdn_net_ciscohdlck_slarp_send_request(lp);
init_timer(&lp->cisco_timer);
lp->cisco_timer.data = (unsigned long) lp;
lp->cisco_timer.function = isdn_net_ciscohdlck_slarp_send_keepalive;
lp->cisco_timer.expires = jiffies + lp->cisco_keepalive_period * HZ;
add_timer(&lp->cisco_timer);
}
isdn_net_device_wake_queue(lp);
}
static void
isdn_ciscohdlck_disconnected(isdn_net_local *lp)
{
if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK) {
del_timer(&lp->cisco_timer);
}
}
static void
isdn_net_ciscohdlck_slarp_send_reply(isdn_net_local *lp)
{
struct sk_buff *skb;
unsigned char *p;
struct in_device *in_dev = NULL;
u32 addr = 0; /* local ipv4 address */
u32 mask = 0; /* local netmask */
if ((in_dev = lp->netdev->dev.ip_ptr) != NULL) {
/* take primary(first) address of interface */
struct in_ifaddr *ifa = in_dev->ifa_list;
if (ifa != NULL) {
addr = ifa->ifa_local;
mask = ifa->ifa_mask;
}
}
skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14);
if (!skb)
return;
p = skb_put(skb, 4 + 14);
/* cisco header */
p += put_u8 (p, CISCO_ADDR_UNICAST);
p += put_u8 (p, CISCO_CTRL);
p += put_u16(p, CISCO_TYPE_SLARP);
/* slarp reply, send own ip/netmask; if values are nonsense remote
* should think we are unable to provide it with an address via SLARP */
p += put_u32(p, CISCO_SLARP_REPLY);
p += put_u32(p, addr); // address
p += put_u32(p, mask); // netmask
p += put_u16(p, 0); // unused
isdn_net_write_super(lp, skb);
}
static void
isdn_net_ciscohdlck_slarp_in(isdn_net_local *lp, struct sk_buff *skb)
{
unsigned char *p;
int period;
u32 code;
u32 my_seq, addr;
u32 your_seq, mask;
u32 local;
u16 unused;
if (skb->len < 14)
return;
p = skb->data;
p += get_u32(p, &code);
switch (code) {
case CISCO_SLARP_REQUEST:
lp->cisco_yourseq = 0;
isdn_net_ciscohdlck_slarp_send_reply(lp);
break;
case CISCO_SLARP_REPLY:
addr = ntohl(*(u32 *)p);
mask = ntohl(*(u32 *)(p+4));
if (mask != 0xfffffffc)
goto slarp_reply_out;
if ((addr & 3) == 0 || (addr & 3) == 3)
goto slarp_reply_out;
local = addr ^ 3;
printk(KERN_INFO "%s: got slarp reply: "
"remote ip: %d.%d.%d.%d, "
"local ip: %d.%d.%d.%d "
"mask: %d.%d.%d.%d\n",
lp->name,
HIPQUAD(addr),
HIPQUAD(local),
HIPQUAD(mask));
break;
slarp_reply_out:
printk(KERN_INFO "%s: got invalid slarp "
"reply (%d.%d.%d.%d/%d.%d.%d.%d) "
"- ignored\n", lp->name,
HIPQUAD(addr), HIPQUAD(mask));
break;
case CISCO_SLARP_KEEPALIVE:
period = (int)((jiffies - lp->cisco_last_slarp_in
+ HZ/2 - 1) / HZ);
if (lp->cisco_debserint &&
(period != lp->cisco_keepalive_period) &&
lp->cisco_last_slarp_in) {
printk(KERN_DEBUG "%s: Keepalive period mismatch - "
"is %d but should be %d.\n",
lp->name, period, lp->cisco_keepalive_period);
}
lp->cisco_last_slarp_in = jiffies;
p += get_u32(p, &my_seq);
p += get_u32(p, &your_seq);
p += get_u16(p, &unused);
lp->cisco_yourseq = my_seq;
lp->cisco_mineseen = your_seq;
break;
}
}
static void
isdn_ciscohdlck_receive(isdn_net_dev *idev, isdn_net_local *olp,
struct sk_buff *skb)
{
isdn_net_local *lp = &idev->local;
unsigned char *p;
u8 addr;
u8 ctrl;
u16 type;
if (skb->len < 4)
goto out_free;
p = skb->data;
p += get_u8 (p, &addr);
p += get_u8 (p, &ctrl);
p += get_u16(p, &type);
skb_pull(skb, 4);
if ((addr != CISCO_ADDR_UNICAST && addr != CISCO_ADDR_BROADCAST) ||
ctrl != CISCO_CTRL) {
printk(KERN_DEBUG "%s: Unknown Cisco header %#02x %#02x\n",
lp->name, addr, ctrl);
goto out_free;
}
switch (type) {
case CISCO_TYPE_SLARP:
isdn_net_ciscohdlck_slarp_in(lp, skb);
goto out_free;
case CISCO_TYPE_CDP:
if (lp->cisco_debserint)
printk(KERN_DEBUG "%s: Received CDP packet. use "
"\"no cdp enable\" on cisco.\n", lp->name);
goto out_free;
default:
/* no special cisco protocol */
isdn_net_reset_huptimer(lp, olp);
skb->protocol = htons(type);
netif_rx(skb);
return;
}
out_free:
kfree_skb(skb);
}
static int
isdn_ciscohdlck_header(struct sk_buff *skb, struct net_device *dev,
unsigned short type,
void *daddr, void *saddr, unsigned plen)
{
unsigned char *p = skb_push(skb, 4);
p += put_u8 (p, CISCO_ADDR_UNICAST);
p += put_u8 (p, CISCO_CTRL);
p += put_u16(p, type);
return 4;
}
int
isdn_ciscohdlck_setup(isdn_net_dev *p)
{
p->dev.hard_header = isdn_ciscohdlck_header;
p->dev.hard_header_cache = NULL;
p->dev.header_cache_update = NULL;
p->dev.flags = IFF_NOARP|IFF_POINTOPOINT;
p->dev.do_ioctl = isdn_ciscohdlck_dev_ioctl;
p->local.receive = isdn_ciscohdlck_receive;
p->local.connected = isdn_ciscohdlck_connected;
p->local.disconnected = isdn_ciscohdlck_disconnected;
return 0;
}
/*
* Linux ISDN subsystem, CISCO HDLC network interfaces
*
* Copyright 1999-2002 by Kai Germaschewski <kai@germaschewski.name>
* 2001 by Bjoern A. Zeeb <i4l@zabbadoz.net>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*/
#ifndef ISDN_CISCOHDLCK_H
#define ISDN_CISCOHDLCK_H
int isdn_ciscohdlck_setup(isdn_net_dev *p);
#endif
...@@ -611,11 +611,9 @@ isdn_status_callback(isdn_ctrl * c) ...@@ -611,11 +611,9 @@ isdn_status_callback(isdn_ctrl * c)
dbg_statcallb("BHUP: %d\n", i); dbg_statcallb("BHUP: %d\n", i);
dev->drv[di]->online &= ~(1 << (c->arg)); dev->drv[di]->online &= ~(1 << (c->arg));
isdn_info_update(); isdn_info_update();
#ifdef CONFIG_ISDN_X25
/* Signal hangup to network-devices */ /* Signal hangup to network-devices */
if (isdn_net_stat_callback(i, c)) if (isdn_net_stat_callback(i, c))
break; break;
#endif
isdn_v110_stat_callback(&slot[i].iv110, c); isdn_v110_stat_callback(&slot[i].iv110, c);
if (isdn_tty_stat_callback(i, c)) if (isdn_tty_stat_callback(i, c))
break; break;
......
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
* *
*/ */
#include <linux/isdn.h>
#undef ISDN_DEBUG_MODEM_OPEN #undef ISDN_DEBUG_MODEM_OPEN
#undef ISDN_DEBUG_MODEM_IOCTL #undef ISDN_DEBUG_MODEM_IOCTL
#undef ISDN_DEBUG_MODEM_WAITSENT #undef ISDN_DEBUG_MODEM_WAITSENT
......
...@@ -106,3 +106,145 @@ struct concap_proto * isdn_concap_new( int encap ) ...@@ -106,3 +106,145 @@ struct concap_proto * isdn_concap_new( int encap )
} }
return NULL; return NULL;
} }
void isdn_x25_cleanup(isdn_net_dev *p)
{
isdn_net_local *lp = &p->local;
struct concap_proto * cprot = p -> cprot;
unsigned long flags;
/* delete old encapsulation protocol if present ... */
save_flags(flags);
cli(); /* avoid races with incoming events trying to
call cprot->pops methods */
if( cprot && cprot -> pops )
cprot -> pops -> proto_del ( cprot );
p -> cprot = NULL;
lp -> dops = NULL;
restore_flags(flags);
}
void isdn_x25_open(struct net_device *dev)
{
struct concap_device_ops * dops =
( (isdn_net_local *) dev->priv ) -> dops;
struct concap_proto * cprot =
( (isdn_net_local *) dev->priv ) -> netdev -> cprot;
unsigned long flags;
save_flags(flags);
cli(); /* Avoid glitch on writes to CMD regs */
if( cprot && cprot -> pops && dops )
cprot -> pops -> restart ( cprot, dev, dops );
restore_flags(flags);
}
void isdn_x25_close(struct net_device *dev)
{
struct concap_proto * cprot =
( (isdn_net_local *) dev->priv ) -> netdev -> cprot;
if( cprot && cprot -> pops ) cprot -> pops -> close( cprot );
}
static void isdn_x25_connected(isdn_net_local *lp)
{
struct concap_proto *cprot = lp -> netdev -> cprot;
struct concap_proto_ops *pops = cprot ? cprot -> pops : 0;
/* try if there are generic concap receiver routines */
if( pops )
if( pops->connect_ind)
pops->connect_ind(cprot);
isdn_net_device_wake_queue(lp);
}
static void isdn_x25_disconnected(isdn_net_local *lp)
{
struct concap_proto *cprot = lp -> netdev -> cprot;
struct concap_proto_ops *pops = cprot ? cprot -> pops : 0;
/* try if there are generic encap protocol
receiver routines and signal the closure of
the link */
if( pops && pops -> disconn_ind )
pops -> disconn_ind(cprot);
}
int isdn_x25_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
/* At this point hard_start_xmit() passes control to the encapsulation
protocol (if present).
For X.25 auto-dialing is completly bypassed because:
- It does not conform with the semantics of a reliable datalink
service as needed by X.25 PLP.
- I don't want that the interface starts dialing when the network layer
sends a message which requests to disconnect the lapb link (or if it
sends any other message not resulting in data transmission).
Instead, dialing will be initiated by the encapsulation protocol entity
when a dl_establish request is received from the upper layer.
*/
isdn_net_local *lp = (isdn_net_local *) dev->priv;
struct concap_proto * cprot = lp -> netdev -> cprot;
int ret = cprot -> pops -> encap_and_xmit ( cprot , skb);
if (ret)
netif_stop_queue(dev);
return ret;
}
static void
isdn_x25_receive(isdn_net_dev *p, isdn_net_local *olp, struct sk_buff *skb)
{
isdn_net_local *lp = &p->local;
struct concap_proto *cprot = lp -> netdev -> cprot;
/* try if there are generic sync_device receiver routines */
if(cprot)
if(cprot -> pops)
if( cprot -> pops -> data_ind) {
cprot -> pops -> data_ind(cprot,skb);
return;
}
}
void isdn_x25_realrm(isdn_net_dev *p)
{
if( p -> cprot && p -> cprot -> pops )
p -> cprot -> pops -> proto_del ( p -> cprot );
}
int isdn_x25_setup(isdn_net_dev *p, int encap)
{
isdn_net_local *lp = &p->local;
/* ... , prepare for configuration of new one ... */
switch ( encap ){
case ISDN_NET_ENCAP_X25IFACE:
lp -> dops = &isdn_concap_reliable_dl_dops;
}
/* ... and allocate new one ... */
p -> cprot = isdn_concap_new( cfg -> p_encap );
/* p -> cprot == NULL now if p_encap is not supported
by means of the concap_proto mechanism */
if (!p->cprot)
return -EINVAL;
p->dev.type = ARPHRD_X25; /* change ARP type */
p->dev.addr_len = 0;
p->dev.hard_header = NULL;
p->dev.hard_header_cache = NULL;
p->dev.header_cache_update = NULL;
p->local.receive = isdn_x25_receive;
p->local.connected = isdn_x25_connected;
p->local.disconnected = isdn_x25_disconnected;
/* the protocol is not configured yet; this will
happen later when isdn_x25_open() is called */
return 0;
}
#endif /* CONFIG_ISDN_X25 */
...@@ -9,6 +9,51 @@ ...@@ -9,6 +9,51 @@
extern struct concap_device_ops isdn_concap_reliable_dl_dops; extern struct concap_device_ops isdn_concap_reliable_dl_dops;
extern struct concap_device_ops isdn_concap_demand_dial_dops; extern struct concap_device_ops isdn_concap_demand_dial_dops;
extern struct concap_proto * isdn_concap_new( int );
struct concap_proto *isdn_concap_new(int);
#ifdef CONFIG_ISDN_X25
int isdn_x25_setup(isdn_net_dev *p, int encap);
void isdn_x25_cleanup(isdn_net_dev *p);
void isdn_x25_open(struct net_device *dev);
void isdn_x25_close(struct net_device *dev);
int isdn_x25_start_xmit(struct sk_buff *skb, struct net_device *dev);
void isdn_x25_realrm(isdn_net_dev *p);
#else
static inline void
isdn_x25_cleanup(isdn_net_dev *p)
{
}
static inline int
isdn_x25_setup(isdn_net_dev *p, int encap)
{
printk(KERN_WARNING "ISDN: X25 support not configured\n");
return -EINVAL;
}
static inline void
isdn_x25_open(struct net_device *dev)
{
}
static inline void
isdn_x25_close(struct net_device *dev)
{
}
static inline int
isdn_x25_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
return 0;
}
static inline void
isdn_x25_realrm(isdn_net_dev *p)
{
}
#endif
...@@ -3,8 +3,9 @@ ...@@ -3,8 +3,9 @@
* Linux ISDN subsystem, network interfaces and related functions (linklevel). * Linux ISDN subsystem, network interfaces and related functions (linklevel).
* *
* Copyright 1994-1998 by Fritz Elfert (fritz@isdn4linux.de) * Copyright 1994-1998 by Fritz Elfert (fritz@isdn4linux.de)
* Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg * 1995,96 by Thinking Objects Software GmbH Wuerzburg
* Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de) * 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
* 1999-2002 by Kai Germaschewski <kai@germaschewski.name>
* *
* This software may be used and distributed according to the terms * This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference. * of the GNU General Public License, incorporated herein by reference.
...@@ -17,9 +18,6 @@ ...@@ -17,9 +18,6 @@
* 'V' - accept VOICE (DOV) only * 'V' - accept VOICE (DOV) only
* 'B' - accept BOTH DATA and DOV types * 'B' - accept BOTH DATA and DOV types
* *
* Jan 2001: fix CISCO HDLC Bjoern A. Zeeb <i4l@zabbadoz.net>
* for info on the protocol, see
* http://i4l.zabbadoz.net/i4l/cisco-hdlc.txt
*/ */
#include <linux/config.h> #include <linux/config.h>
...@@ -30,13 +28,10 @@ ...@@ -30,13 +28,10 @@
#include <linux/inetdevice.h> #include <linux/inetdevice.h>
#include "isdn_common.h" #include "isdn_common.h"
#include "isdn_net.h" #include "isdn_net.h"
#ifdef CONFIG_ISDN_PPP
#include "isdn_ppp.h" #include "isdn_ppp.h"
#endif
#ifdef CONFIG_ISDN_X25
#include <linux/concap.h> #include <linux/concap.h>
#include "isdn_concap.h" #include "isdn_concap.h"
#endif #include "isdn_ciscohdlck.h"
enum { enum {
ST_NULL, ST_NULL,
...@@ -109,18 +104,6 @@ static __inline__ int isdn_net_device_started(isdn_net_dev *n) ...@@ -109,18 +104,6 @@ static __inline__ int isdn_net_device_started(isdn_net_dev *n)
return netif_running(dev); return netif_running(dev);
} }
/*
* wake up the network -> net_device queue.
* For slaves, wake the corresponding master interface.
*/
static __inline__ void isdn_net_device_wake_queue(isdn_net_local *lp)
{
if (lp->master)
netif_wake_queue(lp->master);
else
netif_wake_queue(&lp->netdev->dev);
}
/* /*
* stop the network -> net_device queue. * stop the network -> net_device queue.
* For slaves, stop the corresponding master interface. * For slaves, stop the corresponding master interface.
...@@ -208,11 +191,13 @@ int isdn_net_force_dial_lp(isdn_net_local *); ...@@ -208,11 +191,13 @@ int isdn_net_force_dial_lp(isdn_net_local *);
static int isdn_net_start_xmit(struct sk_buff *, struct net_device *); static int isdn_net_start_xmit(struct sk_buff *, struct net_device *);
static void do_dialout(isdn_net_local *lp); static void do_dialout(isdn_net_local *lp);
static void isdn_net_ciscohdlck_connected(isdn_net_local *lp);
static void isdn_net_ciscohdlck_disconnected(isdn_net_local *lp);
static int isdn_net_handle_event(isdn_net_local *lp, int pr, void *arg); static int isdn_net_handle_event(isdn_net_local *lp, int pr, void *arg);
static int isdn_rawip_setup(isdn_net_dev *p);
static int isdn_ether_setup(isdn_net_dev *p);
static int isdn_uihdlc_setup(isdn_net_dev *p);
static int isdn_iptyp_setup(isdn_net_dev *p);
char *isdn_net_revision = "$Revision: 1.140.6.11 $"; char *isdn_net_revision = "$Revision: 1.140.6.11 $";
/* /*
...@@ -232,27 +217,6 @@ isdn_net_unreachable(struct net_device *dev, struct sk_buff *skb, char *reason) ...@@ -232,27 +217,6 @@ isdn_net_unreachable(struct net_device *dev, struct sk_buff *skb, char *reason)
dst_link_failure(skb); dst_link_failure(skb);
} }
static void
isdn_net_reset(struct net_device *dev)
{
#ifdef CONFIG_ISDN_X25
struct concap_device_ops * dops =
( (isdn_net_local *) dev->priv ) -> dops;
struct concap_proto * cprot =
( (isdn_net_local *) dev->priv ) -> netdev -> cprot;
#endif
ulong flags;
/* not sure if the cli() is needed at all --KG */
save_flags(flags);
cli(); /* Avoid glitch on writes to CMD regs */
#ifdef CONFIG_ISDN_X25
if( cprot && cprot -> pops && dops )
cprot -> pops -> restart ( cprot, dev, dops );
#endif
restore_flags(flags);
}
/* Open/initialize the board. */ /* Open/initialize the board. */
static int static int
isdn_net_open(struct net_device *dev) isdn_net_open(struct net_device *dev)
...@@ -266,7 +230,7 @@ isdn_net_open(struct net_device *dev) ...@@ -266,7 +230,7 @@ isdn_net_open(struct net_device *dev)
we need to call netif_start_queue, not netif_wake_queue here */ we need to call netif_start_queue, not netif_wake_queue here */
netif_start_queue(dev); netif_start_queue(dev);
isdn_net_reset(dev); isdn_x25_open(dev);
/* Fill in the MAC-level header (not needed, but for compatibility... */ /* Fill in the MAC-level header (not needed, but for compatibility... */
for (i = 0; i < ETH_ALEN - sizeof(u32); i++) for (i = 0; i < ETH_ALEN - sizeof(u32); i++)
dev->dev_addr[i] = 0xfc; dev->dev_addr[i] = 0xfc;
...@@ -283,7 +247,7 @@ isdn_net_open(struct net_device *dev) ...@@ -283,7 +247,7 @@ isdn_net_open(struct net_device *dev)
if ((p = (((isdn_net_local *) dev->priv)->slave))) { if ((p = (((isdn_net_local *) dev->priv)->slave))) {
while (p) { while (p) {
isdn_net_reset(p); isdn_x25_open(p);
p = (((isdn_net_local *) p->priv)->slave); p = (((isdn_net_local *) p->priv)->slave);
} }
} }
...@@ -405,16 +369,10 @@ static void isdn_net_lp_disconnected(isdn_net_local *lp) ...@@ -405,16 +369,10 @@ static void isdn_net_lp_disconnected(isdn_net_local *lp)
static void isdn_net_connected(isdn_net_local *lp) static void isdn_net_connected(isdn_net_local *lp)
{ {
#ifdef CONFIG_ISDN_X25
struct concap_proto *cprot = lp -> netdev -> cprot;
struct concap_proto_ops *pops = cprot ? cprot -> pops : 0;
#endif
lp->dialstate = ST_ACTIVE; lp->dialstate = ST_ACTIVE;
lp->hup_timer.expires = jiffies + HZ; lp->hup_timer.expires = jiffies + HZ;
add_timer(&lp->hup_timer); add_timer(&lp->hup_timer);
if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK)
isdn_net_ciscohdlck_connected(lp);
if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP) { if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP) {
if (lp->master) { /* is lp a slave? */ if (lp->master) { /* is lp a slave? */
isdn_net_dev *nd = ((isdn_net_local *)lp->master->priv)->netdev; isdn_net_dev *nd = ((isdn_net_local *)lp->master->priv)->netdev;
...@@ -435,19 +393,7 @@ static void isdn_net_connected(isdn_net_local *lp) ...@@ -435,19 +393,7 @@ static void isdn_net_connected(isdn_net_local *lp)
lp->cps = 0; lp->cps = 0;
lp->last_jiffies = jiffies; lp->last_jiffies = jiffies;
#ifdef CONFIG_ISDN_PPP lp->connected(lp);
if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
isdn_ppp_wakeup_daemon(lp);
#endif
#ifdef CONFIG_ISDN_X25
/* try if there are generic concap receiver routines */
if( pops )
if( pops->connect_ind)
pops->connect_ind(cprot);
#endif /* CONFIG_ISDN_X25 */
/* ppp needs to do negotiations first */
if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP)
isdn_net_device_wake_queue(lp);
} }
/* /*
...@@ -583,10 +529,6 @@ do_dialout(isdn_net_local *lp) ...@@ -583,10 +529,6 @@ do_dialout(isdn_net_local *lp)
static int static int
isdn_net_handle_event(isdn_net_local *lp, int pr, void *arg) isdn_net_handle_event(isdn_net_local *lp, int pr, void *arg)
{ {
#ifdef CONFIG_ISDN_X25
struct concap_proto *cprot = lp -> netdev -> cprot;
struct concap_proto_ops *pops = cprot ? cprot -> pops : 0;
#endif
isdn_net_dev *p = lp->netdev; isdn_net_dev *p = lp->netdev;
isdn_ctrl *c = arg; isdn_ctrl *c = arg;
isdn_ctrl cmd; isdn_ctrl cmd;
...@@ -606,45 +548,19 @@ isdn_net_handle_event(isdn_net_local *lp, int pr, void *arg) ...@@ -606,45 +548,19 @@ isdn_net_handle_event(isdn_net_local *lp, int pr, void *arg)
} }
break; break;
case ISDN_STAT_DHUP: case ISDN_STAT_DHUP:
/* Either D-Channel-hangup or error during dialout */ if (!(lp->flags & ISDN_NET_CONNECTED))
#ifdef CONFIG_ISDN_X25 // FIXME handle != ST_0? break;
/* If we are not connencted then dialing had
failed. If there are generic encap protocol if (lp->disconnected)
receiver routines signal the closure of lp->disconnected(lp);
the link*/
isdn_net_lp_disconnected(lp);
if (!(lp->flags & ISDN_NET_CONNECTED) isdn_slot_all_eaz(lp->isdn_slot);
&& pops && pops->disconn_ind) printk(KERN_INFO "%s: remote hangup\n", lp->name);
pops -> disconn_ind(cprot); printk(KERN_INFO "%s: Chargesum is %d\n", lp->name,
#endif /* CONFIG_ISDN_X25 */ lp->charge);
if (lp->flags & ISDN_NET_CONNECTED) { isdn_net_unbind_channel(lp);
if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK) return 1;
isdn_net_ciscohdlck_disconnected(lp);
#ifdef CONFIG_ISDN_PPP
if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
isdn_ppp_free(lp);
#endif
isdn_net_lp_disconnected(lp);
isdn_slot_all_eaz(lp->isdn_slot);
printk(KERN_INFO "%s: remote hangup\n", lp->name);
printk(KERN_INFO "%s: Chargesum is %d\n", lp->name,
lp->charge);
isdn_net_unbind_channel(lp);
return 1;
}
break;
#ifdef CONFIG_ISDN_X25 // FIXME handle != ST_0?
case ISDN_STAT_BHUP:
/* B-Channel-hangup */
/* try if there are generic encap protocol
receiver routines and signal the closure of
the link */
if( pops && pops -> disconn_ind ){
pops -> disconn_ind(cprot);
return 1;
}
break;
#endif /* CONFIG_ISDN_X25 */
case ISDN_STAT_CINF: case ISDN_STAT_CINF:
/* Charge-info from TelCo. Calculate interval between /* Charge-info from TelCo. Calculate interval between
* charge-infos and set timestamp for last info for * charge-infos and set timestamp for last info for
...@@ -777,10 +693,6 @@ void ...@@ -777,10 +693,6 @@ void
isdn_net_hangup(isdn_net_local *lp) isdn_net_hangup(isdn_net_local *lp)
{ {
isdn_ctrl cmd; isdn_ctrl cmd;
#ifdef CONFIG_ISDN_X25
struct concap_proto *cprot = lp -> netdev -> cprot;
struct concap_proto_ops *pops = cprot ? cprot -> pops : 0;
#endif
del_timer_sync(&lp->hup_timer); del_timer_sync(&lp->hup_timer);
if (lp->flags & ISDN_NET_CONNECTED) { if (lp->flags & ISDN_NET_CONNECTED) {
...@@ -794,18 +706,10 @@ isdn_net_hangup(isdn_net_local *lp) ...@@ -794,18 +706,10 @@ isdn_net_hangup(isdn_net_local *lp)
} }
} }
printk(KERN_INFO "isdn_net: local hangup %s\n", lp->name); printk(KERN_INFO "isdn_net: local hangup %s\n", lp->name);
#ifdef CONFIG_ISDN_PPP if (lp->disconnected)
if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) lp->disconnected(lp);
isdn_ppp_free(lp);
#endif
isdn_net_lp_disconnected(lp); isdn_net_lp_disconnected(lp);
#ifdef CONFIG_ISDN_X25
/* try if there are generic encap protocol
receiver routines and signal the closure of
the link */
if( pops && pops -> disconn_ind )
pops -> disconn_ind(cprot);
#endif /* CONFIG_ISDN_X25 */
isdn_slot_command(lp->isdn_slot, ISDN_CMD_HANGUP, &cmd); isdn_slot_command(lp->isdn_slot, ISDN_CMD_HANGUP, &cmd);
printk(KERN_INFO "%s: Chargesum is %d\n", lp->name, lp->charge); printk(KERN_INFO "%s: Chargesum is %d\n", lp->name, lp->charge);
...@@ -861,12 +765,10 @@ isdn_net_log_skb(struct sk_buff * skb, isdn_net_local * lp) ...@@ -861,12 +765,10 @@ isdn_net_log_skb(struct sk_buff * skb, isdn_net_local * lp)
proto = ntohs(*(unsigned short *) &buf[2]); proto = ntohs(*(unsigned short *) &buf[2]);
p = &buf[4]; p = &buf[4];
break; break;
#ifdef CONFIG_ISDN_PPP
case ISDN_NET_ENCAP_SYNCPPP: case ISDN_NET_ENCAP_SYNCPPP:
proto = ntohs(skb->protocol); proto = ntohs(skb->protocol);
p = &buf[IPPP_MAX_HEADER]; p = &buf[IPPP_MAX_HEADER];
break; break;
#endif
} }
} }
data_ofs = ((p[0] & 15) * 4); data_ofs = ((p[0] & 15) * 4);
...@@ -1025,11 +927,9 @@ isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb) ...@@ -1025,11 +927,9 @@ isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb)
} }
/* For the other encaps the header has already been built */ /* For the other encaps the header has already been built */
#ifdef CONFIG_ISDN_PPP
if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) { if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) {
return isdn_ppp_xmit(skb, ndev); return isdn_ppp_xmit(skb, ndev);
} }
#endif
nd = ((isdn_net_local *) ndev->priv)->netdev; nd = ((isdn_net_local *) ndev->priv)->netdev;
lp = isdn_net_get_locked_lp(nd); lp = isdn_net_get_locked_lp(nd);
if (!lp) { if (!lp) {
...@@ -1138,27 +1038,10 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) ...@@ -1138,27 +1038,10 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
{ {
unsigned long flags; unsigned long flags;
isdn_net_local *lp = (isdn_net_local *) ndev->priv; isdn_net_local *lp = (isdn_net_local *) ndev->priv;
#ifdef CONFIG_ISDN_X25
struct concap_proto * cprot = lp -> netdev -> cprot; if (lp->p_encap == ISDN_NET_ENCAP_X25IFACE)
#endif return isdn_x25_start_xmit(skb, ndev);
#ifdef CONFIG_ISDN_X25
/* At this point hard_start_xmit() passes control to the encapsulation
protocol (if present).
For X.25 auto-dialing is completly bypassed because:
- It does not conform with the semantics of a reliable datalink
service as needed by X.25 PLP.
- I don't want that the interface starts dialing when the network layer
sends a message which requests to disconnect the lapb link (or if it
sends any other message not resulting in data transmission).
Instead, dialing will be initiated by the encapsulation protocol entity
when a dl_establish request is received from the upper layer.
*/
if( cprot ) {
int ret = cprot -> pops -> encap_and_xmit ( cprot , skb);
if(ret) netif_stop_queue(ndev);
return ret;
} else
#endif
/* auto-dialing xmit function */ /* auto-dialing xmit function */
{ {
isdn_net_adjust_hdr(skb, ndev); isdn_net_adjust_hdr(skb, ndev);
...@@ -1219,7 +1102,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) ...@@ -1219,7 +1102,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
isdn_net_log_skb(skb, lp); isdn_net_log_skb(skb, lp);
/* Connect interface with channel */ /* Connect interface with channel */
isdn_net_bind_channel(lp, chi); isdn_net_bind_channel(lp, chi);
#ifdef CONFIG_ISDN_PPP
if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) { if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) {
/* no 'first_skb' handling for syncPPP */ /* no 'first_skb' handling for syncPPP */
if (isdn_ppp_bind(lp) < 0) { if (isdn_ppp_bind(lp) < 0) {
...@@ -1233,7 +1116,6 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) ...@@ -1233,7 +1116,6 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
netif_stop_queue(ndev); netif_stop_queue(ndev);
return 1; /* let upper layer requeue skb packet */ return 1; /* let upper layer requeue skb packet */
} }
#endif
/* Initiate dialing */ /* Initiate dialing */
restore_flags(flags); restore_flags(flags);
init_dialout(lp); init_dialout(lp);
...@@ -1262,25 +1144,13 @@ static int ...@@ -1262,25 +1144,13 @@ static int
isdn_net_close(struct net_device *dev) isdn_net_close(struct net_device *dev)
{ {
struct net_device *p; struct net_device *p;
#ifdef CONFIG_ISDN_X25
struct concap_proto * cprot =
( (isdn_net_local *) dev->priv ) -> netdev -> cprot;
/* printk(KERN_DEBUG "isdn_net_close %s\n" , dev-> name ); */
#endif
#ifdef CONFIG_ISDN_X25 isdn_x25_close(dev);
if( cprot && cprot -> pops ) cprot -> pops -> close( cprot );
#endif
netif_stop_queue(dev); netif_stop_queue(dev);
if ((p = (((isdn_net_local *) dev->priv)->slave))) { if ((p = (((isdn_net_local *) dev->priv)->slave))) {
/* If this interface has slaves, stop them also */ /* If this interface has slaves, stop them also */
while (p) { while (p) {
#ifdef CONFIG_ISDN_X25 isdn_x25_close(p);
cprot = ( (isdn_net_local *) p->priv )
-> netdev -> cprot;
if( cprot && cprot -> pops )
cprot -> pops -> close( cprot );
#endif
isdn_net_hangup(p->priv); isdn_net_hangup(p->priv);
p = (((isdn_net_local *) p->priv)->slave); p = (((isdn_net_local *) p->priv)->slave);
} }
...@@ -1300,417 +1170,6 @@ isdn_net_get_stats(struct net_device *dev) ...@@ -1300,417 +1170,6 @@ isdn_net_get_stats(struct net_device *dev)
return &lp->stats; return &lp->stats;
} }
/* This is simply a copy from std. eth.c EXCEPT we pull ETH_HLEN
* instead of dev->hard_header_len off. This is done because the
* lowlevel-driver has already pulled off its stuff when we get
* here and this routine only gets called with p_encap == ETHER.
* Determine the packet's protocol ID. The rule here is that we
* assume 802.3 if the type field is short enough to be a length.
* This is normal practice and works for any 'now in use' protocol.
*/
static unsigned short
isdn_net_type_trans(struct sk_buff *skb, struct net_device *dev)
{
struct ethhdr *eth;
unsigned char *rawp;
skb->mac.raw = skb->data;
skb_pull(skb, ETH_HLEN);
eth = skb->mac.ethernet;
if (*eth->h_dest & 1) {
if (memcmp(eth->h_dest, dev->broadcast, ETH_ALEN) == 0)
skb->pkt_type = PACKET_BROADCAST;
else
skb->pkt_type = PACKET_MULTICAST;
}
/*
* This ALLMULTI check should be redundant by 1.4
* so don't forget to remove it.
*/
else if (dev->flags & (IFF_PROMISC /*| IFF_ALLMULTI*/)) {
if (memcmp(eth->h_dest, dev->dev_addr, ETH_ALEN))
skb->pkt_type = PACKET_OTHERHOST;
}
if (ntohs(eth->h_proto) >= 1536)
return eth->h_proto;
rawp = skb->data;
/*
* This is a magic hack to spot IPX packets. Older Novell breaks
* the protocol design and runs IPX over 802.3 without an 802.2 LLC
* layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
* won't work for fault tolerant netware but does for the rest.
*/
if (*(unsigned short *) rawp == 0xFFFF)
return htons(ETH_P_802_3);
/*
* Real 802.2 LLC
*/
return htons(ETH_P_802_2);
}
/*
* CISCO HDLC keepalive specific stuff
*/
static struct sk_buff*
isdn_net_ciscohdlck_alloc_skb(isdn_net_local *lp, int len)
{
unsigned short hl = isdn_slot_hdrlen(lp->isdn_slot);
struct sk_buff *skb;
skb = alloc_skb(hl + len, GFP_ATOMIC);
if (!skb) {
printk("isdn out of mem at %s:%d!\n", __FILE__, __LINE__);
return 0;
}
skb_reserve(skb, hl);
return skb;
}
/* cisco hdlck device private ioctls */
int
isdn_ciscohdlck_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
isdn_net_local *lp = (isdn_net_local *) dev->priv;
unsigned long len = 0;
unsigned long expires = 0;
int tmp = 0;
int period = lp->cisco_keepalive_period;
char debserint = lp->cisco_debserint;
int rc = 0;
if (lp->p_encap != ISDN_NET_ENCAP_CISCOHDLCK)
return -EINVAL;
switch (cmd) {
/* get/set keepalive period */
case SIOCGKEEPPERIOD:
len = (unsigned long)sizeof(lp->cisco_keepalive_period);
if (copy_to_user((char *)ifr->ifr_ifru.ifru_data,
(int *)&lp->cisco_keepalive_period, len))
rc = -EFAULT;
break;
case SIOCSKEEPPERIOD:
tmp = lp->cisco_keepalive_period;
len = (unsigned long)sizeof(lp->cisco_keepalive_period);
if (copy_from_user((int *)&period,
(char *)ifr->ifr_ifru.ifru_data, len))
rc = -EFAULT;
if ((period > 0) && (period <= 32767))
lp->cisco_keepalive_period = period;
else
rc = -EINVAL;
if (!rc && (tmp != lp->cisco_keepalive_period)) {
expires = (unsigned long)(jiffies +
lp->cisco_keepalive_period * HZ);
mod_timer(&lp->cisco_timer, expires);
printk(KERN_INFO "%s: Keepalive period set "
"to %d seconds.\n",
lp->name, lp->cisco_keepalive_period);
}
break;
/* get/set debugging */
case SIOCGDEBSERINT:
len = (unsigned long)sizeof(lp->cisco_debserint);
if (copy_to_user((char *)ifr->ifr_ifru.ifru_data,
(char *)&lp->cisco_debserint, len))
rc = -EFAULT;
break;
case SIOCSDEBSERINT:
len = (unsigned long)sizeof(lp->cisco_debserint);
if (copy_from_user((char *)&debserint,
(char *)ifr->ifr_ifru.ifru_data, len))
rc = -EFAULT;
if ((debserint >= 0) && (debserint <= 64))
lp->cisco_debserint = debserint;
else
rc = -EINVAL;
break;
default:
rc = -EINVAL;
break;
}
return (rc);
}
/* called via cisco_timer.function */
static void
isdn_net_ciscohdlck_slarp_send_keepalive(unsigned long data)
{
isdn_net_local *lp = (isdn_net_local *) data;
struct sk_buff *skb;
unsigned char *p;
unsigned long last_cisco_myseq = lp->cisco_myseq;
int myseq_diff = 0;
if (!(lp->flags & ISDN_NET_CONNECTED) || lp->dialstate != ST_ACTIVE) {
isdn_BUG();
return;
}
lp->cisco_myseq++;
myseq_diff = (lp->cisco_myseq - lp->cisco_mineseen);
if ((lp->cisco_line_state) && ((myseq_diff >= 3)||(myseq_diff <= -3))) {
/* line up -> down */
lp->cisco_line_state = 0;
printk (KERN_WARNING
"UPDOWN: Line protocol on Interface %s,"
" changed state to down\n", lp->name);
/* should stop routing higher-level data accross */
} else if ((!lp->cisco_line_state) &&
(myseq_diff >= 0) && (myseq_diff <= 2)) {
/* line down -> up */
lp->cisco_line_state = 1;
printk (KERN_WARNING
"UPDOWN: Line protocol on Interface %s,"
" changed state to up\n", lp->name);
/* restart routing higher-level data accross */
}
if (lp->cisco_debserint)
printk (KERN_DEBUG "%s: HDLC "
"myseq %lu, mineseen %lu%c, yourseen %lu, %s\n",
lp->name, last_cisco_myseq, lp->cisco_mineseen,
((last_cisco_myseq == lp->cisco_mineseen) ? '*' : 040),
lp->cisco_yourseq,
((lp->cisco_line_state) ? "line up" : "line down"));
skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14);
if (!skb)
return;
p = skb_put(skb, 4 + 14);
/* cisco header */
p += put_u8 (p, CISCO_ADDR_UNICAST);
p += put_u8 (p, CISCO_CTRL);
p += put_u16(p, CISCO_TYPE_SLARP);
/* slarp keepalive */
p += put_u32(p, CISCO_SLARP_KEEPALIVE);
p += put_u32(p, lp->cisco_myseq);
p += put_u32(p, lp->cisco_yourseq);
p += put_u16(p, 0xffff); // reliablity, always 0xffff
isdn_net_write_super(lp, skb);
lp->cisco_timer.expires = jiffies + lp->cisco_keepalive_period * HZ;
add_timer(&lp->cisco_timer);
}
static void
isdn_net_ciscohdlck_slarp_send_request(isdn_net_local *lp)
{
struct sk_buff *skb;
unsigned char *p;
skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14);
if (!skb)
return;
p = skb_put(skb, 4 + 14);
/* cisco header */
p += put_u8 (p, CISCO_ADDR_UNICAST);
p += put_u8 (p, CISCO_CTRL);
p += put_u16(p, CISCO_TYPE_SLARP);
/* slarp request */
p += put_u32(p, CISCO_SLARP_REQUEST);
p += put_u32(p, 0); // address
p += put_u32(p, 0); // netmask
p += put_u16(p, 0); // unused
isdn_net_write_super(lp, skb);
}
static void
isdn_net_ciscohdlck_connected(isdn_net_local *lp)
{
lp->cisco_myseq = 0;
lp->cisco_mineseen = 0;
lp->cisco_yourseq = 0;
lp->cisco_keepalive_period = ISDN_TIMER_KEEPINT;
lp->cisco_last_slarp_in = 0;
lp->cisco_line_state = 0;
lp->cisco_debserint = 0;
/* send slarp request because interface/seq.no.s reset */
isdn_net_ciscohdlck_slarp_send_request(lp);
init_timer(&lp->cisco_timer);
lp->cisco_timer.data = (unsigned long) lp;
lp->cisco_timer.function = isdn_net_ciscohdlck_slarp_send_keepalive;
lp->cisco_timer.expires = jiffies + lp->cisco_keepalive_period * HZ;
add_timer(&lp->cisco_timer);
}
static void
isdn_net_ciscohdlck_disconnected(isdn_net_local *lp)
{
del_timer(&lp->cisco_timer);
}
static void
isdn_net_ciscohdlck_slarp_send_reply(isdn_net_local *lp)
{
struct sk_buff *skb;
unsigned char *p;
struct in_device *in_dev = NULL;
u32 addr = 0; /* local ipv4 address */
u32 mask = 0; /* local netmask */
if ((in_dev = lp->netdev->dev.ip_ptr) != NULL) {
/* take primary(first) address of interface */
struct in_ifaddr *ifa = in_dev->ifa_list;
if (ifa != NULL) {
addr = ifa->ifa_local;
mask = ifa->ifa_mask;
}
}
skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14);
if (!skb)
return;
p = skb_put(skb, 4 + 14);
/* cisco header */
p += put_u8 (p, CISCO_ADDR_UNICAST);
p += put_u8 (p, CISCO_CTRL);
p += put_u16(p, CISCO_TYPE_SLARP);
/* slarp reply, send own ip/netmask; if values are nonsense remote
* should think we are unable to provide it with an address via SLARP */
p += put_u32(p, CISCO_SLARP_REPLY);
p += put_u32(p, addr); // address
p += put_u32(p, mask); // netmask
p += put_u16(p, 0); // unused
isdn_net_write_super(lp, skb);
}
static void
isdn_net_ciscohdlck_slarp_in(isdn_net_local *lp, struct sk_buff *skb)
{
unsigned char *p;
int period;
u32 code;
u32 my_seq, addr;
u32 your_seq, mask;
u32 local;
u16 unused;
if (skb->len < 14)
return;
p = skb->data;
p += get_u32(p, &code);
switch (code) {
case CISCO_SLARP_REQUEST:
lp->cisco_yourseq = 0;
isdn_net_ciscohdlck_slarp_send_reply(lp);
break;
case CISCO_SLARP_REPLY:
addr = ntohl(*(u32 *)p);
mask = ntohl(*(u32 *)(p+4));
if (mask != 0xfffffffc)
goto slarp_reply_out;
if ((addr & 3) == 0 || (addr & 3) == 3)
goto slarp_reply_out;
local = addr ^ 3;
printk(KERN_INFO "%s: got slarp reply: "
"remote ip: %d.%d.%d.%d, "
"local ip: %d.%d.%d.%d "
"mask: %d.%d.%d.%d\n",
lp->name,
HIPQUAD(addr),
HIPQUAD(local),
HIPQUAD(mask));
break;
slarp_reply_out:
printk(KERN_INFO "%s: got invalid slarp "
"reply (%d.%d.%d.%d/%d.%d.%d.%d) "
"- ignored\n", lp->name,
HIPQUAD(addr), HIPQUAD(mask));
break;
case CISCO_SLARP_KEEPALIVE:
period = (int)((jiffies - lp->cisco_last_slarp_in
+ HZ/2 - 1) / HZ);
if (lp->cisco_debserint &&
(period != lp->cisco_keepalive_period) &&
lp->cisco_last_slarp_in) {
printk(KERN_DEBUG "%s: Keepalive period mismatch - "
"is %d but should be %d.\n",
lp->name, period, lp->cisco_keepalive_period);
}
lp->cisco_last_slarp_in = jiffies;
p += get_u32(p, &my_seq);
p += get_u32(p, &your_seq);
p += get_u16(p, &unused);
lp->cisco_yourseq = my_seq;
lp->cisco_mineseen = your_seq;
break;
}
}
static void
isdn_net_ciscohdlck_receive(isdn_net_local *lp, struct sk_buff *skb)
{
unsigned char *p;
u8 addr;
u8 ctrl;
u16 type;
if (skb->len < 4)
goto out_free;
p = skb->data;
p += get_u8 (p, &addr);
p += get_u8 (p, &ctrl);
p += get_u16(p, &type);
skb_pull(skb, 4);
if (addr != CISCO_ADDR_UNICAST && addr != CISCO_ADDR_BROADCAST) {
printk(KERN_WARNING "%s: Unknown Cisco addr 0x%02x\n",
lp->name, addr);
goto out_free;
}
if (ctrl != CISCO_CTRL) {
printk(KERN_WARNING "%s: Unknown Cisco ctrl 0x%02x\n",
lp->name, ctrl);
goto out_free;
}
switch (type) {
case CISCO_TYPE_SLARP:
isdn_net_ciscohdlck_slarp_in(lp, skb);
goto out_free;
case CISCO_TYPE_CDP:
if (lp->cisco_debserint)
printk(KERN_DEBUG "%s: Received CDP packet. use "
"\"no cdp enable\" on cisco.\n", lp->name);
goto out_free;
default:
/* no special cisco protocol */
skb->protocol = htons(type);
netif_rx(skb);
return;
}
out_free:
kfree_skb(skb);
}
/* /*
* Got a packet from ISDN-Channel. * Got a packet from ISDN-Channel.
*/ */
...@@ -1719,12 +1178,7 @@ isdn_net_receive(struct net_device *ndev, struct sk_buff *skb) ...@@ -1719,12 +1178,7 @@ isdn_net_receive(struct net_device *ndev, struct sk_buff *skb)
{ {
isdn_net_local *lp = (isdn_net_local *) ndev->priv; isdn_net_local *lp = (isdn_net_local *) ndev->priv;
isdn_net_local *olp = lp; /* original 'lp' */ isdn_net_local *olp = lp; /* original 'lp' */
#ifdef CONFIG_ISDN_PPP
int proto = PPP_PROTOCOL(skb->data);
#endif
#ifdef CONFIG_ISDN_X25
struct concap_proto *cprot = lp -> netdev -> cprot;
#endif
lp->transcount += skb->len; lp->transcount += skb->len;
lp->stats.rx_packets++; lp->stats.rx_packets++;
...@@ -1742,72 +1196,8 @@ isdn_net_receive(struct net_device *ndev, struct sk_buff *skb) ...@@ -1742,72 +1196,8 @@ isdn_net_receive(struct net_device *ndev, struct sk_buff *skb)
skb->pkt_type = PACKET_HOST; skb->pkt_type = PACKET_HOST;
skb->mac.raw = skb->data; skb->mac.raw = skb->data;
isdn_dumppkt("R:", skb->data, skb->len, 40); isdn_dumppkt("R:", skb->data, skb->len, 40);
switch (lp->p_encap) {
case ISDN_NET_ENCAP_ETHER:
/* Ethernet over ISDN */
olp->huptimer = 0;
lp->huptimer = 0;
skb->protocol = isdn_net_type_trans(skb, ndev);
break;
case ISDN_NET_ENCAP_UIHDLC:
/* HDLC with UI-frame (for ispa with -h1 option) */
olp->huptimer = 0;
lp->huptimer = 0;
skb_pull(skb, 2);
/* Fall through */
case ISDN_NET_ENCAP_RAWIP:
/* RAW-IP without MAC-Header */
olp->huptimer = 0;
lp->huptimer = 0;
skb->protocol = htons(ETH_P_IP);
break;
case ISDN_NET_ENCAP_CISCOHDLCK:
isdn_net_ciscohdlck_receive(lp, skb);
return;
case ISDN_NET_ENCAP_CISCOHDLC:
/* CISCO-HDLC IP with type field and fake I-frame-header */
skb_pull(skb, 2);
/* Fall through */
case ISDN_NET_ENCAP_IPTYP:
/* IP with type field */
olp->huptimer = 0;
lp->huptimer = 0;
skb->protocol = *(unsigned short *) &(skb->data[0]);
skb_pull(skb, 2);
if (*(unsigned short *) skb->data == 0xFFFF)
skb->protocol = htons(ETH_P_802_3);
break;
#ifdef CONFIG_ISDN_PPP
case ISDN_NET_ENCAP_SYNCPPP:
/*
* If encapsulation is syncppp, don't reset
* huptimer on LCP packets.
*/
if (proto != PPP_LCP) {
olp->huptimer = 0;
lp->huptimer = 0;
}
isdn_ppp_receive(lp->netdev, olp, skb);
return;
#endif
default:
#ifdef CONFIG_ISDN_X25
/* try if there are generic sync_device receiver routines */
if(cprot) if(cprot -> pops)
if( cprot -> pops -> data_ind){
cprot -> pops -> data_ind(cprot,skb);
return;
};
#endif /* CONFIG_ISDN_X25 */
printk(KERN_WARNING "%s: unknown encapsulation, dropping\n",
lp->name);
kfree_skb(skb);
return;
}
netif_rx(skb); lp->receive(lp->netdev, olp, skb);
return;
} }
/* /*
...@@ -1831,120 +1221,20 @@ isdn_net_rcv_skb(int idx, struct sk_buff *skb) ...@@ -1831,120 +1221,20 @@ isdn_net_rcv_skb(int idx, struct sk_buff *skb)
return 0; return 0;
} }
/* We don't need to send arp, because we have point-to-point connections. */
static int static int
my_eth_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, isdn_net_rebuild_header(struct sk_buff *skb)
void *daddr, void *saddr, unsigned len)
{ {
struct ethhdr *eth = (struct ethhdr *) skb_push(skb, ETH_HLEN); struct net_device *dev = skb->dev;
isdn_net_local *lp = dev->priv;
/* int ret = 0;
* Set the protocol type. For a packet of type ETH_P_802_3 we
* put the length here instead. It is up to the 802.2 layer to
* carry protocol information.
*/
if (type != ETH_P_802_3)
eth->h_proto = htons(type);
else
eth->h_proto = htons(len);
/*
* Set the source hardware address.
*/
if (saddr)
memcpy(eth->h_source, saddr, dev->addr_len);
else
memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
/* if (lp->p_encap == ISDN_NET_ENCAP_ETHER) {
* Anyway, the loopback-device should never use this function... struct ethhdr *eth = (struct ethhdr *) skb->data;
*/
if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) { /*
memset(eth->h_dest, 0, dev->addr_len); * Only ARP/IP is currently supported
return ETH_HLEN /*(dev->hard_header_len)*/; */
}
if (daddr) {
memcpy(eth->h_dest, daddr, dev->addr_len);
return ETH_HLEN /*dev->hard_header_len*/;
}
return -ETH_HLEN /*dev->hard_header_len*/;
}
/*
* build an header
* depends on encaps that is being used.
*/
static int
isdn_net_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
void *daddr, void *saddr, unsigned plen)
{
isdn_net_local *lp = dev->priv;
unsigned char *p;
ushort len = 0;
switch (lp->p_encap) {
case ISDN_NET_ENCAP_ETHER:
len = my_eth_header(skb, dev, type, daddr, saddr, plen);
break;
#ifdef CONFIG_ISDN_PPP
case ISDN_NET_ENCAP_SYNCPPP:
/* stick on a fake header to keep fragmentation code happy. */
len = IPPP_MAX_HEADER;
skb_push(skb,len);
break;
#endif
case ISDN_NET_ENCAP_RAWIP:
printk(KERN_WARNING "isdn_net_header called with RAW_IP!\n");
len = 0;
break;
case ISDN_NET_ENCAP_IPTYP:
/* ethernet type field */
*((ushort *) skb_push(skb, 2)) = htons(type);
len = 2;
break;
case ISDN_NET_ENCAP_UIHDLC:
/* HDLC with UI-Frames (for ispa with -h1 option) */
*((ushort *) skb_push(skb, 2)) = htons(0x0103);
len = 2;
break;
case ISDN_NET_ENCAP_CISCOHDLC:
case ISDN_NET_ENCAP_CISCOHDLCK:
p = skb_push(skb, 4);
p += put_u8 (p, CISCO_ADDR_UNICAST);
p += put_u8 (p, CISCO_CTRL);
p += put_u16(p, type);
len = 4;
break;
#ifdef CONFIG_ISDN_X25
default:
/* try if there are generic concap protocol routines */
if( lp-> netdev -> cprot ){
printk(KERN_WARNING "isdn_net_header called with concap_proto!\n");
len = 0;
break;
}
break;
#endif /* CONFIG_ISDN_X25 */
}
return len;
}
/* We don't need to send arp, because we have point-to-point connections. */
static int
isdn_net_rebuild_header(struct sk_buff *skb)
{
struct net_device *dev = skb->dev;
isdn_net_local *lp = dev->priv;
int ret = 0;
if (lp->p_encap == ISDN_NET_ENCAP_ETHER) {
struct ethhdr *eth = (struct ethhdr *) skb->data;
/*
* Only ARP/IP is currently supported
*/
if (eth->h_proto != htons(ETH_P_IP)) { if (eth->h_proto != htons(ETH_P_IP)) {
printk(KERN_WARNING printk(KERN_WARNING
...@@ -1970,12 +1260,9 @@ static int ...@@ -1970,12 +1260,9 @@ static int
isdn_net_init(struct net_device *ndev) isdn_net_init(struct net_device *ndev)
{ {
ushort max_hlhdr_len = 0; ushort max_hlhdr_len = 0;
isdn_net_local *lp = (isdn_net_local *) ndev->priv;
int drvidx, i; int drvidx, i;
ether_setup(ndev); ether_setup(ndev);
lp->org_hhc = ndev->hard_header_cache;
lp->org_hcu = ndev->header_cache_update;
/* Setup the generic properties */ /* Setup the generic properties */
...@@ -2312,14 +1599,13 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup) ...@@ -2312,14 +1599,13 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
lp->dialstate = ST_WAIT_BEFORE_CB; lp->dialstate = ST_WAIT_BEFORE_CB;
/* Connect interface with channel */ /* Connect interface with channel */
isdn_net_bind_channel(lp, chi); isdn_net_bind_channel(lp, chi);
#ifdef CONFIG_ISDN_PPP
if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
if (isdn_ppp_bind(lp) < 0) { if (isdn_ppp_bind(lp) < 0) {
isdn_net_unbind_channel(lp); isdn_net_unbind_channel(lp);
restore_flags(flags); restore_flags(flags);
return 0; return 0;
} }
#endif
/* Initiate dialing by returning 2 or 4 */ /* Initiate dialing by returning 2 or 4 */
restore_flags(flags); restore_flags(flags);
return (lp->flags & ISDN_NET_CBHUP) ? 2 : 4; return (lp->flags & ISDN_NET_CBHUP) ? 2 : 4;
...@@ -2329,10 +1615,9 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup) ...@@ -2329,10 +1615,9 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
/* if this interface is dialing, it does it probably on a different /* if this interface is dialing, it does it probably on a different
device, so free this device */ device, so free this device */
if (lp->dialstate == ST_OUT_WAIT_DCONN) { if (lp->dialstate == ST_OUT_WAIT_DCONN) {
#ifdef CONFIG_ISDN_PPP if (lp->disconnected)
if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) lp->disconnected(lp);
isdn_ppp_free(lp);
#endif
isdn_net_lp_disconnected(lp); isdn_net_lp_disconnected(lp);
isdn_slot_free(lp->isdn_slot, isdn_slot_free(lp->isdn_slot,
ISDN_USAGE_NET); ISDN_USAGE_NET);
...@@ -2360,14 +1645,12 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup) ...@@ -2360,14 +1645,12 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
add_timer(&lp->dial_timer); add_timer(&lp->dial_timer);
lp->dialstate = ST_IN_WAIT_DCONN; lp->dialstate = ST_IN_WAIT_DCONN;
#ifdef CONFIG_ISDN_PPP
if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
if (isdn_ppp_bind(lp) < 0) { if (isdn_ppp_bind(lp) < 0) {
isdn_net_unbind_channel(lp); isdn_net_unbind_channel(lp);
restore_flags(flags); restore_flags(flags);
return 0; return 0;
} }
#endif
restore_flags(flags); restore_flags(flags);
return 1; return 1;
} }
...@@ -2423,14 +1706,12 @@ isdn_net_force_dial_lp(isdn_net_local * lp) ...@@ -2423,14 +1706,12 @@ isdn_net_force_dial_lp(isdn_net_local * lp)
} }
/* Connect interface with channel */ /* Connect interface with channel */
isdn_net_bind_channel(lp, chi); isdn_net_bind_channel(lp, chi);
#ifdef CONFIG_ISDN_PPP
if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
if (isdn_ppp_bind(lp) < 0) { if (isdn_ppp_bind(lp) < 0) {
isdn_net_unbind_channel(lp); isdn_net_unbind_channel(lp);
restore_flags(flags); restore_flags(flags);
return -EAGAIN; return -EAGAIN;
} }
#endif
/* Initiate dialing */ /* Initiate dialing */
restore_flags(flags); restore_flags(flags);
init_dialout(lp); init_dialout(lp);
...@@ -2533,7 +1814,7 @@ isdn_net_new(char *name, struct net_device *master) ...@@ -2533,7 +1814,7 @@ isdn_net_new(char *name, struct net_device *master)
netdev->local.isdn_slot = -1; netdev->local.isdn_slot = -1;
netdev->local.pre_device = -1; netdev->local.pre_device = -1;
netdev->local.pre_channel = -1; netdev->local.pre_channel = -1;
netdev->local.exclusive = -1; netdev->local.exclusive = 0;
netdev->local.ppp_slot = -1; netdev->local.ppp_slot = -1;
netdev->local.pppbind = -1; netdev->local.pppbind = -1;
skb_queue_head_init(&netdev->local.super_tx_queue); skb_queue_head_init(&netdev->local.super_tx_queue);
...@@ -2591,6 +1872,136 @@ isdn_net_newslave(char *parm) ...@@ -2591,6 +1872,136 @@ isdn_net_newslave(char *parm)
return isdn_net_new(p+1, &m->dev); return isdn_net_new(p+1, &m->dev);
} }
static int
isdn_net_set_encap(isdn_net_dev *p, isdn_net_ioctl_cfg *cfg)
{
isdn_net_local *lp = &p->local;
int retval;
if (lp->p_encap == cfg->p_encap){
/* nothing to do */
retval = 0;
goto out;
}
if (isdn_net_device_started(p)) {
retval = -EBUSY;
goto out;
}
switch (lp->p_encap) {
case ISDN_NET_ENCAP_X25IFACE:
isdn_x25_cleanup(p);
break;
}
lp->p_encap = cfg->p_encap;
switch (lp->p_encap) {
case ISDN_NET_ENCAP_SYNCPPP:
retval = isdn_ppp_setup(p);
break;
case ISDN_NET_ENCAP_X25IFACE:
retval = isdn_x25_setup(p, cfg->p_encap);
break;
case ISDN_NET_ENCAP_CISCOHDLC:
case ISDN_NET_ENCAP_CISCOHDLCK:
retval = isdn_ciscohdlck_setup(p);
break;
case ISDN_NET_ENCAP_RAWIP:
retval = isdn_rawip_setup(p);
break;
case ISDN_NET_ENCAP_ETHER:
retval = isdn_ether_setup(p);
break;
case ISDN_NET_ENCAP_UIHDLC:
retval = isdn_uihdlc_setup(p);
break;
case ISDN_NET_ENCAP_IPTYP:
retval = isdn_iptyp_setup(p);
break;
default:
retval = -EINVAL;
break;
}
if (retval != 0)
lp->p_encap = -1;
out:
return retval;
}
static int
isdn_net_bind(isdn_net_dev *p, isdn_net_ioctl_cfg *cfg)
{
isdn_net_local *lp = &p->local;
int i, retval;
int drvidx = -1;
int chidx = -1;
char drvid[25];
strncpy(drvid, cfg->drvid, 24);
drvid[24] = 0;
if (cfg->exclusive && !strlen(drvid)) {
/* If we want to bind exclusively, need to specify drv/chan */
retval = -ENODEV;
goto out;
}
if (strlen(drvid)) {
/* A bind has been requested ... */
char *c = strchr(drvid, ',');
if (!c) {
retval = -ENODEV;
goto out;
}
/* The channel-number is appended to the driver-Id with a comma */
*c = 0;
chidx = simple_strtol(c + 1, NULL, 10);
for (i = 0; i < ISDN_MAX_DRIVERS; i++) {
/* Lookup driver-Id in array */
if (!strcmp(dev->drvid[i], drvid)) {
drvidx = i;
break;
}
}
if (drvidx == -1 || chidx == -1) {
/* Either driver-Id or channel-number invalid */
retval = -ENODEV;
goto out;
}
}
if (cfg->exclusive == lp->exclusive &&
drvidx == lp->pre_device && chidx == lp->pre_channel) {
/* no change */
retval = 0;
goto out;
}
if (lp->exclusive) {
isdn_unexclusive_channel(lp->pre_device, lp->pre_channel);
isdn_free_channel(lp->pre_device, lp->pre_channel, ISDN_USAGE_NET);
lp->exclusive = 0;
}
if (cfg->exclusive) {
/* If binding is exclusive, try to grab the channel */
i = isdn_get_free_slot(ISDN_USAGE_NET, lp->l2_proto,
lp->l3_proto, drvidx, chidx, cfg->eaz);
printk("i %d\n", i);
if (i < 0) {
/* Grab failed, because desired channel is in use */
retval = -EBUSY;
goto out;
}
/* All went ok, so update isdninfo */
isdn_slot_set_usage(i, ISDN_USAGE_EXCLUSIVE);
lp->exclusive = 1;
}
lp->pre_device = drvidx;
lp->pre_channel = chidx;
retval = 0;
out:
return retval;
}
/* /*
* Set interface-parameters. * Set interface-parameters.
* Always set all parameters, so the user-level application is responsible * Always set all parameters, so the user-level application is responsible
...@@ -2598,237 +2009,102 @@ isdn_net_newslave(char *parm) ...@@ -2598,237 +2009,102 @@ isdn_net_newslave(char *parm)
* setup first, if only selected parameters are to be changed. * setup first, if only selected parameters are to be changed.
*/ */
int int
isdn_net_setcfg(isdn_net_ioctl_cfg * cfg) isdn_net_setcfg(isdn_net_ioctl_cfg *cfg)
{ {
isdn_net_dev *p = isdn_net_findif(cfg->name); isdn_net_dev *p = isdn_net_findif(cfg->name);
isdn_net_local *lp = &p->local;
ulong features; ulong features;
int i; int i, retval;
int drvidx;
int chidx;
char drvid[25];
#ifdef CONFIG_ISDN_X25
ulong flags;
#endif
if (p) {
isdn_net_local *lp = &p->local;
/* See if any registered driver supports the features we want */ if (!p) {
features = ((1 << cfg->l2_proto) << ISDN_FEATURE_L2_SHIFT) | retval = -ENODEV;
((1 << cfg->l3_proto) << ISDN_FEATURE_L3_SHIFT); goto out;
for (i = 0; i < ISDN_MAX_DRIVERS; i++) }
if (dev->drv[i]) /* See if any registered driver supports the features we want */
if ((dev->drv[i]->interface->features & features) == features) features = ((1 << cfg->l2_proto) << ISDN_FEATURE_L2_SHIFT) |
break; ((1 << cfg->l3_proto) << ISDN_FEATURE_L3_SHIFT);
if (i == ISDN_MAX_DRIVERS) { for (i = 0; i < ISDN_MAX_DRIVERS; i++)
printk(KERN_WARNING "isdn_net: No driver with selected features\n"); if (dev->drv[i] &&
return -ENODEV; (dev->drv[i]->interface->features & features) == features)
}
if (lp->p_encap != cfg->p_encap){
#ifdef CONFIG_ISDN_X25
struct concap_proto * cprot = p -> cprot;
#endif
if (isdn_net_device_started(p)) {
printk(KERN_WARNING "%s: cannot change encap when if is up\n",
lp->name);
return -EBUSY;
}
#ifdef CONFIG_ISDN_X25
/* delete old encapsulation protocol if present ... */
save_flags(flags);
cli(); /* avoid races with incoming events trying to
call cprot->pops methods */
if( cprot && cprot -> pops )
cprot -> pops -> proto_del ( cprot );
p -> cprot = NULL;
lp -> dops = NULL;
restore_flags(flags);
/* ... , prepare for configuration of new one ... */
switch ( cfg -> p_encap ){
case ISDN_NET_ENCAP_X25IFACE:
lp -> dops = &isdn_concap_reliable_dl_dops;
}
/* ... and allocate new one ... */
p -> cprot = isdn_concap_new( cfg -> p_encap );
/* p -> cprot == NULL now if p_encap is not supported
by means of the concap_proto mechanism */
/* the protocol is not configured yet; this will
happen later when isdn_net_reset() is called */
#endif
}
switch ( cfg->p_encap ) {
case ISDN_NET_ENCAP_SYNCPPP:
#ifndef CONFIG_ISDN_PPP
printk(KERN_WARNING "%s: SyncPPP support not configured\n",
lp->name);
return -EINVAL;
#else
p->dev.type = ARPHRD_PPP; /* change ARP type */
p->dev.addr_len = 0;
p->dev.do_ioctl = isdn_ppp_dev_ioctl;
#endif
break;
case ISDN_NET_ENCAP_X25IFACE:
#ifndef CONFIG_ISDN_X25
printk(KERN_WARNING "%s: isdn-x25 support not configured\n",
p->local.name);
return -EINVAL;
#else
p->dev.type = ARPHRD_X25; /* change ARP type */
p->dev.addr_len = 0;
#endif
break;
case ISDN_NET_ENCAP_CISCOHDLCK:
p->dev.do_ioctl = isdn_ciscohdlck_dev_ioctl;
break;
default:
if( cfg->p_encap >= 0 &&
cfg->p_encap <= ISDN_NET_ENCAP_MAX_ENCAP )
break; break;
printk(KERN_WARNING
"%s: encapsulation protocol %d not supported\n",
p->local.name, cfg->p_encap);
return -EINVAL;
}
if (strlen(cfg->drvid)) {
/* A bind has been requested ... */
char *c,
*e;
drvidx = -1;
chidx = -1;
strcpy(drvid, cfg->drvid);
if ((c = strchr(drvid, ','))) {
/* The channel-number is appended to the driver-Id with a comma */
chidx = (int) simple_strtoul(c + 1, &e, 10);
if (e == c)
chidx = -1;
*c = '\0';
}
for (i = 0; i < ISDN_MAX_DRIVERS; i++)
/* Lookup driver-Id in array */
if (!(strcmp(dev->drvid[i], drvid))) {
drvidx = i;
break;
}
if ((drvidx == -1) || (chidx == -1))
/* Either driver-Id or channel-number invalid */
return -ENODEV;
} else {
/* Parameters are valid, so get them */
drvidx = lp->pre_device;
chidx = lp->pre_channel;
}
if (cfg->exclusive > 0) {
unsigned long flags;
/* If binding is exclusive, try to grab the channel */ if (i == ISDN_MAX_DRIVERS) {
save_flags(flags); printk(KERN_WARNING "isdn_net: No driver with selected features\n");
if ((i = isdn_get_free_slot(ISDN_USAGE_NET, retval = -ENODEV;
lp->l2_proto, lp->l3_proto, drvidx, goto out;
chidx, lp->msn)) < 0) { }
/* Grab failed, because desired channel is in use */
lp->exclusive = -1; retval = isdn_net_set_encap(p, cfg);
restore_flags(flags); if (retval)
return -EBUSY; goto out;
}
/* All went ok, so update isdninfo */ retval = isdn_net_bind(p, cfg);
isdn_slot_set_usage(i, ISDN_USAGE_EXCLUSIVE); if (retval)
restore_flags(flags); goto out;
lp->exclusive = i;
} else { strncpy(lp->msn, cfg->eaz, ISDN_MSNLEN-1);
/* Non-exclusive binding or unbind. */ lp->msn[ISDN_MSNLEN-1] = 0;
lp->exclusive = -1; lp->onhtime = cfg->onhtime;
if ((lp->pre_device != -1) && (cfg->exclusive == -1)) { lp->charge = cfg->charge;
isdn_unexclusive_channel(lp->pre_device, lp->pre_channel); lp->l2_proto = cfg->l2_proto;
isdn_free_channel(lp->pre_device, lp->pre_channel, ISDN_USAGE_NET); lp->l3_proto = cfg->l3_proto;
drvidx = -1; lp->cbdelay = cfg->cbdelay * HZ / 5;
chidx = -1; lp->dialmax = cfg->dialmax;
} lp->triggercps = cfg->triggercps;
} lp->slavedelay = cfg->slavedelay * HZ;
strcpy(lp->msn, cfg->eaz); lp->pppbind = cfg->pppbind;
lp->pre_device = drvidx; lp->dialtimeout = cfg->dialtimeout >= 0 ? cfg->dialtimeout * HZ : -1;
lp->pre_channel = chidx; lp->dialwait = cfg->dialwait * HZ;
lp->onhtime = cfg->onhtime; if (cfg->secure)
lp->charge = cfg->charge; lp->flags |= ISDN_NET_SECURE;
lp->l2_proto = cfg->l2_proto; else
lp->l3_proto = cfg->l3_proto; lp->flags &= ~ISDN_NET_SECURE;
lp->cbdelay = cfg->cbdelay * HZ / 5; if (cfg->cbhup)
lp->dialmax = cfg->dialmax; lp->flags |= ISDN_NET_CBHUP;
lp->triggercps = cfg->triggercps; else
lp->slavedelay = cfg->slavedelay * HZ; lp->flags &= ~ISDN_NET_CBHUP;
lp->pppbind = cfg->pppbind; switch (cfg->callback) {
lp->dialtimeout = cfg->dialtimeout >= 0 ? cfg->dialtimeout * HZ : -1; case 0:
lp->dialwait = cfg->dialwait * HZ; lp->flags &= ~(ISDN_NET_CALLBACK | ISDN_NET_CBOUT);
if (cfg->secure) break;
lp->flags |= ISDN_NET_SECURE; case 1:
else lp->flags |= ISDN_NET_CALLBACK;
lp->flags &= ~ISDN_NET_SECURE; lp->flags &= ~ISDN_NET_CBOUT;
if (cfg->cbhup) break;
lp->flags |= ISDN_NET_CBHUP; case 2:
else lp->flags |= ISDN_NET_CBOUT;
lp->flags &= ~ISDN_NET_CBHUP; lp->flags &= ~ISDN_NET_CALLBACK;
switch (cfg->callback) { break;
case 0: }
lp->flags &= ~(ISDN_NET_CALLBACK | ISDN_NET_CBOUT); lp->flags &= ~ISDN_NET_DIALMODE_MASK; /* first all bits off */
break; if (cfg->dialmode && !(cfg->dialmode & ISDN_NET_DIALMODE_MASK)) {
case 1: retval = -EINVAL;
lp->flags |= ISDN_NET_CALLBACK; goto out;
lp->flags &= ~ISDN_NET_CBOUT; }
break;
case 2:
lp->flags |= ISDN_NET_CBOUT;
lp->flags &= ~ISDN_NET_CALLBACK;
break;
}
lp->flags &= ~ISDN_NET_DIALMODE_MASK; /* first all bits off */
if (cfg->dialmode && !(cfg->dialmode & ISDN_NET_DIALMODE_MASK)) {
/* old isdnctrl version, where only 0 or 1 is given */
printk(KERN_WARNING
"Old isdnctrl version detected! Please update.\n");
lp->flags |= ISDN_NET_DM_OFF; /* turn on `off' bit */
}
else {
lp->flags |= cfg->dialmode; /* turn on selected bits */
}
if (lp->flags & ISDN_NET_DM_OFF)
isdn_net_hangup(lp);
if (cfg->chargehup) lp->flags |= cfg->dialmode; /* turn on selected bits */
lp->hupflags |= ISDN_CHARGEHUP; if (lp->flags & ISDN_NET_DM_OFF)
else isdn_net_hangup(lp);
lp->hupflags &= ~ISDN_CHARGEHUP;
if (cfg->ihup) if (cfg->chargehup)
lp->hupflags |= ISDN_INHUP; lp->hupflags |= ISDN_CHARGEHUP;
else else
lp->hupflags &= ~ISDN_INHUP; lp->hupflags &= ~ISDN_CHARGEHUP;
if (cfg->chargeint > 10) {
lp->chargeint = cfg->chargeint * HZ; if (cfg->ihup)
lp->charge_state = ST_CHARGE_HAVE_CINT; lp->hupflags |= ISDN_INHUP;
lp->hupflags |= ISDN_MANCHARGE; else
} lp->hupflags &= ~ISDN_INHUP;
if (cfg->p_encap != lp->p_encap) {
if (cfg->p_encap == ISDN_NET_ENCAP_RAWIP) { if (cfg->chargeint > 10) {
p->dev.hard_header = NULL; lp->chargeint = cfg->chargeint * HZ;
p->dev.hard_header_cache = NULL; lp->charge_state = ST_CHARGE_HAVE_CINT;
p->dev.header_cache_update = NULL; lp->hupflags |= ISDN_MANCHARGE;
p->dev.flags = IFF_NOARP|IFF_POINTOPOINT;
} else {
p->dev.hard_header = isdn_net_header;
if (cfg->p_encap == ISDN_NET_ENCAP_ETHER) {
p->dev.hard_header_cache = lp->org_hhc;
p->dev.header_cache_update = lp->org_hcu;
p->dev.flags = IFF_BROADCAST | IFF_MULTICAST;
} else {
p->dev.hard_header_cache = NULL;
p->dev.header_cache_update = NULL;
p->dev.flags = IFF_NOARP|IFF_POINTOPOINT;
}
}
}
lp->p_encap = cfg->p_encap;
return 0;
} }
return -ENODEV; retval = 0;
out:
return retval;
} }
/* /*
...@@ -2838,52 +2114,52 @@ int ...@@ -2838,52 +2114,52 @@ int
isdn_net_getcfg(isdn_net_ioctl_cfg * cfg) isdn_net_getcfg(isdn_net_ioctl_cfg * cfg)
{ {
isdn_net_dev *p = isdn_net_findif(cfg->name); isdn_net_dev *p = isdn_net_findif(cfg->name);
isdn_net_local *lp = &p->local;
if (!p)
return -ENODEV;
if (p) { strcpy(cfg->eaz, lp->msn);
isdn_net_local *lp = &p->local; cfg->exclusive = lp->exclusive;
if (lp->pre_device >= 0) {
sprintf(cfg->drvid, "%s,%d", dev->drvid[lp->pre_device],
lp->pre_channel);
} else
cfg->drvid[0] = '\0';
cfg->onhtime = lp->onhtime;
cfg->charge = lp->charge;
cfg->l2_proto = lp->l2_proto;
cfg->l3_proto = lp->l3_proto;
cfg->p_encap = lp->p_encap;
cfg->secure = (lp->flags & ISDN_NET_SECURE) ? 1 : 0;
cfg->callback = 0;
if (lp->flags & ISDN_NET_CALLBACK)
cfg->callback = 1;
if (lp->flags & ISDN_NET_CBOUT)
cfg->callback = 2;
cfg->cbhup = (lp->flags & ISDN_NET_CBHUP) ? 1 : 0;
cfg->dialmode = lp->flags & ISDN_NET_DIALMODE_MASK;
cfg->chargehup = (lp->hupflags & 4) ? 1 : 0;
cfg->ihup = (lp->hupflags & 8) ? 1 : 0;
cfg->cbdelay = lp->cbdelay * 5 / HZ;
cfg->dialmax = lp->dialmax;
cfg->triggercps = lp->triggercps;
cfg->slavedelay = lp->slavedelay / HZ;
cfg->chargeint = (lp->hupflags & ISDN_CHARGEHUP) ?
(lp->chargeint / HZ) : 0;
cfg->pppbind = lp->pppbind;
cfg->dialtimeout = lp->dialtimeout >= 0 ? lp->dialtimeout / HZ : -1;
cfg->dialwait = lp->dialwait / HZ;
if (lp->slave)
strcpy(cfg->slave, ((isdn_net_local *) lp->slave->priv)->name);
else
cfg->slave[0] = '\0';
if (lp->master)
strcpy(cfg->master, ((isdn_net_local *) lp->master->priv)->name);
else
cfg->master[0] = '\0';
strcpy(cfg->eaz, lp->msn); return 0;
cfg->exclusive = lp->exclusive;
if (lp->pre_device >= 0) {
sprintf(cfg->drvid, "%s,%d", dev->drvid[lp->pre_device],
lp->pre_channel);
} else
cfg->drvid[0] = '\0';
cfg->onhtime = lp->onhtime;
cfg->charge = lp->charge;
cfg->l2_proto = lp->l2_proto;
cfg->l3_proto = lp->l3_proto;
cfg->p_encap = lp->p_encap;
cfg->secure = (lp->flags & ISDN_NET_SECURE) ? 1 : 0;
cfg->callback = 0;
if (lp->flags & ISDN_NET_CALLBACK)
cfg->callback = 1;
if (lp->flags & ISDN_NET_CBOUT)
cfg->callback = 2;
cfg->cbhup = (lp->flags & ISDN_NET_CBHUP) ? 1 : 0;
cfg->dialmode = lp->flags & ISDN_NET_DIALMODE_MASK;
cfg->chargehup = (lp->hupflags & 4) ? 1 : 0;
cfg->ihup = (lp->hupflags & 8) ? 1 : 0;
cfg->cbdelay = lp->cbdelay * 5 / HZ;
cfg->dialmax = lp->dialmax;
cfg->triggercps = lp->triggercps;
cfg->slavedelay = lp->slavedelay / HZ;
cfg->chargeint = (lp->hupflags & ISDN_CHARGEHUP) ?
(lp->chargeint / HZ) : 0;
cfg->pppbind = lp->pppbind;
cfg->dialtimeout = lp->dialtimeout >= 0 ? lp->dialtimeout / HZ : -1;
cfg->dialwait = lp->dialwait / HZ;
if (lp->slave)
strcpy(cfg->slave, ((isdn_net_local *) lp->slave->priv)->name);
else
cfg->slave[0] = '\0';
if (lp->master)
strcpy(cfg->master, ((isdn_net_local *) lp->master->priv)->name);
else
cfg->master[0] = '\0';
return 0;
}
return -ENODEV;
} }
/* /*
...@@ -3067,14 +2343,12 @@ isdn_net_realrm(isdn_net_dev *p) ...@@ -3067,14 +2343,12 @@ isdn_net_realrm(isdn_net_dev *p)
restore_flags(flags); restore_flags(flags);
return -EBUSY; return -EBUSY;
} }
#ifdef CONFIG_ISDN_X25 isdn_x25_realrm(p);
if( p -> cprot && p -> cprot -> pops )
p -> cprot -> pops -> proto_del ( p -> cprot );
#endif
/* Free all phone-entries */ /* Free all phone-entries */
isdn_net_rmallphone(p); isdn_net_rmallphone(p);
/* If interface is bound exclusive, free channel-usage */ /* If interface is bound exclusive, free channel-usage */
if (p->local.exclusive != -1) if (p->local.exclusive)
isdn_unexclusive_channel(p->local.pre_device, p->local.pre_channel); isdn_unexclusive_channel(p->local.pre_device, p->local.pre_channel);
if (p->local.master) { if (p->local.master) {
/* It's a slave-device, so update master's slave-pointer if necessary */ /* It's a slave-device, so update master's slave-pointer if necessary */
...@@ -3082,8 +2356,6 @@ isdn_net_realrm(isdn_net_dev *p) ...@@ -3082,8 +2356,6 @@ isdn_net_realrm(isdn_net_dev *p)
((isdn_net_local *) (p->local.master->priv))->slave = p->local.slave; ((isdn_net_local *) (p->local.master->priv))->slave = p->local.slave;
} else { } else {
/* Unregister only if it's a master-device */ /* Unregister only if it's a master-device */
p->dev.hard_header_cache = p->local.org_hhc;
p->dev.header_cache_update = p->local.org_hcu;
unregister_netdev(&p->dev); unregister_netdev(&p->dev);
} }
/* Unlink device from chain */ /* Unlink device from chain */
...@@ -3150,3 +2422,193 @@ isdn_net_rmall(void) ...@@ -3150,3 +2422,193 @@ isdn_net_rmall(void)
restore_flags(flags); restore_flags(flags);
return 0; return 0;
} }
// ISDN_NET_ENCAP_IPTYP
// ethernet type field
// ======================================================================
static int
isdn_iptyp_header(struct sk_buff *skb, struct net_device *dev,
unsigned short type, void *daddr, void *saddr,
unsigned plen)
{
put_u16(skb_push(skb, 2), type);
return 2;
}
static void
isdn_iptyp_receive(isdn_net_dev *p, isdn_net_local *olp,
struct sk_buff *skb)
{
isdn_net_local *lp = &p->local;
isdn_net_reset_huptimer(lp, olp);
get_u16(skb->data, &skb->protocol);
skb_pull(skb, 2);
netif_rx(skb);
}
static int
isdn_iptyp_setup(isdn_net_dev *p)
{
p->dev.hard_header = isdn_iptyp_header;
p->dev.hard_header_cache = NULL;
p->dev.header_cache_update = NULL;
p->dev.flags = IFF_NOARP|IFF_POINTOPOINT;
p->local.receive = isdn_iptyp_receive;
p->local.connected = isdn_net_device_wake_queue;
p->local.disconnected = NULL;
return 0;
}
// ISDN_NET_ENCAP_UIHDLC
// HDLC with UI-Frames (for ispa with -h1 option) */
// ======================================================================
static int
isdn_uihdlc_header(struct sk_buff *skb, struct net_device *dev,
unsigned short type, void *daddr, void *saddr,
unsigned plen)
{
put_u16(skb_push(skb, 2), 0x0103);
return 2;
}
static void
isdn_uihdlc_receive(isdn_net_dev *p, isdn_net_local *olp,
struct sk_buff *skb)
{
isdn_net_local *lp = &p->local;
isdn_net_reset_huptimer(lp, olp);
skb_pull(skb, 2);
skb->protocol = htons(ETH_P_IP);
netif_rx(skb);
}
static int
isdn_uihdlc_setup(isdn_net_dev *p)
{
p->dev.hard_header = isdn_uihdlc_header;
p->dev.hard_header_cache = NULL;
p->dev.header_cache_update = NULL;
p->dev.flags = IFF_NOARP|IFF_POINTOPOINT;
p->local.receive = isdn_uihdlc_receive;
p->local.connected = isdn_net_device_wake_queue;
p->local.disconnected = NULL;
return 0;
}
// ISDN_NET_ENCAP_RAWIP
// RAW-IP without MAC-Header
// ======================================================================
static void
isdn_rawip_receive(isdn_net_dev *p, isdn_net_local *olp,
struct sk_buff *skb)
{
isdn_net_local *lp = &p->local;
isdn_net_reset_huptimer(lp, olp);
skb->protocol = htons(ETH_P_IP);
netif_rx(skb);
}
static int
isdn_rawip_setup(isdn_net_dev *p)
{
p->dev.hard_header = NULL;
p->dev.hard_header_cache = NULL;
p->dev.header_cache_update = NULL;
p->dev.flags = IFF_NOARP|IFF_POINTOPOINT;
p->local.receive = isdn_rawip_receive;
p->local.connected = isdn_net_device_wake_queue;
p->local.disconnected = NULL;
return 0;
}
// ISDN_NET_ENCAP_ETHER
// Ethernet over ISDN
// ======================================================================
/* This is simply a copy from std. eth.c EXCEPT we pull ETH_HLEN
* instead of dev->hard_header_len off. This is done because the
* lowlevel-driver has already pulled off its stuff when we get
* here and this routine only gets called with p_encap == ETHER.
* Determine the packet's protocol ID. The rule here is that we
* assume 802.3 if the type field is short enough to be a length.
* This is normal practice and works for any 'now in use' protocol.
* FIXME
*/
static unsigned short
isdn_eth_type_trans(struct sk_buff *skb, struct net_device *dev)
{
struct ethhdr *eth;
unsigned char *rawp;
skb->mac.raw = skb->data;
skb_pull(skb, ETH_HLEN);
eth = skb->mac.ethernet;
if (*eth->h_dest & 1) {
if (memcmp(eth->h_dest, dev->broadcast, ETH_ALEN) == 0)
skb->pkt_type = PACKET_BROADCAST;
else
skb->pkt_type = PACKET_MULTICAST;
}
/*
* This ALLMULTI check should be redundant by 1.4
* so don't forget to remove it.
*/
else if (dev->flags & (IFF_PROMISC /*| IFF_ALLMULTI*/)) {
if (memcmp(eth->h_dest, dev->dev_addr, ETH_ALEN))
skb->pkt_type = PACKET_OTHERHOST;
}
if (ntohs(eth->h_proto) >= 1536)
return eth->h_proto;
rawp = skb->data;
/*
* This is a magic hack to spot IPX packets. Older Novell breaks
* the protocol design and runs IPX over 802.3 without an 802.2 LLC
* layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
* won't work for fault tolerant netware but does for the rest.
*/
if (*(unsigned short *) rawp == 0xFFFF)
return htons(ETH_P_802_3);
/*
* Real 802.2 LLC
*/
return htons(ETH_P_802_2);
}
static void
isdn_ether_receive(isdn_net_dev *p, isdn_net_local *olp,
struct sk_buff *skb)
{
isdn_net_local *lp = &p->local;
isdn_net_reset_huptimer(lp, olp);
skb->protocol = isdn_eth_type_trans(skb, skb->dev);
netif_rx(skb);
}
static int
isdn_ether_setup(isdn_net_dev *p)
{
p->dev.hard_header = eth_header;
p->dev.hard_header_cache = eth_header_cache;
p->dev.header_cache_update = eth_header_cache_update;
p->dev.flags = IFF_BROADCAST | IFF_MULTICAST;
p->local.receive = isdn_ether_receive;
p->local.connected = isdn_net_device_wake_queue;
p->local.disconnected = NULL;
return 0;
}
...@@ -11,7 +11,10 @@ ...@@ -11,7 +11,10 @@
* *
*/ */
/* Definitions for hupflags: */ #include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/isdn.h>
/* Definitions for hupflags: */
#define ISDN_CHARGEHUP 4 /* We want to use the charge mechanism */ #define ISDN_CHARGEHUP 4 /* We want to use the charge mechanism */
#define ISDN_INHUP 8 /* Even if incoming, close after huptimeout */ #define ISDN_INHUP 8 /* Even if incoming, close after huptimeout */
#define ISDN_MANCHARGE 16 /* Charge Interval manually set */ #define ISDN_MANCHARGE 16 /* Charge Interval manually set */
...@@ -51,6 +54,13 @@ extern int isdn_net_dial_req(isdn_net_local *); ...@@ -51,6 +54,13 @@ extern int isdn_net_dial_req(isdn_net_local *);
extern void isdn_net_writebuf_skb(isdn_net_local *lp, struct sk_buff *skb); extern void isdn_net_writebuf_skb(isdn_net_local *lp, struct sk_buff *skb);
extern void isdn_net_write_super(isdn_net_local *lp, struct sk_buff *skb); extern void isdn_net_write_super(isdn_net_local *lp, struct sk_buff *skb);
static inline void
isdn_net_reset_huptimer(isdn_net_local *lp, isdn_net_local *olp)
{
olp->huptimer = 0;
lp->huptimer = 0;
}
#define ISDN_NET_MAX_QUEUE_LENGTH 2 #define ISDN_NET_MAX_QUEUE_LENGTH 2
/* /*
...@@ -135,6 +145,18 @@ static __inline__ void isdn_net_rm_from_bundle(isdn_net_local *lp) ...@@ -135,6 +145,18 @@ static __inline__ void isdn_net_rm_from_bundle(isdn_net_local *lp)
spin_unlock_irqrestore(&master_lp->netdev->queue_lock, flags); spin_unlock_irqrestore(&master_lp->netdev->queue_lock, flags);
} }
/*
* wake up the network -> net_device queue.
* For slaves, wake the corresponding master interface.
*/
static inline void isdn_net_device_wake_queue(isdn_net_local *lp)
{
if (lp->master)
netif_wake_queue(lp->master);
else
netif_wake_queue(&lp->netdev->dev);
}
static inline int static inline int
put_u8(unsigned char *p, u8 x) put_u8(unsigned char *p, u8 x)
{ {
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/ppp-comp.h> #include <linux/ppp-comp.h>
#include <linux/if_arp.h>
#include "isdn_common.h" #include "isdn_common.h"
#include "isdn_ppp.h" #include "isdn_ppp.h"
...@@ -98,7 +99,7 @@ isdn_ppp_frame_log(char *info, char *data, int len, int maxlen,int unit,int slot ...@@ -98,7 +99,7 @@ isdn_ppp_frame_log(char *info, char *data, int len, int maxlen,int unit,int slot
* note: it can happen, that we hangup/free the master before the slaves * note: it can happen, that we hangup/free the master before the slaves
* in this case we bind another lp to the master device * in this case we bind another lp to the master device
*/ */
int static void
isdn_ppp_free(isdn_net_local * lp) isdn_ppp_free(isdn_net_local * lp)
{ {
unsigned long flags; unsigned long flags;
...@@ -107,7 +108,7 @@ isdn_ppp_free(isdn_net_local * lp) ...@@ -107,7 +108,7 @@ isdn_ppp_free(isdn_net_local * lp)
if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS) { if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS) {
printk(KERN_ERR "%s: ppp_slot(%d) out of range\n", printk(KERN_ERR "%s: ppp_slot(%d) out of range\n",
__FUNCTION__ , lp->ppp_slot); __FUNCTION__ , lp->ppp_slot);
return 0; return;
} }
save_flags(flags); save_flags(flags);
...@@ -128,7 +129,7 @@ isdn_ppp_free(isdn_net_local * lp) ...@@ -128,7 +129,7 @@ isdn_ppp_free(isdn_net_local * lp)
printk(KERN_ERR "%s: ppp_slot(%d) now invalid\n", printk(KERN_ERR "%s: ppp_slot(%d) now invalid\n",
__FUNCTION__ , lp->ppp_slot); __FUNCTION__ , lp->ppp_slot);
restore_flags(flags); restore_flags(flags);
return 0; return;
} }
is = ippp_table[lp->ppp_slot]; is = ippp_table[lp->ppp_slot];
if ((is->state & IPPP_CONNECT)) if ((is->state & IPPP_CONNECT))
...@@ -143,7 +144,7 @@ isdn_ppp_free(isdn_net_local * lp) ...@@ -143,7 +144,7 @@ isdn_ppp_free(isdn_net_local * lp)
lp->ppp_slot = -1; /* is this OK ?? */ lp->ppp_slot = -1; /* is this OK ?? */
restore_flags(flags); restore_flags(flags);
return 0; return;
} }
/* /*
...@@ -223,7 +224,7 @@ isdn_ppp_bind(isdn_net_local * lp) ...@@ -223,7 +224,7 @@ isdn_ppp_bind(isdn_net_local * lp)
* (wakes up daemon after B-channel connect) * (wakes up daemon after B-channel connect)
*/ */
void static void
isdn_ppp_wakeup_daemon(isdn_net_local * lp) isdn_ppp_wakeup_daemon(isdn_net_local * lp)
{ {
if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) { if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
...@@ -961,14 +962,19 @@ static int isdn_ppp_strip_proto(struct sk_buff *skb) ...@@ -961,14 +962,19 @@ static int isdn_ppp_strip_proto(struct sk_buff *skb)
/* /*
* handler for incoming packets on a syncPPP interface * handler for incoming packets on a syncPPP interface
*/ */
void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb) static void isdn_ppp_receive(isdn_net_dev *net_dev, isdn_net_local *lp,
struct sk_buff *skb)
{ {
struct ippp_struct *is; struct ippp_struct *is;
int slot; int slot;
int proto; int proto;
if (net_dev->local.master) /*
BUG(); // we're called with the master device always * If encapsulation is syncppp, don't reset
* huptimer on LCP packets.
*/
if (PPP_PROTOCOL(skb->data) != PPP_LCP)
isdn_net_reset_huptimer(&net_dev->local,lp);
slot = lp->ppp_slot; slot = lp->ppp_slot;
if (slot < 0 || slot > ISDN_MAX_CHANNELS) { if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
...@@ -2893,3 +2899,35 @@ static int isdn_ppp_set_compressor(struct ippp_struct *is, struct isdn_ppp_comp_ ...@@ -2893,3 +2899,35 @@ static int isdn_ppp_set_compressor(struct ippp_struct *is, struct isdn_ppp_comp_
} }
return -EINVAL; return -EINVAL;
} }
// ISDN_NET_ENCAP_SYNCPPP
// ======================================================================
static int
isdn_ppp_header(struct sk_buff *skb, struct net_device *dev,
unsigned short type, void *daddr, void *saddr,
unsigned plen)
{
skb_push(skb, IPPP_MAX_HEADER);
return IPPP_MAX_HEADER;
}
int
isdn_ppp_setup(isdn_net_dev *p)
{
p->dev.hard_header = isdn_ppp_header;
p->dev.hard_header_cache = NULL;
p->dev.header_cache_update = NULL;
p->dev.flags = IFF_NOARP|IFF_POINTOPOINT;
p->dev.type = ARPHRD_PPP; /* change ARP type */
p->dev.addr_len = 0;
p->dev.do_ioctl = isdn_ppp_dev_ioctl;
p->local.receive = isdn_ppp_receive;
p->local.connected = isdn_ppp_wakeup_daemon;
p->local.disconnected = isdn_ppp_free;
return 0;
}
...@@ -16,16 +16,37 @@ extern struct file_operations isdn_ppp_fops; ...@@ -16,16 +16,37 @@ extern struct file_operations isdn_ppp_fops;
extern int isdn_ppp_init(void); extern int isdn_ppp_init(void);
extern void isdn_ppp_cleanup(void); extern void isdn_ppp_cleanup(void);
extern int isdn_ppp_free(isdn_net_local *);
extern int isdn_ppp_bind(isdn_net_local *);
extern int isdn_ppp_xmit(struct sk_buff *, struct net_device *);
extern void isdn_ppp_receive(isdn_net_dev *, isdn_net_local *, struct sk_buff *);
extern int isdn_ppp_dev_ioctl(struct net_device *, struct ifreq *, int);
extern int isdn_ppp_dial_slave(char *); extern int isdn_ppp_dial_slave(char *);
extern void isdn_ppp_wakeup_daemon(isdn_net_local *); extern int isdn_ppp_hangup_slave(char *);
extern int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc); #ifdef CONFIG_ISDN_PPP
extern int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *ipc);
int isdn_ppp_setup(isdn_net_dev *p);
int isdn_ppp_bind(isdn_net_local *);
int isdn_ppp_xmit(struct sk_buff *, struct net_device *);
#else
static inline int
isdn_ppp_setup(isdn_net_dev *p)
{
printk(KERN_WARNING "ISDN: SyncPPP support not configured\n");
return -EINVAL;
}
static inline int
isdn_ppp_bind(isdn_net_local *)
{
return 0;
}
static inline int
isdn_ppp_xmit(struct sk_buff *, struct net_device *);
{
return 0;
}
#endif
#define IPPP_OPEN 0x01 #define IPPP_OPEN 0x01
#define IPPP_CONNECT 0x02 #define IPPP_CONNECT 0x02
......
...@@ -75,7 +75,6 @@ ...@@ -75,7 +75,6 @@
#define ISDN_NET_ENCAP_UIHDLC 5 #define ISDN_NET_ENCAP_UIHDLC 5
#define ISDN_NET_ENCAP_CISCOHDLCK 6 /* With SLARP and keepalive */ #define ISDN_NET_ENCAP_CISCOHDLCK 6 /* With SLARP and keepalive */
#define ISDN_NET_ENCAP_X25IFACE 7 /* Documentation/networking/x25-iface.txt*/ #define ISDN_NET_ENCAP_X25IFACE 7 /* Documentation/networking/x25-iface.txt*/
#define ISDN_NET_ENCAP_MAX_ENCAP ISDN_NET_ENCAP_X25IFACE
/* Facility which currently uses an ISDN-channel */ /* Facility which currently uses an ISDN-channel */
#define ISDN_USAGE_NONE 0 #define ISDN_USAGE_NONE 0
...@@ -353,13 +352,6 @@ typedef struct isdn_net_local_s { ...@@ -353,13 +352,6 @@ typedef struct isdn_net_local_s {
/* a particular channel (including */ /* a particular channel (including */
/* the frame_cnt */ /* the frame_cnt */
int (*org_hhc)(
struct neighbour *neigh,
struct hh_cache *hh);
/* Ptr to orig. header_cache_update */
void (*org_hcu)(struct hh_cache *,
struct net_device *,
unsigned char *);
int pppbind; /* ippp device for bindings */ int pppbind; /* ippp device for bindings */
int dialtimeout; /* How long shall we try on dialing? (jiffies) */ int dialtimeout; /* How long shall we try on dialing? (jiffies) */
int dialwait; /* How long shall we wait after failed attempt? (jiffies) */ int dialwait; /* How long shall we wait after failed attempt? (jiffies) */
...@@ -379,6 +371,11 @@ typedef struct isdn_net_local_s { ...@@ -379,6 +371,11 @@ typedef struct isdn_net_local_s {
char cisco_debserint; /* debugging flag of cisco hdlc with slarp */ char cisco_debserint; /* debugging flag of cisco hdlc with slarp */
struct timer_list cisco_timer; struct timer_list cisco_timer;
struct tq_struct tqueue; struct tq_struct tqueue;
void (*receive)(struct isdn_net_dev_s *p,
struct isdn_net_local_s *olp,
struct sk_buff *skb);
void (*connected)(struct isdn_net_local_s *lp);
void (*disconnected)(struct isdn_net_local_s *lp);
} isdn_net_local; } isdn_net_local;
/* the interface itself */ /* the interface itself */
......
...@@ -138,8 +138,6 @@ struct isdn_ppp_compressor { ...@@ -138,8 +138,6 @@ struct isdn_ppp_compressor {
extern int isdn_ppp_register_compressor(struct isdn_ppp_compressor *); extern int isdn_ppp_register_compressor(struct isdn_ppp_compressor *);
extern int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *); extern int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *);
extern int isdn_ppp_dial_slave(char *);
extern int isdn_ppp_hangup_slave(char *);
typedef struct { typedef struct {
unsigned long seqerrs; unsigned long seqerrs;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment