Commit b2b109e8 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 2b9fa51a 0066476b
......@@ -164,7 +164,7 @@ isdn_net_ciscohdlck_slarp_send_keepalive(unsigned long data)
p += put_u32(p, lp->cisco_yourseq);
p += put_u16(p, 0xffff); // reliablity, always 0xffff
isdn_net_write_super(lp, skb);
isdn_net_write_super(idev, skb);
lp->cisco_timer.expires = jiffies + lp->cisco_keepalive_period * HZ;
......@@ -174,6 +174,7 @@ isdn_net_ciscohdlck_slarp_send_keepalive(unsigned long data)
static void
isdn_net_ciscohdlck_slarp_send_request(isdn_net_local *lp)
{
isdn_net_dev *idev = lp->netdev;
struct sk_buff *skb;
unsigned char *p;
......@@ -194,7 +195,7 @@ isdn_net_ciscohdlck_slarp_send_request(isdn_net_local *lp)
p += put_u32(p, 0); // netmask
p += put_u16(p, 0); // unused
isdn_net_write_super(lp, skb);
isdn_net_write_super(idev, skb);
}
static void
......@@ -218,7 +219,7 @@ isdn_ciscohdlck_connected(isdn_net_local *lp)
lp->cisco_timer.expires = jiffies + lp->cisco_keepalive_period * HZ;
add_timer(&lp->cisco_timer);
}
isdn_net_device_wake_queue(lp);
isdn_net_dev_wake_queue(lp->netdev);
}
static void
......@@ -232,13 +233,14 @@ isdn_ciscohdlck_disconnected(isdn_net_local *lp)
static void
isdn_net_ciscohdlck_slarp_send_reply(isdn_net_local *lp)
{
isdn_net_dev *idev = lp->netdev;
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) {
if ((in_dev = lp->dev.ip_ptr) != NULL) {
/* take primary(first) address of interface */
struct in_ifaddr *ifa = in_dev->ifa_list;
if (ifa != NULL) {
......@@ -265,7 +267,7 @@ isdn_net_ciscohdlck_slarp_send_reply(isdn_net_local *lp)
p += put_u32(p, mask); // netmask
p += put_u16(p, 0); // unused
isdn_net_write_super(lp, skb);
isdn_net_write_super(idev, skb);
}
static void
......@@ -335,10 +337,9 @@ isdn_net_ciscohdlck_slarp_in(isdn_net_local *lp, struct sk_buff *skb)
}
static void
isdn_ciscohdlck_receive(isdn_net_dev *idev, isdn_net_local *olp,
isdn_ciscohdlck_receive(isdn_net_local *lp, isdn_net_dev *idev,
struct sk_buff *skb)
{
isdn_net_local *lp = &idev->local;
unsigned char *p;
u8 addr;
u8 ctrl;
......@@ -371,7 +372,7 @@ isdn_ciscohdlck_receive(isdn_net_dev *idev, isdn_net_local *olp,
goto out_free;
default:
/* no special cisco protocol */
isdn_net_reset_huptimer(idev, olp->netdev);
isdn_net_reset_huptimer(lp, idev);
skb->protocol = htons(type);
netif_rx(skb);
return;
......
......@@ -92,15 +92,16 @@ LIST_HEAD(isdn_net_devs); /* Linked list of isdn_net_dev's */
* Find out if the netdevice has been ifup-ed yet.
* For slaves, look at the corresponding master.
*/
static __inline__ int isdn_net_device_started(isdn_net_dev *n)
static inline int
isdn_net_device_started(isdn_net_dev *idev)
{
isdn_net_local *lp = &n->local;
struct net_device *dev;
if (lp->master)
dev = lp->master;
if (idev->master)
dev = &idev->master->dev;
else
dev = &n->dev;
dev = &idev->local.dev;
return netif_running(dev);
}
......@@ -108,12 +109,13 @@ static __inline__ int isdn_net_device_started(isdn_net_dev *n)
* stop the network -> net_device queue.
* For slaves, stop the corresponding master interface.
*/
static __inline__ void isdn_net_device_stop_queue(isdn_net_local *lp)
static inline void
isdn_net_dev_stop_queue(isdn_net_dev *idev)
{
if (lp->master)
netif_stop_queue(lp->master);
if (idev->master)
netif_stop_queue(&idev->master->dev);
else
netif_stop_queue(&lp->netdev->dev);
netif_stop_queue(&idev->local.dev);
}
/*
......@@ -121,57 +123,61 @@ static __inline__ void isdn_net_device_stop_queue(isdn_net_local *lp)
* master or slave) is busy. It's busy iff all (master and slave)
* queues are busy
*/
static __inline__ int isdn_net_device_busy(isdn_net_local *lp)
static inline int
isdn_net_device_busy(isdn_net_dev *idev)
{
isdn_net_local *nlp;
isdn_net_dev *nd;
isdn_net_dev *ndev;
isdn_net_local *mlp;
unsigned long flags;
if (!isdn_net_lp_busy(lp))
if (!isdn_net_dev_busy(idev))
return 0;
if (lp->master)
nd = ((isdn_net_local *) lp->master->priv)->netdev;
if (idev->master)
mlp = idev->master;
else
nd = lp->netdev;
mlp = &idev->local;
spin_lock_irqsave(&nd->queue_lock, flags);
nlp = lp->next;
while (nlp != lp) {
if (!isdn_net_lp_busy(nlp)) {
spin_unlock_irqrestore(&nd->queue_lock, flags);
spin_lock_irqsave(&mlp->queue_lock, flags);
ndev = idev->next;
while (ndev != idev) {
if (!isdn_net_dev_busy(ndev)) {
spin_unlock_irqrestore(&mlp->queue_lock, flags);
return 0;
}
nlp = nlp->next;
ndev = ndev->next;
}
spin_unlock_irqrestore(&nd->queue_lock, flags);
spin_unlock_irqrestore(&mlp->queue_lock, flags);
return 1;
}
static __inline__ void isdn_net_inc_frame_cnt(isdn_net_local *lp)
static inline
void isdn_net_inc_frame_cnt(isdn_net_dev *idev)
{
atomic_inc(&lp->frame_cnt);
if (isdn_net_device_busy(lp))
isdn_net_device_stop_queue(lp);
atomic_inc(&idev->frame_cnt);
if (isdn_net_device_busy(idev))
isdn_net_dev_stop_queue(idev);
}
static __inline__ void isdn_net_dec_frame_cnt(isdn_net_local *lp)
static inline void
isdn_net_dec_frame_cnt(isdn_net_dev *idev)
{
atomic_dec(&lp->frame_cnt);
atomic_dec(&idev->frame_cnt);
if (!(isdn_net_device_busy(lp))) {
if (!skb_queue_empty(&lp->super_tx_queue)) {
queue_task(&lp->tqueue, &tq_immediate);
if (!(isdn_net_device_busy(idev))) {
if (!skb_queue_empty(&idev->super_tx_queue)) {
queue_task(&idev->tqueue, &tq_immediate);
mark_bh(IMMEDIATE_BH);
} else {
isdn_net_device_wake_queue(lp);
isdn_net_dev_wake_queue(idev);
}
}
}
static __inline__ void isdn_net_zero_frame_cnt(isdn_net_local *lp)
static inline
void isdn_net_zero_frame_cnt(isdn_net_dev *idev)
{
atomic_set(&lp->frame_cnt, 0);
atomic_set(&idev->frame_cnt, 0);
}
/* For 2.2.x we leave the transmitter busy timeout at 2 secs, just
......@@ -208,7 +214,7 @@ int isdn_net_online(isdn_net_dev *idev)
/* Prototypes */
static int isdn_net_force_dial_lp(isdn_net_local *);
static int isdn_net_force_dial_idev(isdn_net_dev *);
static int isdn_net_start_xmit(struct sk_buff *, struct net_device *);
static void do_dialout(isdn_net_local *lp);
static int isdn_net_set_encap(isdn_net_dev *p, int encap);
......@@ -269,14 +275,14 @@ isdn_net_unbind_channel(isdn_net_local * lp)
if (lp->ops->unbind)
lp->ops->unbind(lp);
skb_queue_purge(&lp->super_tx_queue);
skb_queue_purge(&idev->super_tx_queue);
if (!lp->master) { /* reset only master device */
if (!idev->master) { /* reset only master device */
/* Moral equivalent of dev_purge_queues():
BEWARE! This chunk of code cannot be called from hardware
interrupt handler. I hope it is true. --ANK
*/
qdisc_reset(lp->netdev->dev.qdisc);
qdisc_reset(lp->dev.qdisc);
}
idev->dialstate = ST_NULL;
if (idev->isdn_slot >= 0) {
......@@ -376,23 +382,23 @@ static void isdn_net_hup_timer(unsigned long data)
mod_timer(&idev->hup_timer, idev->hup_timer.expires + HZ);
}
static void isdn_net_lp_disconnected(isdn_net_local *lp)
static void isdn_net_lp_disconnected(isdn_net_dev *idev)
{
isdn_net_rm_from_bundle(lp);
isdn_net_rm_from_bundle(idev);
}
static void isdn_net_connected(isdn_net_local *lp)
static void isdn_net_connected(isdn_net_dev *idev)
{
isdn_net_dev *idev = lp->netdev;
isdn_net_local *lp = &idev->local;
idev->dialstate = ST_ACTIVE;
idev->hup_timer.expires = jiffies + HZ;
add_timer(&idev->hup_timer);
if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP) {
if (lp->master) { /* is lp a slave? */
isdn_net_dev *nd = ((isdn_net_local *)lp->master->priv)->netdev;
isdn_net_add_to_bundle(nd, lp);
if (idev->master) { /* is lp a slave? */
isdn_net_local *mlp = idev->master;
isdn_net_add_to_bundle(mlp, idev);
}
}
printk(KERN_INFO "isdn_net: %s connected\n", idev->name);
......@@ -412,7 +418,7 @@ static void isdn_net_connected(isdn_net_local *lp)
if (lp->ops->connected)
lp->ops->connected(lp);
else
isdn_net_device_wake_queue(lp);
isdn_net_dev_wake_queue(idev);
}
/*
......@@ -562,7 +568,7 @@ isdn_net_handle_event(isdn_net_local *lp, int pr, void *arg)
switch (pr) {
case ISDN_STAT_BSENT:
/* A packet has successfully been sent out */
isdn_net_dec_frame_cnt(lp);
isdn_net_dec_frame_cnt(idev);
lp->stats.tx_packets++;
lp->stats.tx_bytes += c->parm.length;
return 1;
......@@ -570,7 +576,7 @@ isdn_net_handle_event(isdn_net_local *lp, int pr, void *arg)
if (lp->ops->disconnected)
lp->ops->disconnected(lp);
isdn_net_lp_disconnected(lp);
isdn_net_lp_disconnected(idev);
isdn_slot_all_eaz(idev->isdn_slot);
printk(KERN_INFO "%s: remote hangup\n", idev->name);
printk(KERN_INFO "%s: Chargesum is %d\n", idev->name,
......@@ -637,7 +643,7 @@ isdn_net_handle_event(isdn_net_local *lp, int pr, void *arg)
case ISDN_STAT_BCONN:
del_timer(&idev->dial_timer);
isdn_slot_set_usage(idev->isdn_slot, isdn_slot_usage(idev->isdn_slot) | ISDN_USAGE_OUTGOING);
isdn_net_connected(lp);
isdn_net_connected(idev);
return 1;
case ISDN_STAT_DHUP:
del_timer(&idev->dial_timer);
......@@ -676,7 +682,7 @@ isdn_net_handle_event(isdn_net_local *lp, int pr, void *arg)
case ISDN_STAT_BCONN:
del_timer(&idev->dial_timer);
isdn_slot_set_rx_netdev(idev->isdn_slot, idev);
isdn_net_connected(lp);
isdn_net_connected(idev);
return 1;
case ISDN_STAT_DHUP:
del_timer(&idev->dial_timer);
......@@ -716,21 +722,20 @@ isdn_net_hangup(isdn_net_dev *idev)
return;
// FIXME ugly and recursive
if (lp->slave != NULL) {
isdn_net_local *slp = (isdn_net_local *)lp->slave->priv;
isdn_net_dev *sidev = slp->netdev;
if (isdn_net_bound(sidev)) {
if (idev->slave) {
isdn_net_dev *sdev = idev->slave;
if (isdn_net_bound(sdev)) {
printk(KERN_INFO
"isdn_net: hang up slave %s before %s\n",
sidev->name, idev->name);
isdn_net_hangup(sidev);
sdev->name, idev->name);
isdn_net_hangup(sdev);
}
}
printk(KERN_INFO "isdn_net: local hangup %s\n", idev->name);
if (lp->ops->disconnected)
lp->ops->disconnected(lp);
isdn_net_lp_disconnected(lp);
isdn_net_lp_disconnected(idev);
isdn_slot_command(idev->isdn_slot, ISDN_CMD_HANGUP, &cmd);
printk(KERN_INFO "%s: Chargesum is %d\n", idev->name, idev->charge);
......@@ -846,24 +851,25 @@ isdn_net_log_skb(struct sk_buff * skb, isdn_net_local * lp)
* not received from the network layer, but e.g. frames from ipppd, CCP
* reset frames etc.
*/
void isdn_net_write_super(isdn_net_local *lp, struct sk_buff *skb)
void
isdn_net_write_super(isdn_net_dev *idev, struct sk_buff *skb)
{
if (in_irq()) {
// we can't grab the lock from irq context,
// so we just queue the packet
skb_queue_tail(&lp->super_tx_queue, skb);
queue_task(&lp->tqueue, &tq_immediate);
skb_queue_tail(&idev->super_tx_queue, skb);
queue_task(&idev->tqueue, &tq_immediate);
mark_bh(IMMEDIATE_BH);
return;
}
spin_lock_bh(&lp->xmit_lock);
if (!isdn_net_lp_busy(lp)) {
isdn_net_writebuf_skb(lp, skb);
spin_lock_bh(&idev->xmit_lock);
if (!isdn_net_dev_busy(idev)) {
isdn_net_writebuf_skb(idev, skb);
} else {
skb_queue_tail(&lp->super_tx_queue, skb);
skb_queue_tail(&idev->super_tx_queue, skb);
}
spin_unlock_bh(&lp->xmit_lock);
spin_unlock_bh(&idev->xmit_lock);
}
/*
......@@ -871,32 +877,32 @@ void isdn_net_write_super(isdn_net_local *lp, struct sk_buff *skb)
*/
static void isdn_net_softint(void *private)
{
isdn_net_local *lp = private;
isdn_net_dev *idev = private;
struct sk_buff *skb;
spin_lock_bh(&lp->xmit_lock);
while (!isdn_net_lp_busy(lp)) {
skb = skb_dequeue(&lp->super_tx_queue);
spin_lock_bh(&idev->xmit_lock);
while (!isdn_net_dev_busy(idev)) {
skb = skb_dequeue(&idev->super_tx_queue);
if (!skb)
break;
isdn_net_writebuf_skb(lp, skb);
isdn_net_writebuf_skb(idev, skb);
}
spin_unlock_bh(&lp->xmit_lock);
spin_unlock_bh(&idev->xmit_lock);
}
/*
* all frames sent from the (net) LL to a HL driver should go via this function
* it's serialized by the caller holding the lp->xmit_lock spinlock
* it's serialized by the caller holding the idev->xmit_lock spinlock
*/
void isdn_net_writebuf_skb(isdn_net_local *lp, struct sk_buff *skb)
void isdn_net_writebuf_skb(isdn_net_dev *idev, struct sk_buff *skb)
{
isdn_net_dev *idev = lp->netdev;
isdn_net_local *lp = &idev->local;
int ret;
int len = skb->len; /* save len */
/* before obtaining the lock the caller should have checked that
the lp isn't busy */
if (isdn_net_lp_busy(lp)) {
if (isdn_net_dev_busy(idev)) {
isdn_BUG();
goto error;
}
......@@ -913,7 +919,7 @@ void isdn_net_writebuf_skb(isdn_net_local *lp, struct sk_buff *skb)
}
idev->transcount += len;
isdn_net_inc_frame_cnt(lp);
isdn_net_inc_frame_cnt(idev);
return;
error:
......@@ -936,34 +942,29 @@ void isdn_net_writebuf_skb(isdn_net_local *lp, struct sk_buff *skb)
static int
isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb)
{
isdn_net_dev *nd, *idev;
isdn_net_local *slp;
isdn_net_local *mlp;
isdn_net_dev *sdev;
isdn_net_local *lp = ndev->priv;
isdn_net_dev *idev = lp->netdev;
int retv = 0;
if (lp->master) {
isdn_BUG();
dev_kfree_skb(skb);
return 0;
}
/* For the other encaps the header has already been built */
if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) {
return isdn_ppp_xmit(skb, ndev);
}
nd = ((isdn_net_local *) ndev->priv)->netdev;
lp = isdn_net_get_locked_lp(nd);
if (!lp) {
mlp = ndev->priv;
idev = isdn_net_get_locked_dev(mlp);
if (!idev) {
printk(KERN_WARNING "%s: all channels busy - requeuing!\n", ndev->name);
return 1;
}
idev = lp->netdev;
/* we have our lp locked from now on */
/* we have our idev locked from now on */
lp = &idev->local;
/* Reset hangup-timeout */
idev->huptimer = 0; // FIXME?
isdn_net_writebuf_skb(lp, skb);
spin_unlock_bh(&lp->xmit_lock);
isdn_net_writebuf_skb(idev, skb);
spin_unlock_bh(&idev->xmit_lock);
/* the following stuff is here for backwards compatibility.
* in future, start-up and hangup of slaves (based on current load)
......@@ -979,27 +980,27 @@ isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb)
printk(KERN_DEBUG "%s: %d bogocps\n", idev->name, idev->cps);
if (idev->cps > lp->triggercps) {
if (lp->slave) {
if (!lp->sqfull) {
if (idev->slave) {
if (!idev->sqfull) {
/* First time overload: set timestamp only */
lp->sqfull = 1;
lp->sqfull_stamp = jiffies;
idev->sqfull = 1;
idev->sqfull_stamp = jiffies;
} else {
/* subsequent overload: if slavedelay exceeded, start dialing */
if (time_after(jiffies, lp->sqfull_stamp + lp->slavedelay)) {
slp = lp->slave->priv;
if (!isdn_net_bound(slp->netdev)) {
isdn_net_force_dial_lp((isdn_net_local *) lp->slave->priv);
if (time_after(jiffies, idev->sqfull_stamp + lp->slavedelay)) {
sdev = idev->slave;
if (!isdn_net_bound(sdev)) {
isdn_net_force_dial_idev(sdev);
}
}
}
}
} else {
if (lp->sqfull && time_after(jiffies, lp->sqfull_stamp + lp->slavedelay + (10 * HZ))) {
lp->sqfull = 0;
if (idev->sqfull && time_after(jiffies, idev->sqfull_stamp + lp->slavedelay + 10 * HZ)) {
idev->sqfull = 0;
}
/* this is a hack to allow auto-hangup for slaves on moderate loads */
nd->queue = &nd->local;
mlp->queue = mlp->netdev;
}
return retv;
......@@ -1053,7 +1054,7 @@ isdn_net_autodial(struct sk_buff *skb, struct net_device *ndev)
idev->dialwait_timer = 0;
}
if (isdn_net_force_dial_lp(lp) < 0)
if (isdn_net_force_dial_idev(idev) < 0)
goto discard;
/* Log packet, which triggered dialing */
......@@ -1113,18 +1114,19 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
static int
isdn_net_close(struct net_device *dev)
{
struct net_device *p;
isdn_net_local *lp = dev->priv;
isdn_net_dev *idev = lp->netdev;
isdn_net_dev *sdev;
if (lp->ops->close)
lp->ops->close(lp);
netif_stop_queue(dev);
for (p = lp->slave; p; p = ((isdn_net_local *) p->priv)->slave)
isdn_net_hangup(p->priv);
for (sdev = idev->slave; sdev; sdev = sdev->slave)
isdn_net_hangup(sdev);
isdn_net_hangup(dev->priv);
isdn_net_hangup(idev);
isdn_MOD_DEC_USE_COUNT();
return 0;
}
......@@ -1143,31 +1145,29 @@ isdn_net_get_stats(struct net_device *dev)
* Got a packet from ISDN-Channel.
*/
static void
isdn_net_receive(struct net_device *ndev, struct sk_buff *skb)
isdn_net_receive(isdn_net_dev *idev, struct sk_buff *skb)
{
isdn_net_local *lp = (isdn_net_local *) ndev->priv;
isdn_net_dev *idev = lp->netdev;
isdn_net_local *olp = lp; /* original 'lp' */
isdn_net_local *lp;
struct net_device *ndev;
idev->transcount += skb->len;
lp->stats.rx_packets++;
lp->stats.rx_bytes += skb->len;
if (lp->master) {
if (idev->master) {
/* Bundling: If device is a slave-device, deliver to master, also
* handle master's statistics and hangup-timeout
*/
ndev = lp->master;
lp = (isdn_net_local *) ndev->priv;
lp->stats.rx_packets++;
lp->stats.rx_bytes += skb->len;
ndev = &idev->master->dev;
} else {
ndev = &idev->local.dev;
}
lp = ndev->priv;
lp->stats.rx_packets++;
lp->stats.rx_bytes += skb->len;
skb->dev = ndev;
skb->pkt_type = PACKET_HOST;
skb->mac.raw = skb->data;
isdn_dumppkt("R:", skb->data, skb->len, 40);
lp->ops->receive(lp->netdev, olp, skb);
lp->ops->receive(lp, idev, skb);
}
/*
......@@ -1186,7 +1186,7 @@ isdn_net_rcv_skb(int idx, struct sk_buff *skb)
if (!isdn_net_online(idev))
return 0;
isdn_net_receive(&idev->dev, skb);
isdn_net_receive(idev, skb);
return 0;
}
......@@ -1394,23 +1394,23 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
/* Interface is up, now see if it's a slave. If so, see if
* it's master and parent slave is online. If not, reject the call.
*/
if (lp->master) {
isdn_net_local *mlp = (isdn_net_local *) lp->master->priv;
if (idev->master) {
isdn_net_dev *pdev = idev->master->netdev;
printk(KERN_DEBUG "ICALLslv: %s\n", idev->name);
printk(KERN_DEBUG "master=%s\n", mlp->netdev->name);
if (isdn_net_bound(mlp->netdev)) {
printk(KERN_DEBUG "master=%s\n", pdev->name);
if (isdn_net_bound(pdev)) {
printk(KERN_DEBUG "master online\n");
/* Master is online, find parent-slave (master if first slave) */
while (mlp->slave) {
if ((isdn_net_local *) mlp->slave->priv == lp)
while (pdev->slave) {
if (pdev->slave == idev)
break;
mlp = (isdn_net_local *) mlp->slave->priv;
pdev = pdev->slave;
}
} else
printk(KERN_DEBUG "master offline\n");
/* Found parent, if it's offline iterate next device */
printk(KERN_DEBUG "mlpf: %d\n", isdn_net_bound(mlp->netdev));
if (!isdn_net_bound(mlp->netdev)) {
printk(KERN_DEBUG "mlpf: %d\n", isdn_net_bound(pdev));
if (!isdn_net_bound(pdev)) {
continue;
}
}
......@@ -1474,11 +1474,11 @@ isdn_net_findif(char *name)
* from isdn_net_start_xmit().
*/
static int
isdn_net_force_dial_lp(isdn_net_local *lp)
isdn_net_force_dial_idev(isdn_net_dev *idev)
{
isdn_net_dev *idev = lp->netdev;
int slot;
unsigned long flags;
isdn_net_local *lp = &idev->local;
if (isdn_net_bound(idev))
return -EBUSY;
......@@ -1515,12 +1515,13 @@ isdn_net_force_dial_lp(isdn_net_local *lp)
* themselves.
*/
int
isdn_net_dial_req(isdn_net_local * lp)
isdn_net_dial_req(isdn_net_dev *idev)
{
isdn_net_local *lp = &idev->local;
/* is there a better error code? */
if (!(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_AUTO)) return -EBUSY;
return isdn_net_force_dial_lp(lp);
return isdn_net_force_dial_idev(idev);
}
/*
......@@ -1534,7 +1535,8 @@ isdn_net_force_dial(char *name)
if (!p)
return -ENODEV;
return (isdn_net_force_dial_lp(&p->local));
return isdn_net_force_dial_idev(p);
}
/*
......@@ -1544,6 +1546,7 @@ int
isdn_net_new(char *name, struct net_device *master)
{
int retval;
isdn_net_local *mlp = master->priv;
isdn_net_dev *netdev;
/* Avoid creating an existing interface */
......@@ -1557,29 +1560,25 @@ isdn_net_new(char *name, struct net_device *master)
}
memset(netdev, 0, sizeof(isdn_net_dev));
strcpy(netdev->name, name);
strcpy(netdev->dev.name, name);
netdev->dev.priv = &netdev->local;
netdev->dev.init = isdn_net_init;
strcpy(netdev->local.dev.name, name);
netdev->local.dev.priv = &netdev->local;
netdev->local.dev.init = isdn_net_init;
if (master) {
/* Device shall be a slave */
struct net_device *p = (((isdn_net_local *) master->priv)->slave);
struct net_device *q = master;
netdev->local.master = master;
/* Put device at end of slave-chain */
while (p) {
q = p;
p = (((isdn_net_local *) p->priv)->slave);
}
((isdn_net_local *) q->priv)->slave = &(netdev->dev);
isdn_net_dev *p = mlp->netdev;
while (p->slave)
p = p->slave;
p->slave = netdev;
} else {
/* Device shall be a master */
/*
* Watchdog timer (currently) for master only.
*/
netdev->dev.tx_timeout = isdn_net_tx_timeout;
netdev->dev.watchdog_timeo = ISDN_NET_TX_TIMEOUT;
retval = register_netdev(&netdev->dev);
netdev->local.dev.tx_timeout = isdn_net_tx_timeout;
netdev->local.dev.watchdog_timeo = ISDN_NET_TX_TIMEOUT;
retval = register_netdev(&netdev->local.dev);
if (retval) {
printk(KERN_WARNING "isdn_net: Could not register net-device\n");
kfree(netdev);
......@@ -1588,17 +1587,17 @@ isdn_net_new(char *name, struct net_device *master)
}
netdev->local.magic = ISDN_NET_MAGIC;
netdev->queue = &netdev->local;
spin_lock_init(&netdev->queue_lock);
netdev->local.queue = netdev;
spin_lock_init(&netdev->local.queue_lock);
netdev->local.last = &netdev->local;
netdev->last = netdev;
netdev->next = netdev;
netdev->local.netdev = netdev;
netdev->local.next = &netdev->local;
netdev->local.tqueue.sync = 0;
netdev->local.tqueue.routine = isdn_net_softint;
netdev->local.tqueue.data = &netdev->local;
spin_lock_init(&netdev->local.xmit_lock);
netdev->tqueue.sync = 0;
netdev->tqueue.routine = isdn_net_softint;
netdev->tqueue.data = netdev;
spin_lock_init(&netdev->xmit_lock);
netdev->isdn_slot = -1;
netdev->pre_device = -1;
......@@ -1609,7 +1608,7 @@ isdn_net_new(char *name, struct net_device *master)
netdev->pppbind = -1;
netdev->local.p_encap = -1;
skb_queue_head_init(&netdev->local.super_tx_queue);
skb_queue_head_init(&netdev->super_tx_queue);
netdev->local.l2_proto = ISDN_PROTO_L2_X75I;
netdev->local.l3_proto = ISDN_PROTO_L3_TRANS;
netdev->local.triggercps = 6000;
......@@ -1656,19 +1655,19 @@ isdn_net_newslave(char *parm)
if (!(m = isdn_net_findif(parm)))
return -ESRCH;
/* Master must be a real interface, not a slave */
if (m->local.master)
if (m->master)
return -ENXIO;
/* Master must not be started yet */
if (isdn_net_device_started(m))
return -EBUSY;
return isdn_net_new(p+1, &m->dev);
return isdn_net_new(p+1, &m->local.dev);
}
static int
isdn_net_set_encap(isdn_net_dev *p, int encap)
isdn_net_set_encap(isdn_net_dev *idev, int encap)
{
isdn_net_local *lp = &p->local;
isdn_net_local *lp = &idev->local;
int retval = 0;
if (lp->p_encap == encap){
......@@ -1676,7 +1675,7 @@ isdn_net_set_encap(isdn_net_dev *p, int encap)
retval = 0;
goto out;
}
if (isdn_net_device_started(p)) {
if (isdn_net_device_started(idev)) {
retval = -EBUSY;
goto out;
}
......@@ -1693,11 +1692,11 @@ isdn_net_set_encap(isdn_net_dev *p, int encap)
lp->p_encap = encap;
lp->ops = netif_ops[encap];
p->dev.hard_header = lp->ops->hard_header;
p->dev.do_ioctl = lp->ops->do_ioctl;
p->dev.flags = lp->ops->flags;
p->dev.type = lp->ops->type;
p->dev.addr_len = lp->ops->addr_len;
lp->dev.hard_header = lp->ops->hard_header;
lp->dev.do_ioctl = lp->ops->do_ioctl;
lp->dev.flags = lp->ops->flags;
lp->dev.type = lp->ops->type;
lp->dev.addr_len = lp->ops->addr_len;
if (lp->ops->init)
retval = lp->ops->init(lp);
......@@ -1928,12 +1927,12 @@ isdn_net_getcfg(isdn_net_ioctl_cfg * cfg)
cfg->pppbind = idev->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)->netdev->name);
if (idev->slave)
strcpy(cfg->slave, idev->slave->name);
else
cfg->slave[0] = '\0';
if (lp->master)
strcpy(cfg->master, ((isdn_net_local *) lp->master->priv)->netdev->name);
if (idev->master)
strcpy(cfg->master, idev->master->netdev->name);
else
cfg->master[0] = '\0';
......@@ -2090,7 +2089,7 @@ int
isdn_net_force_hangup(char *name)
{
isdn_net_dev *idev = isdn_net_findif(name);
struct net_device *q;
isdn_net_dev *p;
if (!idev)
return -ENODEV;
......@@ -2098,11 +2097,11 @@ isdn_net_force_hangup(char *name)
if (idev->isdn_slot < 0)
return -ENOTCONN;
q = idev->local.slave;
p = idev->slave;
/* If this interface has slaves, do a hangup for them also. */
while (q) {
isdn_net_hangup(((isdn_net_local *) q->priv)->netdev);
q = (((isdn_net_local *) q->priv)->slave);
while (p) {
isdn_net_hangup(p);
p = p->slave;
}
isdn_net_hangup(idev);
return 0;
......@@ -2129,19 +2128,19 @@ isdn_net_realrm(isdn_net_dev *p)
/* If interface is bound exclusive, free channel-usage */
if (p->exclusive >= 0)
isdn_unexclusive_channel(p->pre_device, p->pre_channel);
if (p->local.master) {
if (p->master) {
/* It's a slave-device, so update master's slave-pointer if necessary */
if (((isdn_net_local *) (p->local.master->priv))->slave == &p->dev)
((isdn_net_local *) (p->local.master->priv))->slave = p->local.slave;
if (p->master->netdev->slave == p)
p->master->netdev->slave = p->slave;
} else {
/* Unregister only if it's a master-device */
unregister_netdev(&p->dev);
unregister_netdev(&p->local.dev);
}
/* Unlink device from chain */
list_del(&p->global_list);
if (p->local.slave) {
if (p->slave) {
/* If this interface has a slave, remove it also */
char *slavename = ((isdn_net_local *) (p->local.slave->priv))->netdev->name;
char *slavename = p->slave->name;
struct list_head *l;
list_for_each(l, &isdn_net_devs) {
......@@ -2191,7 +2190,7 @@ isdn_net_rmall(void)
isdn_net_dev *p = list_entry(isdn_net_devs.next, isdn_net_dev, global_list);
/* Remove master-devices only, slaves get removed with their master */
if (!p->local.master) {
if (!p->master) {
if ((ret = isdn_net_realrm(p))) {
restore_flags(flags);
return ret;
......@@ -2216,10 +2215,10 @@ isdn_iptyp_header(struct sk_buff *skb, struct net_device *dev,
}
static void
isdn_iptyp_receive(isdn_net_dev *p, isdn_net_local *olp,
isdn_iptyp_receive(isdn_net_local *lp, isdn_net_dev *idev,
struct sk_buff *skb)
{
isdn_net_reset_huptimer(p, olp->netdev);
isdn_net_reset_huptimer(lp, idev);
get_u16(skb->data, &skb->protocol);
skb_pull(skb, 2);
netif_rx(skb);
......@@ -2247,10 +2246,10 @@ isdn_uihdlc_header(struct sk_buff *skb, struct net_device *dev,
}
static void
isdn_uihdlc_receive(isdn_net_dev *p, isdn_net_local *olp,
isdn_uihdlc_receive(isdn_net_local *lp, isdn_net_dev *idev,
struct sk_buff *skb)
{
isdn_net_reset_huptimer(p, olp->netdev);
isdn_net_reset_huptimer(lp, idev);
skb_pull(skb, 2);
skb->protocol = htons(ETH_P_IP);
netif_rx(skb);
......@@ -2269,10 +2268,10 @@ static struct isdn_netif_ops uihdlc_ops = {
// ======================================================================
static void
isdn_rawip_receive(isdn_net_dev *p, isdn_net_local *olp,
isdn_rawip_receive(isdn_net_local *lp, isdn_net_dev *idev,
struct sk_buff *skb)
{
isdn_net_reset_huptimer(p, olp->netdev);
isdn_net_reset_huptimer(lp, idev);
skb->protocol = htons(ETH_P_IP);
netif_rx(skb);
}
......@@ -2342,10 +2341,10 @@ isdn_eth_type_trans(struct sk_buff *skb, struct net_device *dev)
}
static void
isdn_ether_receive(isdn_net_dev *p, isdn_net_local *olp,
isdn_ether_receive(isdn_net_local *lp, isdn_net_dev *idev,
struct sk_buff *skb)
{
isdn_net_reset_huptimer(p, olp->netdev);
isdn_net_reset_huptimer(lp, idev);
skb->protocol = isdn_eth_type_trans(skb, skb->dev);
netif_rx(skb);
}
......@@ -2353,7 +2352,7 @@ isdn_ether_receive(isdn_net_dev *p, isdn_net_local *olp,
static int
isdn_ether_open(isdn_net_local *lp)
{
struct net_device *dev = &lp->netdev->dev;
struct net_device *dev = &lp->dev;
struct in_device *in_dev;
int i;
......@@ -2373,7 +2372,7 @@ isdn_ether_open(isdn_net_local *lp)
static int
isdn_ether_init(isdn_net_local *lp)
{
struct net_device *dev = &lp->netdev->dev;
struct net_device *dev = &lp->dev;
ether_setup(dev);
dev->tx_queue_len = 10;
......
......@@ -52,16 +52,16 @@ extern int isdn_net_force_hangup(char *);
extern int isdn_net_force_dial(char *);
extern isdn_net_dev *isdn_net_findif(char *);
extern int isdn_net_rcv_skb(int, struct sk_buff *);
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_write_super(isdn_net_local *lp, struct sk_buff *skb);
extern int isdn_net_online(isdn_net_dev *idev);
extern int isdn_net_dial_req(isdn_net_dev *);
extern void isdn_net_writebuf_skb(isdn_net_dev *, struct sk_buff *skb);
extern void isdn_net_write_super(isdn_net_dev *, struct sk_buff *skb);
extern int isdn_net_online(isdn_net_dev *);
static inline void
isdn_net_reset_huptimer(isdn_net_dev *idev, isdn_net_dev *idev2)
isdn_net_reset_huptimer(isdn_net_local *lp, isdn_net_dev *idev)
{
lp->netdev->huptimer = 0;
idev->huptimer = 0;
idev2->huptimer = 0;
}
#define ISDN_NET_MAX_QUEUE_LENGTH 2
......@@ -69,9 +69,10 @@ isdn_net_reset_huptimer(isdn_net_dev *idev, isdn_net_dev *idev2)
/*
* is this particular channel busy?
*/
static __inline__ int isdn_net_lp_busy(isdn_net_local *lp)
static inline int
isdn_net_dev_busy(isdn_net_dev *idev)
{
if (atomic_read(&lp->frame_cnt) < ISDN_NET_MAX_QUEUE_LENGTH)
if (atomic_read(&idev->frame_cnt) < ISDN_NET_MAX_QUEUE_LENGTH)
return 0;
else
return 1;
......@@ -81,86 +82,93 @@ static __inline__ int isdn_net_lp_busy(isdn_net_local *lp)
* For the given net device, this will get a non-busy channel out of the
* corresponding bundle. The returned channel is locked.
*/
static __inline__ isdn_net_local * isdn_net_get_locked_lp(isdn_net_dev *nd)
static inline isdn_net_dev *
isdn_net_get_locked_dev(isdn_net_local *mlp)
{
unsigned long flags;
isdn_net_local *lp;
spin_lock_irqsave(&nd->queue_lock, flags);
lp = nd->queue; /* get lp on top of queue */
spin_lock_bh(&nd->queue->xmit_lock);
while (isdn_net_lp_busy(nd->queue)) {
spin_unlock_bh(&nd->queue->xmit_lock);
nd->queue = nd->queue->next;
if (nd->queue == lp) { /* not found -- should never happen */
lp = NULL;
isdn_net_dev *idev;
isdn_net_dev *head;
spin_lock_irqsave(&mlp->queue_lock, flags);
head = mlp->queue;
idev = head;
spin_lock_bh(&idev->xmit_lock);
while (isdn_net_dev_busy(idev)) {
spin_unlock_bh(&idev->xmit_lock);
mlp->queue = mlp->queue->next;
idev = mlp->queue;
if (idev == head) { /* not found -- should never happen */
idev = NULL;
goto errout;
}
spin_lock_bh(&nd->queue->xmit_lock);
spin_lock_bh(&idev->xmit_lock);
}
lp = nd->queue;
nd->queue = nd->queue->next;
idev = mlp->queue;
mlp->queue = mlp->queue->next;
errout:
spin_unlock_irqrestore(&nd->queue_lock, flags);
return lp;
spin_unlock_irqrestore(&mlp->queue_lock, flags);
return idev;
}
/*
* add a channel to a bundle
*/
static __inline__ void isdn_net_add_to_bundle(isdn_net_dev *nd, isdn_net_local *nlp)
static inline void
isdn_net_add_to_bundle(isdn_net_local *mlp, isdn_net_dev *idev)
{
isdn_net_local *lp;
isdn_net_dev *qdev;
unsigned long flags;
spin_lock_irqsave(&nd->queue_lock, flags);
spin_lock_irqsave(&mlp->queue_lock, flags);
lp = nd->queue;
nlp->last = lp->last;
lp->last->next = nlp;
lp->last = nlp;
nlp->next = lp;
nd->queue = nlp;
qdev = mlp->queue;
idev->last = qdev->last;
qdev->last->next = idev;
qdev->last = idev;
idev->next = qdev;
mlp->queue = idev;
spin_unlock_irqrestore(&nd->queue_lock, flags);
spin_unlock_irqrestore(&mlp->queue_lock, flags);
}
/*
* remove a channel from the bundle it belongs to
*/
static __inline__ void isdn_net_rm_from_bundle(isdn_net_local *lp)
static inline void
isdn_net_rm_from_bundle(isdn_net_dev *idev)
{
isdn_net_local *master_lp = lp;
isdn_net_local *mlp;
unsigned long flags;
if (lp->master)
master_lp = (isdn_net_local *) lp->master->priv;
if (idev->master)
mlp = idev->master;
else
mlp = &idev->local;
spin_lock_irqsave(&master_lp->netdev->queue_lock, flags);
lp->last->next = lp->next;
lp->next->last = lp->last;
if (master_lp->netdev->queue == lp) {
master_lp->netdev->queue = lp->next;
if (lp->next == lp) { /* last in queue */
master_lp->netdev->queue = &master_lp->netdev->local;
}
spin_lock_irqsave(&mlp->queue_lock, flags);
idev->last->next = idev->next;
idev->next->last = idev->last;
if (mlp->queue == idev) {
mlp->queue = idev->next;
}
lp->next = lp->last = lp; /* (re)set own pointers */
spin_unlock_irqrestore(&master_lp->netdev->queue_lock, flags);
idev->next = idev->last = idev; /* (re)set own pointers */
spin_unlock_irqrestore(&mlp->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)
static inline void
isdn_net_dev_wake_queue(isdn_net_dev *idev)
{
if (lp->master)
netif_wake_queue(lp->master);
if (idev->master)
netif_wake_queue(&idev->master->dev);
else
netif_wake_queue(&lp->netdev->dev);
netif_wake_queue(&idev->local.dev);
}
static inline int isdn_net_bound(isdn_net_dev *idev)
static inline int
isdn_net_bound(isdn_net_dev *idev)
{
return idev->isdn_slot >= 0;
}
......
......@@ -23,7 +23,7 @@
/* Prototypes */
static int isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot);
static int isdn_ppp_closewait(int slot);
static void isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp,
static void isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev,
struct sk_buff *skb, int proto);
static int isdn_ppp_if_get_unit(char *namebuf);
static int isdn_ppp_set_compressor(struct ippp_struct *is,struct isdn_ppp_comp_data *);
......@@ -59,10 +59,10 @@ static void isdn_ppp_ccp_reset_ack_rcvd(struct ippp_struct *is,
static ippp_bundle * isdn_ppp_bundle_arr = NULL;
static int isdn_ppp_mp_bundle_array_init(void);
static int isdn_ppp_mp_init( isdn_net_local * lp, ippp_bundle * add_to );
static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp,
struct sk_buff *skb);
static void isdn_ppp_mp_cleanup( isdn_net_local * lp );
static int isdn_ppp_mp_init(isdn_net_local *lp, ippp_bundle *add_to);
static void isdn_ppp_mp_receive(isdn_net_local *lp, isdn_net_dev *idev,
struct sk_buff *skb);
static void isdn_ppp_mp_cleanup(isdn_net_local *lp );
static int isdn_ppp_bundle(struct ippp_struct *, int unit);
#endif /* CONFIG_ISDN_MPP */
......@@ -118,7 +118,7 @@ isdn_ppp_free(isdn_net_local * lp)
#ifdef CONFIG_ISDN_MPP
spin_lock(&lp->netdev->pb->lock);
#endif
isdn_net_rm_from_bundle(lp);
isdn_net_rm_from_bundle(idev);
#ifdef CONFIG_ISDN_MPP
if (lp->netdev->pb->ref_ct == 1) /* last link in queue? */
isdn_ppp_mp_cleanup(lp);
......@@ -314,8 +314,6 @@ isdn_ppp_open(struct inode *ino, struct file *file)
is->maxcid = 16; /* VJ: maxcid */
is->tk = current;
init_waitqueue_head(&is->wq);
is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */
is->last = is->rq;
is->minor = minor;
#ifdef CONFIG_ISDN_PPP_VJ
/*
......@@ -337,7 +335,6 @@ static int
isdn_ppp_release(struct inode *ino, struct file *file)
{
uint minor = minor(ino->i_rdev) - ISDN_MINOR_PPP;
int i;
struct ippp_struct *is;
lock_kernel();
......@@ -356,14 +353,7 @@ isdn_ppp_release(struct inode *ino, struct file *file)
is->state &= ~IPPP_CONNECT;
isdn_net_hangup(is->idev);
}
for (i = 0; i < NUM_RCV_BUFFS; i++) {
if (is->rq[i].buf) {
kfree(is->rq[i].buf);
is->rq[i].buf = NULL;
}
}
is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */
is->last = is->rq;
skb_queue_purge(&is->rq);
#ifdef CONFIG_ISDN_PPP_VJ
/* TODO: if this was the previous master: link the slcomp to the new master */
......@@ -487,7 +477,7 @@ isdn_ppp_ioctl(struct inode *ino, struct file *file, unsigned int cmd, unsigned
if (val & SC_ENABLE_IP && !(is->pppcfg & SC_ENABLE_IP) && (is->state & IPPP_CONNECT)) {
if (idev) {
/* OK .. we are ready to send buffers */
netif_wake_queue(&idev->dev);
netif_wake_queue(&idev->local.dev);
}
}
is->pppcfg = val;
......@@ -595,12 +585,8 @@ static unsigned int
isdn_ppp_poll(struct file *file, poll_table * wait)
{
unsigned int mask;
struct ippp_buf_queue *bf;
struct ippp_buf_queue *bl;
unsigned long flags;
struct ippp_struct *is;
lock_kernel();
is = file->private_data;
if (is->debug & 0x2)
......@@ -622,21 +608,15 @@ isdn_ppp_poll(struct file *file, poll_table * wait)
/* we're always ready to send .. */
mask = POLLOUT | POLLWRNORM;
save_flags(flags);
cli();
bl = is->last;
bf = is->first;
/*
* if IPPP_NOBLOCK is set we return even if we have nothing to read
*/
if (bf->next != bl || (is->state & IPPP_NOBLOCK)) {
if (!skb_queue_empty(&is->rq) || is->state & IPPP_NOBLOCK) {
is->state &= ~IPPP_NOBLOCK;
mask |= POLLIN | POLLRDNORM;
}
restore_flags(flags);
out:
unlock_kernel();
return mask;
}
......@@ -647,10 +627,8 @@ isdn_ppp_poll(struct file *file, poll_table * wait)
static int
isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot)
{
struct ippp_buf_queue *bf,
*bl;
unsigned long flags;
unsigned char *nbuf;
struct sk_buff *skb;
unsigned char *p;
struct ippp_struct *is;
if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
......@@ -663,36 +641,23 @@ isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot)
printk(KERN_DEBUG "ippp: device not activated.\n");
return 0;
}
nbuf = (unsigned char *) kmalloc(len + 4, GFP_ATOMIC);
if (!nbuf) {
printk(KERN_WARNING "ippp: Can't alloc buf\n");
if (skb_queue_len(&is->rq) > IPPP_MAX_RQ_LEN) {
printk(KERN_WARNING "ippp: Queue is full\n");
return 0;
}
nbuf[0] = PPP_ALLSTATIONS;
nbuf[1] = PPP_UI;
nbuf[2] = proto >> 8;
nbuf[3] = proto & 0xff;
memcpy(nbuf + 4, buf, len);
save_flags(flags);
cli();
bf = is->first;
bl = is->last;
if (bf == bl) {
printk(KERN_WARNING "ippp: Queue is full; discarding first buffer\n");
bf = bf->next;
kfree(bf->buf);
is->first = bf;
skb = dev_alloc_skb(len + 4);
if (!skb) {
printk(KERN_WARNING "ippp: Can't alloc buf\n");
return 0;
}
bl->buf = (char *) nbuf;
bl->len = len + 4;
is->last = bl->next;
restore_flags(flags);
p = skb_put(skb, 4);
p += put_u8(p, PPP_ALLSTATIONS);
p += put_u8(p, PPP_UI);
p += put_u16(p, proto);
memcpy(skb_put(skb, len), buf, len);
wake_up_interruptible(&is->wq);
skb_queue_tail(&is->rq, skb);
wake_up_interruptible(&is->wq);
return len;
}
......@@ -706,54 +671,36 @@ static ssize_t
isdn_ppp_read(struct file *file, char *buf, size_t count, loff_t *off)
{
struct ippp_struct *is;
struct ippp_buf_queue *b;
unsigned long flags;
unsigned char *save_buf;
struct sk_buff *skb;
int retval;
if (off != &file->f_pos)
return -ESPIPE;
lock_kernel();
is = file->private_data;
if (!(is->state & IPPP_OPEN)) {
retval = 0;
goto out;
}
retval = verify_area(VERIFY_WRITE, (void *) buf, count);
if (retval)
goto out;
save_flags(flags);
cli();
b = is->first->next;
save_buf = b->buf;
if (!save_buf) {
restore_flags(flags);
skb = skb_dequeue(&is->rq);
if (!skb) {
retval = -EAGAIN;
goto out;
}
if (b->len < count)
count = b->len;
b->buf = NULL;
is->first = b;
restore_flags(flags);
if (copy_to_user(buf, save_buf, count)) {
kfree(save_buf);
if (skb->len > count) {
retval = -EMSGSIZE;
goto out_free;
}
if (copy_to_user(buf, skb->data, skb->len)) {
retval = -EFAULT;
goto out;
goto out_free;
}
kfree(save_buf);
retval = count;
retval = skb->len;
out_free:
dev_kfree_skb(skb);
out:
unlock_kernel();
return retval;
}
......@@ -834,7 +781,7 @@ isdn_ppp_write(struct file *file, const char *buf, size_t count, loff_t *off)
isdn_ppp_send_ccp(idev,&idev->local,skb); /* keeps CCP/compression states in sync */
isdn_net_write_super(&idev->local, skb);
isdn_net_write_super(idev, skb);
}
}
retval = count;
......@@ -881,15 +828,7 @@ isdn_ppp_init(void)
}
memset((char *) ippp_table[i], 0, sizeof(struct ippp_struct));
ippp_table[i]->state = 0;
ippp_table[i]->first = ippp_table[i]->rq + NUM_RCV_BUFFS - 1;
ippp_table[i]->last = ippp_table[i]->rq;
for (j = 0; j < NUM_RCV_BUFFS; j++) {
ippp_table[i]->rq[j].buf = NULL;
ippp_table[i]->rq[j].last = ippp_table[i]->rq +
(NUM_RCV_BUFFS + j - 1) % NUM_RCV_BUFFS;
ippp_table[i]->rq[j].next = ippp_table[i]->rq + (j + 1) % NUM_RCV_BUFFS;
}
skb_queue_head_init(&ippp_table[i]->rq);
}
return 0;
}
......@@ -963,10 +902,9 @@ static int isdn_ppp_strip_proto(struct sk_buff *skb)
/*
* handler for incoming packets on a syncPPP interface
*/
static void isdn_ppp_receive(isdn_net_dev *net_dev, isdn_net_local *lp,
static void isdn_ppp_receive(isdn_net_local *lp, isdn_net_dev *idev,
struct sk_buff *skb)
{
isdn_net_dev *idev = lp->netdev;
struct ippp_struct *is;
int slot;
int proto;
......@@ -976,7 +914,7 @@ static void isdn_ppp_receive(isdn_net_dev *net_dev, isdn_net_local *lp,
* huptimer on LCP packets.
*/
if (PPP_PROTOCOL(skb->data) != PPP_LCP)
isdn_net_reset_huptimer(net_dev,lp->netdev);
isdn_net_reset_huptimer(lp, idev);
slot = idev->ppp_slot;
if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
......@@ -1012,12 +950,12 @@ static void isdn_ppp_receive(isdn_net_dev *net_dev, isdn_net_local *lp,
if (!(is->mpppcfg & SC_REJ_MP_PROT)) { // we agreed to receive MPPP
if (proto == PPP_MP) {
isdn_ppp_mp_receive(net_dev, lp, skb);
isdn_ppp_mp_receive(lp, idev, skb);
return;
}
}
#endif
isdn_ppp_push_higher(net_dev, lp, skb, proto);
isdn_ppp_push_higher(lp, idev, skb, proto);
}
/*
......@@ -1026,10 +964,10 @@ static void isdn_ppp_receive(isdn_net_dev *net_dev, isdn_net_local *lp,
* note: net_dev has to be master net_dev
*/
static void
isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb, int proto)
isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev,
struct sk_buff *skb, int proto)
{
isdn_net_dev *idev = lp->netdev;
struct net_device *dev = &net_dev->dev;
struct net_device *dev = &lp->dev;
struct ippp_struct *is, *mis;
int slot;
......@@ -1041,8 +979,8 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
}
is = ippp_table[slot];
if (lp->master) { // FIXME?
slot = ((isdn_net_local *) (lp->master->priv))->netdev->ppp_slot;
if (idev->master) { // FIXME?
slot = idev->master->netdev->ppp_slot;
if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
printk(KERN_ERR "isdn_ppp_push_higher: master->ppp_slot(%d)\n",
slot);
......@@ -1079,12 +1017,12 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
case PPP_VJC_UNCOMP:
if (is->debug & 0x20)
printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n");
if (net_dev->ppp_slot < 0) {
if (lp->netdev->ppp_slot < 0) {
printk(KERN_ERR "%s: net_dev->ppp_slot(%d) out of range\n",
__FUNCTION__ , net_dev->ppp_slot);
__FUNCTION__ , lp->netdev->ppp_slot);
goto drop_packet;
}
if (slhc_remember(ippp_table[net_dev->ppp_slot]->slcomp, skb->data, skb->len) <= 0) {
if (slhc_remember(ippp_table[lp->netdev->ppp_slot]->slcomp, skb->data, skb->len) <= 0) {
printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n");
goto drop_packet;
}
......@@ -1105,12 +1043,12 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
}
skb_put(skb, skb_old->len + 128);
memcpy(skb->data, skb_old->data, skb_old->len);
if (net_dev->ppp_slot < 0) {
if (lp->netdev->ppp_slot < 0) {
printk(KERN_ERR "%s: net_dev->ppp_slot(%d) out of range\n",
__FUNCTION__ , net_dev->ppp_slot);
__FUNCTION__ , lp->netdev->ppp_slot);
goto drop_packet;
}
pkt_len = slhc_uncompress(ippp_table[net_dev->ppp_slot]->slcomp,
pkt_len = slhc_uncompress(ippp_table[lp->netdev->ppp_slot]->slcomp,
skb->data, skb_old->len);
kfree_skb(skb_old);
if (pkt_len < 0)
......@@ -1123,7 +1061,7 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
#endif
case PPP_CCP:
case PPP_CCPFRAG:
isdn_ppp_receive_ccp(net_dev,lp,skb,proto);
isdn_ppp_receive_ccp(lp->netdev,lp,skb,proto);
/* Dont pop up ResetReq/Ack stuff to the daemon any
longer - the job is done already */
if(skb->data[0] == CCP_RESETREQ ||
......@@ -1146,7 +1084,7 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff
return;
drop_packet:
net_dev->local.stats.rx_dropped++;
lp->stats.rx_dropped++;
kfree_skb(skb);
}
......@@ -1187,14 +1125,14 @@ static unsigned char *isdn_ppp_skb_push(struct sk_buff **skb_p,int len)
int
isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
{
isdn_net_local *lp,*mlp;
isdn_net_local *mlp;
isdn_net_dev *idev;
isdn_net_dev *nd;
unsigned int proto = PPP_IP; /* 0x21 */
struct ippp_struct *ipt,*ipts;
int slot;
mlp = (isdn_net_local *) (netdev->priv);
mlp = netdev->priv;
nd = mlp->netdev; /* get master lp */
slot = nd->ppp_slot;
......@@ -1226,13 +1164,12 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
return 0;
}
lp = isdn_net_get_locked_lp(nd);
if (!lp) {
idev = isdn_net_get_locked_dev(mlp);
if (!idev) {
printk(KERN_WARNING "%s: all channels busy - requeuing!\n", netdev->name);
return 1;
}
/* we have our lp locked from now on */
idev = lp->netdev;
slot = idev->ppp_slot;
if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n",
......@@ -1385,10 +1322,10 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
isdn_ppp_frame_log("xmit", skb->data, skb->len, 32,ipt->unit,idev->ppp_slot);
}
isdn_net_writebuf_skb(lp, skb);
isdn_net_writebuf_skb(idev, skb);
unlock:
spin_unlock_bh(&lp->xmit_lock);
spin_unlock_bh(&idev->xmit_lock);
return 0;
}
......@@ -1459,7 +1396,7 @@ static int isdn_ppp_mp_init( isdn_net_local * lp, ippp_bundle * add_to )
is->mp_seqno = 0;
if ((lp->netdev->pb = isdn_ppp_mp_bundle_alloc()) == NULL)
return -ENOMEM;
lp->next = lp->last = lp; /* nobody else in a queue */
idev->next = idev->last = idev; /* nobody else in a queue */
lp->netdev->pb->frags = NULL;
lp->netdev->pb->frames = 0;
lp->netdev->pb->seq = LONG_MAX;
......@@ -1479,12 +1416,12 @@ static void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp,
static void isdn_ppp_mp_free_skb( ippp_bundle * mp, struct sk_buff * skb );
static void isdn_ppp_mp_print_recv_pkt( int slot, struct sk_buff * skb );
static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp,
struct sk_buff *skb)
static void isdn_ppp_mp_receive(isdn_net_local *lp, isdn_net_dev *dev,
struct sk_buff *skb)
{
isdn_net_dev *idev = lp->netdev;
struct ippp_struct *is;
isdn_net_local * lpq;
isdn_net_dev *qdev;
ippp_bundle * mp;
isdn_mppp_stats * stats;
struct sk_buff * newfrag, * frag, * start, *nextf;
......@@ -1492,8 +1429,8 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp,
unsigned long flags;
int slot;
spin_lock_irqsave(&net_dev->pb->lock, flags);
mp = net_dev->pb;
spin_lock_irqsave(&lp->netdev->pb->lock, flags);
mp = lp->netdev->pb;
stats = &mp->stats;
slot = idev->ppp_slot;
if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
......@@ -1531,8 +1468,8 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp,
/* find the minimum received sequence number over all links */
is->last_link_seqno = minseq = newseq;
for (lpq = net_dev->queue;;) {
slot = lpq->netdev->ppp_slot;
for (qdev = lp->queue;;) {
slot = qdev->ppp_slot;
if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
printk(KERN_ERR "%s: lpq->ppp_slot(%d)\n",
__FUNCTION__ ,slot);
......@@ -1541,7 +1478,7 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp,
if (MP_LT(lls, minseq))
minseq = lls;
}
if ((lpq = lpq->next) == net_dev->queue)
if ((qdev = qdev->next) == lp->queue)
break;
}
if (MP_LT(minseq, mp->seq))
......@@ -1631,7 +1568,7 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp,
if (start != NULL && (MP_FLAGS(frag) & MP_END_FRAG)) {
minseq = mp->seq = (thisseq+1) & MP_LONGSEQ_MASK;
/* Reassemble the packet then dispatch it */
isdn_ppp_mp_reassembly(net_dev, lp, start, nextf);
isdn_ppp_mp_reassembly(lp->netdev, lp, start, nextf);
start = NULL;
frag = NULL;
......@@ -1808,7 +1745,7 @@ void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp,
}
}
proto = isdn_ppp_strip_proto(skb);
isdn_ppp_push_higher(net_dev, lp, skb, proto);
isdn_ppp_push_higher(lp, idev, skb, proto);
}
static void isdn_ppp_mp_free_skb(ippp_bundle * mp, struct sk_buff * skb)
......@@ -1844,7 +1781,7 @@ isdn_ppp_bundle(struct ippp_struct *is, int unit)
spin_lock_irqsave(&p->pb->lock, flags);
nidev = is->idev;
idev = p->queue->netdev;
idev = p->local.queue;
if( nidev->ppp_slot < 0 || nidev->ppp_slot >= ISDN_MAX_CHANNELS ||
idev ->ppp_slot < 0 || idev ->ppp_slot >= ISDN_MAX_CHANNELS ) {
printk(KERN_ERR "ippp_bundle: binding to invalid slot %d\n",
......@@ -1854,7 +1791,7 @@ isdn_ppp_bundle(struct ippp_struct *is, int unit)
goto out;
}
isdn_net_add_to_bundle(p, &nidev->local);
isdn_net_add_to_bundle(&p->local, nidev);
ippp_table[nidev->ppp_slot]->unit = ippp_table[idev->ppp_slot]->unit;
......@@ -1978,7 +1915,7 @@ isdn_ppp_dial_slave(char *name)
#ifdef CONFIG_ISDN_MPP
isdn_net_dev *idev;
isdn_net_local *lp;
struct net_device *sdev;
isdn_net_dev *sdev;
idev = isdn_net_findif(name);
if (!idev)
......@@ -1988,17 +1925,16 @@ isdn_ppp_dial_slave(char *name)
if (!isdn_net_bound(idev))
return 5;
sdev = lp->slave;
sdev = idev->slave;
while (sdev) {
isdn_net_local *mlp = (isdn_net_local *) sdev->priv;
if (!isdn_net_bound(mlp->netdev))
if (!isdn_net_bound(sdev))
break;
sdev = mlp->slave;
sdev = sdev->slave;
}
if (!sdev)
return 2;
isdn_net_dial_req((isdn_net_local *) sdev->priv);
isdn_net_dial_req(sdev);
return 0;
#else
return -1;
......@@ -2009,35 +1945,20 @@ int
isdn_ppp_hangup_slave(char *name)
{
#ifdef CONFIG_ISDN_MPP
isdn_net_dev *idev;
isdn_net_local *lp, *mlp = NULL;
struct net_device *sdev;
isdn_net_dev *idev, *sdev;
idev = isdn_net_findif(name);
if (!idev)
return 1;
lp = &idev->local;
if (!isdn_net_bound(idev))
return 5;
sdev = lp->slave;
while (sdev) {
mlp = (isdn_net_local *) sdev->priv;
if (mlp->slave) { /* find last connected link in chain */
isdn_net_local *nlp = (isdn_net_local *) mlp->slave->priv;
if (!isdn_net_bound(nlp->netdev))
break;
} else if (isdn_net_bound(mlp->netdev))
break;
sdev = mlp->slave;
}
if (!sdev)
sdev = idev->slave;
if (!sdev || !isdn_net_bound(sdev))
return 2;
isdn_net_hangup(mlp->netdev);
isdn_net_hangup(sdev);
return 0;
#else
return -1;
......@@ -2139,7 +2060,7 @@ static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto,
printk(KERN_DEBUG "Sending CCP Frame:\n");
isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit,idev->ppp_slot);
isdn_net_write_super(&idev->local, skb);
isdn_net_write_super(idev, skb);
}
/* Allocate the reset state vector */
......@@ -2557,8 +2478,8 @@ static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,
is = ippp_table[idev->ppp_slot];
isdn_ppp_frame_log("ccp-rcv", skb->data, skb->len, 32, is->unit,idev->ppp_slot);
if(lp->master) {
int slot = ((isdn_net_local *) (lp->master->priv))->netdev->ppp_slot;
if (idev->master) {
int slot = idev->master->netdev->ppp_slot;
if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
printk(KERN_ERR "%s: slot(%d) out of range\n",
__FUNCTION__ , slot);
......@@ -2745,8 +2666,8 @@ static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, struct
printk(KERN_DEBUG "Received CCP frame from daemon:\n");
isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit,idev->ppp_slot);
if (lp->master) {
slot = ((isdn_net_local *) (lp->master->priv))->netdev->ppp_slot;
if (idev->master) {
slot = idev->master->netdev->ppp_slot;
if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
printk(KERN_ERR "%s: slot(%d) out of range\n",
__FUNCTION__ , slot);
......
......@@ -294,8 +294,8 @@ struct isdn_netif_ops {
unsigned short flags; /* interface flags (a la BSD) */
unsigned short type; /* interface hardware type */
unsigned char addr_len;/* hardware address length */
void (*receive)(struct isdn_net_dev_s *p,
struct isdn_net_local_s *olp,
void (*receive)(struct isdn_net_local_s *lp,
struct isdn_net_dev_s *idev,
struct sk_buff *skb);
void (*connected)(struct isdn_net_local_s *lp);
void (*disconnected)(struct isdn_net_local_s *lp);
......@@ -329,26 +329,17 @@ typedef struct isdn_net_local_s {
u_char l2_proto; /* Layer-2-protocol */
u_char l3_proto; /* Layer-3-protocol */
int sqfull; /* Flag: netdev-queue overloaded */
ulong sqfull_stamp; /* Start-Time of overload */
ulong slavedelay; /* Dynamic bundling delaytime */
int triggercps; /* BogoCPS needed for trigger slave */
struct list_head phone[2]; /* List of remote-phonenumbers */
/* phone[0] = Incoming Numbers */
/* phone[1] = Outgoing Numbers */
struct net_device *master; /* Ptr to Master device for slaves */
struct net_device *slave; /* Ptr to Slave device for masters */
struct isdn_net_local_s *next; /* Ptr to next link in bundle */
struct isdn_net_local_s *last; /* Ptr to last link in bundle */
struct isdn_net_dev_s *netdev; /* Ptr to netdev */
struct sk_buff_head super_tx_queue; /* List of supervisory frames to */
/* be transmitted asap */
atomic_t frame_cnt; /* number of frames currently */
/* queued in HL driver */
/* Ptr to orig. hard_header_cache */
spinlock_t xmit_lock; /* used to protect the xmit path of */
/* a particular channel (including */
/* the frame_cnt */
struct isdn_net_dev_s *queue; /* circular list of all bundled
channels, which are currently
online */
spinlock_t queue_lock; /* lock to protect queue */
#ifdef CONFIG_ISDN_X25
struct concap_device_ops *dops; /* callbacks used by encapsulator */
......@@ -361,9 +352,11 @@ typedef struct isdn_net_local_s {
ulong cisco_last_slarp_in; /* jiffie of last keepalive packet we received */
char cisco_line_state; /* state of line according to keepalive packets */
char cisco_debserint; /* debugging flag of cisco hdlc with slarp */
struct timer_list cisco_timer;
struct tq_struct tqueue;
struct isdn_netif_ops *ops;
struct timer_list cisco_timer;
struct isdn_netif_ops *ops;
struct net_device dev; /* interface to upper levels */
} isdn_net_local;
/* the interface itself */
......@@ -386,6 +379,8 @@ typedef struct isdn_net_dev_s {
int cps; /* current speed of this interface */
int transcount; /* byte-counter for cps-calculation */
int last_jiffies; /* when transcount was reset */
int sqfull; /* Flag: netdev-queue overloaded */
ulong sqfull_stamp; /* Start-Time of overload */
struct timer_list hup_timer; /* auto hangup timer */
int huptimer; /* Timeout-counter for auto-hangup */
......@@ -397,13 +392,24 @@ typedef struct isdn_net_dev_s {
int pppbind; /* ippp device for bindings */
int ppp_slot; /* PPPD device slot number */
isdn_net_local *queue; /* circular list of all bundled
channels, which are currently
online */
spinlock_t queue_lock; /* lock to protect queue */
spinlock_t xmit_lock; /* used to protect the xmit path of */
/* a particular channel (including */
/* the frame_cnt */
struct sk_buff_head super_tx_queue; /* List of supervisory frames to */
/* be transmitted asap */
atomic_t frame_cnt; /* number of frames currently */
/* queued in HL driver */
struct tq_struct tqueue;
isdn_net_local *master; /* Ptr to Master device for slaves */
struct isdn_net_dev_s *slave; /* Ptr to Slave device for masters */
struct isdn_net_dev_s *next; /* Ptr to next link in bundle */
struct isdn_net_dev_s *last; /* Ptr to last link in bundle */
char name[10]; /* Name of device */
struct list_head global_list; /* global list of all isdn_net_devs */
struct net_device dev; /* interface to upper levels */
#ifdef CONFIG_ISDN_PPP
ippp_bundle * pb; /* pointer to the common bundle structure
* with the per-bundle data */
......
......@@ -159,14 +159,7 @@ typedef struct {
isdn_mppp_stats stats;
} ippp_bundle;
#define NUM_RCV_BUFFS 64
struct ippp_buf_queue {
struct ippp_buf_queue *next;
struct ippp_buf_queue *last;
char *buf; /* NULL here indicates end of queue */
int len;
};
#define IPPP_MAX_RQ_LEN 8
/* The data structure for one CCP reset transaction */
enum ippp_ccp_reset_states {
......@@ -201,9 +194,7 @@ struct ippp_ccp_reset {
struct ippp_struct {
struct ippp_struct *next_link;
int state;
struct ippp_buf_queue rq[NUM_RCV_BUFFS]; /* packet queue for isdn_ppp_read() */
struct ippp_buf_queue *first; /* pointer to (current) first packet */
struct ippp_buf_queue *last; /* pointer to (current) last used packet in queue */
struct sk_buff_head rq;
wait_queue_head_t wq;
struct task_struct *tk;
unsigned int mpppcfg;
......
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