Commit a1dfdb3b authored by Kai Germaschewski's avatar Kai Germaschewski

ISDN: Alloc isdn_net_dev and struct net_device separately

This a big patch, which now mostly finishes the separation work
of isdn_net_dev, isdn_net_local and struct net_device.
The latter two are allocated per network-layer known network interface,
while isdn_net_dev is the entity which is accessed using isdnctrl,
i.e. a per-channel thing.

Since we allow for channel bundling, isdn_net_local, the priv data of
an ISDN network interface, gets a list of isdn_net_dev's which can be
used for transfering data on that interface.
parent 4b99dcc3
......@@ -24,9 +24,8 @@
* CISCO HDLC keepalive specific stuff
*/
static struct sk_buff*
isdn_net_ciscohdlck_alloc_skb(isdn_net_local *lp, int len)
isdn_net_ciscohdlck_alloc_skb(isdn_net_dev *idev, int len)
{
isdn_net_dev *idev = lp->netdev;
unsigned short hl = isdn_slot_hdrlen(idev->isdn_slot);
struct sk_buff *skb;
......@@ -43,62 +42,59 @@ isdn_net_ciscohdlck_alloc_skb(isdn_net_local *lp, int len)
static int
isdn_ciscohdlck_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
isdn_net_local *lp = (isdn_net_local *) dev->priv;
isdn_net_dev *idev = lp->netdev;
isdn_net_local *mlp = 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 period;
char debserint;
int rc = 0;
if (lp->p_encap != ISDN_NET_ENCAP_CISCOHDLCK)
if (mlp->p_encap != ISDN_NET_ENCAP_CISCOHDLCK)
return -EINVAL;
switch (cmd) {
/* get/set keepalive period */
case SIOCGKEEPPERIOD:
len = (unsigned long)sizeof(lp->cisco_keepalive_period);
len = sizeof(mlp->cisco_keepalive_period);
if (copy_to_user((char *)ifr->ifr_ifru.ifru_data,
(int *)&lp->cisco_keepalive_period, len))
(char *)&mlp->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))
len = sizeof(mlp->cisco_keepalive_period);
if (copy_from_user((char *)&period,
(char *)ifr->ifr_ifru.ifru_data, len)) {
rc = -EFAULT;
if ((period > 0) && (period <= 32767))
lp->cisco_keepalive_period = period;
else
break;
}
if (period <= 0 || period > 32767) {
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",
idev->name, lp->cisco_keepalive_period);
break;
}
mod_timer(&mlp->cisco_timer, jiffies + period * HZ);
printk(KERN_INFO "%s: Keepalive period set "
"to %d seconds.\n", dev->name, period);
mlp->cisco_keepalive_period = period;
break;
/* get/set debugging */
case SIOCGDEBSERINT:
len = (unsigned long)sizeof(lp->cisco_debserint);
len = sizeof(mlp->cisco_debserint);
if (copy_to_user((char *)ifr->ifr_ifru.ifru_data,
(char *)&lp->cisco_debserint, len))
(char *)&mlp->cisco_debserint, len))
rc = -EFAULT;
break;
case SIOCSDEBSERINT:
len = (unsigned long)sizeof(lp->cisco_debserint);
len = sizeof(mlp->cisco_debserint);
if (copy_from_user((char *)&debserint,
(char *)ifr->ifr_ifru.ifru_data, len))
(char *)ifr->ifr_ifru.ifru_data, len)) {
rc = -EFAULT;
if ((debserint >= 0) && (debserint <= 64))
lp->cisco_debserint = debserint;
else
break;
}
if (debserint < 0 || debserint > 64) {
rc = -EINVAL;
break;
}
mlp->cisco_debserint = debserint;
break;
default:
......@@ -112,42 +108,47 @@ isdn_ciscohdlck_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
static void
isdn_net_ciscohdlck_slarp_send_keepalive(unsigned long data)
{
isdn_net_local *lp = (isdn_net_local *) data;
isdn_net_dev *idev = lp->netdev;
isdn_net_local *mlp = (isdn_net_local *) data;
isdn_net_dev *idev;
struct sk_buff *skb;
unsigned char *p;
unsigned long last_cisco_myseq = lp->cisco_myseq;
unsigned long last_cisco_myseq = mlp->cisco_myseq;
int myseq_diff = 0;
lp->cisco_myseq++;
if (list_empty(&mlp->online)) {
isdn_BUG();
return;
}
idev = list_entry(mlp->online.next, isdn_net_dev, online);
mlp->cisco_myseq++;
myseq_diff = (lp->cisco_myseq - lp->cisco_mineseen);
if ((lp->cisco_line_state) && ((myseq_diff >= 3)||(myseq_diff <= -3))) {
myseq_diff = (mlp->cisco_myseq - mlp->cisco_mineseen);
if (mlp->cisco_line_state && (myseq_diff >= 3 || myseq_diff <= -3)) {
/* line up -> down */
lp->cisco_line_state = 0;
mlp->cisco_line_state = 0;
printk (KERN_WARNING
"UPDOWN: Line protocol on Interface %s,"
" changed state to down\n", idev->name);
/* should stop routing higher-level data accross */
} else if ((!lp->cisco_line_state) &&
(myseq_diff >= 0) && (myseq_diff <= 2)) {
} else if (!mlp->cisco_line_state &&
myseq_diff >= 0 && myseq_diff <= 2) {
/* line down -> up */
lp->cisco_line_state = 1;
mlp->cisco_line_state = 1;
printk (KERN_WARNING
"UPDOWN: Line protocol on Interface %s,"
" changed state to up\n", idev->name);
/* restart routing higher-level data accross */
}
if (lp->cisco_debserint)
if (mlp->cisco_debserint)
printk (KERN_DEBUG "%s: HDLC "
"myseq %lu, mineseen %lu%c, yourseen %lu, %s\n",
idev->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");
idev->name, last_cisco_myseq, mlp->cisco_mineseen,
(last_cisco_myseq == mlp->cisco_mineseen) ? '*' : 040,
mlp->cisco_yourseq,
(mlp->cisco_line_state) ? "line up" : "line down");
skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14);
skb = isdn_net_ciscohdlck_alloc_skb(idev, 4 + 14);
if (!skb)
return;
......@@ -160,25 +161,29 @@ isdn_net_ciscohdlck_slarp_send_keepalive(unsigned long data)
/* 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_u32(p, mlp->cisco_myseq);
p += put_u32(p, mlp->cisco_yourseq);
p += put_u16(p, 0xffff); // reliablity, always 0xffff
isdn_net_write_super(idev, skb);
lp->cisco_timer.expires = jiffies + lp->cisco_keepalive_period * HZ;
add_timer(&lp->cisco_timer);
mod_timer(&mlp->cisco_timer, jiffies + mlp->cisco_keepalive_period * HZ);
}
static void
isdn_net_ciscohdlck_slarp_send_request(isdn_net_local *lp)
isdn_net_ciscohdlck_slarp_send_request(isdn_net_local *mlp)
{
isdn_net_dev *idev = lp->netdev;
isdn_net_dev *idev;
struct sk_buff *skb;
unsigned char *p;
skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14);
if (list_empty(&mlp->online)) {
isdn_BUG();
return;
}
idev = list_entry(mlp->online.next, isdn_net_dev, online);
skb = isdn_net_ciscohdlck_alloc_skb(idev, 4 + 14);
if (!skb)
return;
......@@ -199,8 +204,10 @@ isdn_net_ciscohdlck_slarp_send_request(isdn_net_local *lp)
}
static void
isdn_ciscohdlck_connected(isdn_net_local *lp)
isdn_ciscohdlck_connected(isdn_net_dev *idev)
{
isdn_net_local *lp = idev->mlp;
lp->cisco_myseq = 0;
lp->cisco_mineseen = 0;
lp->cisco_yourseq = 0;
......@@ -219,28 +226,30 @@ isdn_ciscohdlck_connected(isdn_net_local *lp)
lp->cisco_timer.expires = jiffies + lp->cisco_keepalive_period * HZ;
add_timer(&lp->cisco_timer);
}
isdn_net_dev_wake_queue(lp->netdev);
netif_wake_queue(&lp->dev);
}
static void
isdn_ciscohdlck_disconnected(isdn_net_local *lp)
isdn_ciscohdlck_disconnected(isdn_net_dev *idev)
{
isdn_net_local *lp = idev->mlp;
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)
isdn_net_ciscohdlck_slarp_send_reply(isdn_net_dev *idev)
{
isdn_net_dev *idev = lp->netdev;
isdn_net_local *mlp = idev->mlp;
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->dev.ip_ptr) != NULL) {
if ((in_dev = mlp->dev.ip_ptr) != NULL) {
/* take primary(first) address of interface */
struct in_ifaddr *ifa = in_dev->ifa_list;
if (ifa != NULL) {
......@@ -249,7 +258,7 @@ isdn_net_ciscohdlck_slarp_send_reply(isdn_net_local *lp)
}
}
skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14);
skb = isdn_net_ciscohdlck_alloc_skb(idev, 4 + 14);
if (!skb)
return;
......@@ -271,9 +280,9 @@ isdn_net_ciscohdlck_slarp_send_reply(isdn_net_local *lp)
}
static void
isdn_net_ciscohdlck_slarp_in(isdn_net_local *lp, struct sk_buff *skb)
isdn_net_ciscohdlck_slarp_in(isdn_net_dev *idev, struct sk_buff *skb)
{
isdn_net_dev *idev = lp->netdev;
isdn_net_local *mlp = idev->mlp;
unsigned char *p;
int period;
u32 code;
......@@ -290,8 +299,8 @@ isdn_net_ciscohdlck_slarp_in(isdn_net_local *lp, struct sk_buff *skb)
switch (code) {
case CISCO_SLARP_REQUEST:
lp->cisco_yourseq = 0;
isdn_net_ciscohdlck_slarp_send_reply(lp);
mlp->cisco_yourseq = 0;
isdn_net_ciscohdlck_slarp_send_reply(idev);
break;
case CISCO_SLARP_REPLY:
addr = ntohl(*(u32 *)p);
......@@ -317,21 +326,21 @@ isdn_net_ciscohdlck_slarp_in(isdn_net_local *lp, struct sk_buff *skb)
HIPQUAD(addr), HIPQUAD(mask));
break;
case CISCO_SLARP_KEEPALIVE:
period = (int)((jiffies - lp->cisco_last_slarp_in
period = (int)((jiffies - mlp->cisco_last_slarp_in
+ HZ/2 - 1) / HZ);
if (lp->cisco_debserint &&
(period != lp->cisco_keepalive_period) &&
lp->cisco_last_slarp_in) {
if (mlp->cisco_debserint &&
(period != mlp->cisco_keepalive_period) &&
mlp->cisco_last_slarp_in) {
printk(KERN_DEBUG "%s: Keepalive period mismatch - "
"is %d but should be %d.\n",
idev->name, period, lp->cisco_keepalive_period);
idev->name, period, mlp->cisco_keepalive_period);
}
lp->cisco_last_slarp_in = jiffies;
mlp->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;
mlp->cisco_yourseq = my_seq;
mlp->cisco_mineseen = your_seq;
break;
}
}
......@@ -363,7 +372,7 @@ isdn_ciscohdlck_receive(isdn_net_local *lp, isdn_net_dev *idev,
switch (type) {
case CISCO_TYPE_SLARP:
isdn_net_ciscohdlck_slarp_in(lp, skb);
isdn_net_ciscohdlck_slarp_in(idev, skb);
goto out_free;
case CISCO_TYPE_CDP:
if (lp->cisco_debserint)
......@@ -372,7 +381,7 @@ isdn_ciscohdlck_receive(isdn_net_local *lp, isdn_net_dev *idev,
goto out_free;
default:
/* no special cisco protocol */
isdn_net_reset_huptimer(lp, idev);
idev->huptimer = 0;
skb->protocol = htons(type);
netif_rx(skb);
return;
......
......@@ -508,7 +508,7 @@ isdn_status_callback(isdn_ctrl * c)
list_for_each(l, &isdn_net_devs) {
isdn_net_dev *p = list_entry(l, isdn_net_dev, global_list);
if (p->isdn_slot == i) {
strcpy(cmd.parm.setup.eazmsn, p->local.msn);
strcpy(cmd.parm.setup.eazmsn, p->mlp->msn);
isdn_slot_command(i, ISDN_CMD_ACCEPTD, &cmd);
retval = 1;
break;
......
......@@ -22,11 +22,11 @@
#undef ISDN_DEBUG_MODEM_DUMP
#undef ISDN_DEBUG_MODEM_VOICE
#undef ISDN_DEBUG_AT
#undef ISDN_DEBUG_NET_DUMP
#undef ISDN_DEBUG_NET_DIAL
#undef ISDN_DEBUG_NET_ICALL
#undef ISDN_DEBUG_STATCALLB
#undef ISDN_DEBUG_COMMAND
#define ISDN_DEBUG_NET_DUMP
#define ISDN_DEBUG_NET_DIAL
#define ISDN_DEBUG_NET_ICALL
#define ISDN_DEBUG_STATCALLB
#define ISDN_DEBUG_COMMAND
#ifdef ISDN_DEBUG_NET_DIAL
#define dbg_net_dial(arg...) printk(KERN_DEBUG arg)
......
......@@ -90,32 +90,20 @@ 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 *idev)
{
struct net_device *dev;
if (idev->master)
dev = &idev->master->dev;
else
dev = &idev->local.dev;
return netif_running(dev);
return netif_running(&idev->mlp->dev);
}
/*
* stop the network -> net_device queue.
* For slaves, stop the corresponding master interface.
*/
static inline void
isdn_net_dev_stop_queue(isdn_net_dev *idev)
{
if (idev->master)
netif_stop_queue(&idev->master->dev);
else
netif_stop_queue(&idev->local.dev);
netif_stop_queue(&idev->mlp->dev);
}
/*
......@@ -126,18 +114,13 @@ isdn_net_dev_stop_queue(isdn_net_dev *idev)
static inline int
isdn_net_device_busy(isdn_net_dev *idev)
{
isdn_net_local *mlp;
isdn_net_local *mlp = idev->mlp;
unsigned long flags;
int retval = 1;
if (!isdn_net_dev_busy(idev))
return 0;
if (idev->master)
mlp = idev->master;
else
mlp = &idev->local;
spin_lock_irqsave(&mlp->online_lock, flags);
list_for_each_entry(idev, &mlp->online, online) {
if (!isdn_net_dev_busy(idev)) {
......@@ -212,9 +195,9 @@ int isdn_net_online(isdn_net_dev *idev)
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);
static int isdn_net_handle_event(isdn_net_local *lp, int pr, void *arg);
static void do_dialout(isdn_net_dev *idev);
static int isdn_net_handle_event(isdn_net_dev *idev, int pr, void *arg);
static int isdn_net_set_encap(isdn_net_local *mlp, int encap);
char *isdn_net_revision = "$Revision: 1.140.6.11 $";
......@@ -260,32 +243,30 @@ isdn_net_open(struct net_device *dev)
* unbind a net-interface (resets interface after an error)
*/
static void
isdn_net_unbind_channel(isdn_net_local * lp)
isdn_net_unbind_channel(isdn_net_dev *idev)
{
isdn_net_dev *idev = lp->netdev;
isdn_net_local *mlp = idev->mlp;
ulong flags;
save_flags(flags);
cli();
if (lp->ops->unbind)
lp->ops->unbind(lp);
if (idev->isdn_slot < 0) {
isdn_BUG();
return;
}
if (mlp->ops->unbind)
mlp->ops->unbind(idev);
skb_queue_purge(&idev->super_tx_queue);
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->dev.qdisc);
}
idev->dialstate = ST_NULL;
if (idev->isdn_slot >= 0) {
isdn_slot_set_rx_netdev(idev->isdn_slot, NULL);
isdn_slot_set_st_netdev(idev->isdn_slot, NULL);
isdn_slot_free(idev->isdn_slot, ISDN_USAGE_NET);
}
isdn_slot_set_rx_netdev(idev->isdn_slot, NULL);
isdn_slot_set_st_netdev(idev->isdn_slot, NULL);
isdn_slot_free(idev->isdn_slot, ISDN_USAGE_NET);
idev->isdn_slot = -1;
restore_flags(flags);
......@@ -295,9 +276,9 @@ isdn_net_unbind_channel(isdn_net_local * lp)
* Assign an ISDN-channel to a net-interface
*/
static int
isdn_net_bind_channel(isdn_net_local *lp, int idx)
isdn_net_bind_channel(isdn_net_dev *idev, int idx)
{
isdn_net_dev *idev = lp->netdev;
isdn_net_local *mlp = idev->mlp;
int retval = 0;
unsigned long flags;
......@@ -305,14 +286,14 @@ isdn_net_bind_channel(isdn_net_local *lp, int idx)
cli();
idev->isdn_slot = idx;
isdn_slot_set_rx_netdev(idev->isdn_slot, lp->netdev);
isdn_slot_set_st_netdev(idev->isdn_slot, lp->netdev);
isdn_slot_set_rx_netdev(idev->isdn_slot, idev);
isdn_slot_set_st_netdev(idev->isdn_slot, idev);
if (lp->ops->bind)
retval = lp->ops->bind(lp);
if (mlp->ops->bind)
retval = mlp->ops->bind(idev);
if (retval < 0)
isdn_net_unbind_channel(lp);
isdn_net_unbind_channel(idev);
restore_flags(flags);
return retval;
......@@ -331,7 +312,7 @@ isdn_net_bind_channel(isdn_net_local *lp, int idx)
static void isdn_net_hup_timer(unsigned long data)
{
isdn_net_dev *idev = (isdn_net_dev *) data;
isdn_net_local *lp = &idev->local;
isdn_net_local *mlp = idev->mlp;
if (!isdn_net_online(idev)) {
isdn_BUG();
......@@ -339,38 +320,38 @@ static void isdn_net_hup_timer(unsigned long data)
}
dbg_net_dial("%s: huptimer %d, onhtime %d, chargetime %ld, chargeint %d\n",
l->name, l->huptimer, l->onhtime, l->chargetime, l->chargeint);
idev->name, idev->huptimer, mlp->onhtime, idev->chargetime, idev->chargeint);
if (lp->onhtime == 0)
if (mlp->onhtime == 0)
return;
if (idev->huptimer++ <= lp->onhtime)
if (idev->huptimer++ <= mlp->onhtime)
goto mod_timer;
if ((lp->hupflags & (ISDN_MANCHARGE | ISDN_CHARGEHUP)) == (ISDN_MANCHARGE | ISDN_CHARGEHUP)) {
if ((mlp->hupflags & (ISDN_MANCHARGE | ISDN_CHARGEHUP)) == (ISDN_MANCHARGE | ISDN_CHARGEHUP)) {
while (time_after(jiffies, idev->chargetime + idev->chargeint))
idev->chargetime += idev->chargeint;
if (time_after(jiffies, idev->chargetime + idev->chargeint - 2 * HZ)) {
if (idev->outgoing || lp->hupflags & ISDN_INHUP) {
if (idev->outgoing || mlp->hupflags & ISDN_INHUP) {
isdn_net_hangup(idev);
return;
}
}
} else if (idev->outgoing) {
if (lp->hupflags & ISDN_CHARGEHUP) {
if (mlp->hupflags & ISDN_CHARGEHUP) {
if (idev->charge_state != ST_CHARGE_HAVE_CINT) {
dbg_net_dial("%s: did not get CINT\n", lp->name);
dbg_net_dial("%s: did not get CINT\n", idev->name);
isdn_net_hangup(idev);
return;
} else if (time_after(jiffies, idev->chargetime + idev->chargeint)) {
dbg_net_dial("%s: chtime = %lu, chint = %d\n",
lp->name, lp->chargetime, lp->chargeint);
idev->name, idev->chargetime, idev->chargeint);
isdn_net_hangup(idev);
return;
}
}
} else if (lp->hupflags & ISDN_INHUP) {
} else if (mlp->hupflags & ISDN_INHUP) {
isdn_net_hangup(idev);
return;
}
......@@ -385,22 +366,15 @@ static void isdn_net_lp_disconnected(isdn_net_dev *idev)
static void isdn_net_connected(isdn_net_dev *idev)
{
isdn_net_local *lp = &idev->local;
isdn_net_local *mlp = idev->mlp;
idev->dialstate = ST_ACTIVE;
idev->hup_timer.expires = jiffies + HZ;
add_timer(&idev->hup_timer);
if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP) {
isdn_net_local *mlp;
if (idev->master)
mlp = idev->master;
else
mlp = &idev->local;
if (mlp->p_encap != ISDN_NET_ENCAP_SYNCPPP)
isdn_net_add_to_bundle(mlp, idev);
}
printk(KERN_INFO "isdn_net: %s connected\n", idev->name);
/* If first Chargeinfo comes before B-Channel connect,
* we correct the timestamp here.
......@@ -415,8 +389,8 @@ static void isdn_net_connected(isdn_net_dev *idev)
idev->cps = 0;
idev->last_jiffies = jiffies;
if (lp->ops->connected)
lp->ops->connected(lp);
if (mlp->ops->connected)
mlp->ops->connected(idev);
else
isdn_net_dev_wake_queue(idev);
}
......@@ -430,17 +404,14 @@ static void isdn_net_connected(isdn_net_dev *idev)
int
isdn_net_stat_callback(int idx, isdn_ctrl *c)
{
isdn_net_dev *p = isdn_slot_st_netdev(idx);
isdn_net_local *lp;
int cmd = c->command;
isdn_net_dev *idev = isdn_slot_st_netdev(idx);
if (!p) {
if (!idev) {
HERE;
return 0;
}
lp = &p->local;
return isdn_net_handle_event(lp, cmd, c);
return isdn_net_handle_event(idev, c->command, c);
}
static void
......@@ -448,27 +419,27 @@ isdn_net_dial_timer(unsigned long data)
{
isdn_net_dev *idev = (isdn_net_dev *) data;
isdn_net_handle_event(&idev->local, idev->dial_event, NULL);
isdn_net_handle_event(idev, idev->dial_event, NULL);
}
/* Initiate dialout. Set phone-number-pointer to first number
* of interface.
*/
static void
init_dialout(isdn_net_local *lp)
init_dialout(isdn_net_dev *idev)
{
isdn_net_dev *idev = lp->netdev;
isdn_net_local *mlp = idev->mlp;
idev->dial = 0;
if (lp->dialtimeout > 0 &&
if (mlp->dialtimeout > 0 &&
(idev->dialstarted == 0 ||
time_after(jiffies, idev->dialstarted + lp->dialtimeout + lp->dialwait))) {
time_after(jiffies, idev->dialstarted + mlp->dialtimeout + mlp->dialwait))) {
idev->dialstarted = jiffies;
idev->dialwait_timer = 0;
}
lp->dialretry = 0;
do_dialout(lp);
idev->dialretry = 0;
do_dialout(idev);
}
/* Setup interface, dial current phone-number, switch to next number.
......@@ -476,54 +447,54 @@ init_dialout(isdn_net_local *lp)
* retry-counter.
*/
static void
do_dialout(isdn_net_local *lp)
do_dialout(isdn_net_dev *idev)
{
isdn_net_dev *idev = lp->netdev;
isdn_net_local *mlp = idev->mlp;
int i;
unsigned long flags;
struct isdn_net_phone *phone;
struct dial_info dial = {
.l2_proto = lp->l2_proto,
.l3_proto = lp->l3_proto,
.l2_proto = mlp->l2_proto,
.l3_proto = mlp->l3_proto,
.si1 = 7,
.si2 = 0,
.msn = lp->msn,
.msn = mlp->msn,
};
if (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF)
if (ISDN_NET_DIALMODE(*mlp) == ISDN_NET_DM_OFF)
return;
spin_lock_irqsave(&lp->lock, flags);
if (list_empty(&lp->phone[1])) {
spin_unlock_irqrestore(&lp->lock, flags);
spin_lock_irqsave(&mlp->lock, flags);
if (list_empty(&mlp->phone[1])) {
spin_unlock_irqrestore(&mlp->lock, flags);
return;
}
i = 0;
list_for_each_entry(phone, &lp->phone[1], list) {
list_for_each_entry(phone, &mlp->phone[1], list) {
if (i++ == idev->dial)
goto found;
}
/* otherwise start in front */
phone = list_entry(lp->phone[1].next, struct isdn_net_phone, list);
phone = list_entry(mlp->phone[1].next, struct isdn_net_phone, list);
idev->dial = 0;
lp->dialretry++;
idev->dialretry++;
found:
idev->dial++;
dial.phone = phone->num;
spin_unlock_irqrestore(&lp->lock, flags);
spin_unlock_irqrestore(&mlp->lock, flags);
if (lp->dialretry > lp->dialmax) {
if (lp->dialtimeout == 0) {
idev->dialwait_timer = jiffies + lp->dialwait;
if (idev->dialretry > mlp->dialmax) {
if (mlp->dialtimeout == 0) {
idev->dialwait_timer = jiffies + mlp->dialwait;
idev->dialstarted = 0;
}
isdn_net_hangup(idev);
return;
}
if(lp->dialtimeout > 0 &&
time_after(jiffies, idev->dialstarted + lp->dialtimeout)) {
idev->dialwait_timer = jiffies + lp->dialwait;
if (mlp->dialtimeout > 0 &&
time_after(jiffies, idev->dialstarted + mlp->dialtimeout)) {
idev->dialwait_timer = jiffies + mlp->dialwait;
idev->dialstarted = 0;
isdn_net_hangup(idev);
return;
......@@ -540,8 +511,8 @@ do_dialout(isdn_net_local *lp)
else
idev->charge_state = ST_CHARGE_NULL;
if (lp->cbdelay && (lp->flags & ISDN_NET_CBOUT)) {
idev->dial_timer.expires = jiffies + lp->cbdelay;
if (mlp->cbdelay && (mlp->flags & ISDN_NET_CBOUT)) {
idev->dial_timer.expires = jiffies + mlp->cbdelay;
idev->dial_event = EV_NET_TIMER_CB;
} else {
idev->dial_timer.expires = jiffies + 10 * HZ;
......@@ -555,13 +526,14 @@ do_dialout(isdn_net_local *lp)
* For ISDN_STAT_*, returns 1 if event was for us
*/
static int
isdn_net_handle_event(isdn_net_local *lp, int pr, void *arg)
isdn_net_handle_event(isdn_net_dev *idev, int pr, void *arg)
{
isdn_net_dev *idev = lp->netdev;
isdn_net_local *mlp = idev->mlp;
isdn_ctrl *c = arg;
isdn_ctrl cmd;
dbg_net_dial("%s: dialstate=%d pr=%#x\n", lp->name, lp->dialstate,pr);
dbg_net_dial("%s: dialstate=%d pr=%#x\n", idev->name,
idev->dialstate, pr);
switch (idev->dialstate) {
case ST_ACTIVE:
......@@ -569,19 +541,19 @@ isdn_net_handle_event(isdn_net_local *lp, int pr, void *arg)
case ISDN_STAT_BSENT:
/* A packet has successfully been sent out */
isdn_net_dec_frame_cnt(idev);
lp->stats.tx_packets++;
lp->stats.tx_bytes += c->parm.length;
mlp->stats.tx_packets++;
mlp->stats.tx_bytes += c->parm.length;
return 1;
case ISDN_STAT_DHUP:
if (lp->ops->disconnected)
lp->ops->disconnected(lp);
if (mlp->ops->disconnected)
mlp->ops->disconnected(idev);
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,
idev->charge);
isdn_net_unbind_channel(lp);
isdn_net_unbind_channel(idev);
return 1;
case ISDN_STAT_CINF:
/* Charge-info from TelCo. Calculate interval between
......@@ -601,7 +573,7 @@ isdn_net_handle_event(isdn_net_local *lp, int pr, void *arg)
break;
}
idev->chargetime = jiffies;
dbg_net_dial("%s: got CINF\n", lp->name);
dbg_net_dial("%s: got CINF\n", idev->name);
return 1;
}
break;
......@@ -609,7 +581,7 @@ isdn_net_handle_event(isdn_net_local *lp, int pr, void *arg)
switch (pr) {
case EV_NET_TIMER_OUT_DCONN:
/* try again */
do_dialout(lp);
do_dialout(idev);
return 1;
case EV_NET_TIMER_CB:
/* Remote does callback. Hangup after cbdelay,
......@@ -630,7 +602,7 @@ isdn_net_handle_event(isdn_net_local *lp, int pr, void *arg)
del_timer(&idev->dial_timer);
isdn_slot_all_eaz(idev->isdn_slot);
printk(KERN_INFO "%s: remote hangup\n", idev->name);
isdn_net_unbind_channel(lp);
isdn_net_unbind_channel(idev);
return 1;
}
break;
......@@ -638,7 +610,7 @@ isdn_net_handle_event(isdn_net_local *lp, int pr, void *arg)
switch (pr) {
case EV_NET_TIMER_OUT_BCONN:
/* try again */
do_dialout(lp);
do_dialout(idev);
return 1;
case ISDN_STAT_BCONN:
del_timer(&idev->dial_timer);
......@@ -649,7 +621,7 @@ isdn_net_handle_event(isdn_net_local *lp, int pr, void *arg)
del_timer(&idev->dial_timer);
isdn_slot_all_eaz(idev->isdn_slot);
printk(KERN_INFO "%s: remote hangup\n", idev->name);
isdn_net_unbind_channel(lp);
isdn_net_unbind_channel(idev);
return 1;
}
break;
......@@ -670,7 +642,7 @@ isdn_net_handle_event(isdn_net_local *lp, int pr, void *arg)
del_timer(&idev->dial_timer);
isdn_slot_all_eaz(idev->isdn_slot);
printk(KERN_INFO "%s: remote hangup\n", idev->name);
isdn_net_unbind_channel(lp);
isdn_net_unbind_channel(idev);
return 1;
}
break;
......@@ -688,7 +660,7 @@ isdn_net_handle_event(isdn_net_local *lp, int pr, void *arg)
del_timer(&idev->dial_timer);
isdn_slot_all_eaz(idev->isdn_slot);
printk(KERN_INFO "%s: remote hangup\n", idev->name);
isdn_net_unbind_channel(lp);
isdn_net_unbind_channel(idev);
return 1;
}
break;
......@@ -696,7 +668,7 @@ isdn_net_handle_event(isdn_net_local *lp, int pr, void *arg)
switch (pr) {
case EV_NET_TIMER_CB:
/* Callback Delay */
init_dialout(lp);
init_dialout(idev);
return 1;
}
break;
......@@ -704,7 +676,7 @@ isdn_net_handle_event(isdn_net_local *lp, int pr, void *arg)
isdn_BUG();
break;
}
printk("NOT HANDLED?\n");
isdn_BUG();
return 0;
}
......@@ -714,7 +686,7 @@ isdn_net_handle_event(isdn_net_local *lp, int pr, void *arg)
void
isdn_net_hangup(isdn_net_dev *idev)
{
isdn_net_local *lp = &idev->local;
isdn_net_local *mlp = idev->mlp;
isdn_ctrl cmd;
del_timer_sync(&idev->hup_timer);
......@@ -732,15 +704,15 @@ isdn_net_hangup(isdn_net_dev *idev)
}
}
printk(KERN_INFO "isdn_net: local hangup %s\n", idev->name);
if (lp->ops->disconnected)
lp->ops->disconnected(lp);
if (mlp->ops->disconnected)
mlp->ops->disconnected(idev);
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);
isdn_slot_all_eaz(idev->isdn_slot);
isdn_net_unbind_channel(lp);
isdn_net_unbind_channel(idev);
}
void
......@@ -760,9 +732,10 @@ typedef struct {
} ip_ports;
static void
isdn_net_log_skb(struct sk_buff * skb, isdn_net_local * lp)
isdn_net_log_skb(struct sk_buff *skb, isdn_net_dev *idev)
{
isdn_net_dev *idev = lp->netdev;
isdn_net_local *mlp = idev->mlp;
u_char *p = skb->nh.raw; /* hopefully, this was set correctly */
unsigned short proto = ntohs(skb->protocol);
int data_ofs;
......@@ -778,7 +751,7 @@ isdn_net_log_skb(struct sk_buff * skb, isdn_net_local * lp)
printk(KERN_DEBUG "isdn_net: protocol %04x is buggy, dev %s\n", skb->protocol, idev->name);
p = buf;
proto = ETH_P_IP;
switch (lp->p_encap) {
switch (mlp->p_encap) {
case ISDN_NET_ENCAP_IPTYP:
proto = ntohs(*(unsigned short *) &buf[0]);
p = &buf[2];
......@@ -892,7 +865,7 @@ static void isdn_net_tasklet(unsigned long data)
*/
void isdn_net_writebuf_skb(isdn_net_dev *idev, struct sk_buff *skb)
{
isdn_net_local *lp = &idev->local;
isdn_net_local *mlp = idev->mlp;
int ret;
int len = skb->len; /* save len */
......@@ -920,7 +893,7 @@ void isdn_net_writebuf_skb(isdn_net_dev *idev, struct sk_buff *skb)
error:
dev_kfree_skb(skb);
lp->stats.tx_errors++;
mlp->stats.tx_errors++;
}
......@@ -938,24 +911,21 @@ void isdn_net_writebuf_skb(isdn_net_dev *idev, struct sk_buff *skb)
static int
isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb)
{
isdn_net_local *mlp;
isdn_net_dev *sdev;
isdn_net_local *lp = ndev->priv;
isdn_net_dev *idev = lp->netdev;
isdn_net_dev *idev, *sdev;
isdn_net_local *mlp = ndev->priv;
int retv = 0;
mlp = ndev->priv;
/* For the other encaps the header has already been built */
if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) {
if (mlp->p_encap == ISDN_NET_ENCAP_SYNCPPP) {
return isdn_ppp_xmit(skb, ndev);
}
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;
}
/* we have our idev locked from now on */
lp = &idev->local;
/* Reset hangup-timeout */
idev->huptimer = 0; // FIXME?
......@@ -975,7 +945,7 @@ isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb)
if (dev->net_verbose > 3)
printk(KERN_DEBUG "%s: %d bogocps\n", idev->name, idev->cps);
if (idev->cps > lp->triggercps) {
if (idev->cps > mlp->triggercps) {
if (idev->slave) {
if (!idev->sqfull) {
/* First time overload: set timestamp only */
......@@ -983,7 +953,7 @@ isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb)
idev->sqfull_stamp = jiffies;
} else {
/* subsequent overload: if slavedelay exceeded, start dialing */
if (time_after(jiffies, idev->sqfull_stamp + lp->slavedelay)) {
if (time_after(jiffies, idev->sqfull_stamp + mlp->slavedelay)) {
sdev = idev->slave;
if (!isdn_net_bound(sdev)) {
isdn_net_force_dial_idev(sdev);
......@@ -992,12 +962,12 @@ isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb)
}
}
} else {
if (idev->sqfull && time_after(jiffies, idev->sqfull_stamp + lp->slavedelay + 10 * HZ)) {
if (idev->sqfull && time_after(jiffies, idev->sqfull_stamp + mlp->slavedelay + 10 * HZ)) {
idev->sqfull = 0;
}
/* this is a hack to allow auto-hangup for slaves on moderate loads */
list_del(&mlp->online);
list_add_tail(&mlp->online, &lp->netdev->online);
list_add_tail(&mlp->online, &idev->online);
}
return retv;
......@@ -1020,29 +990,32 @@ isdn_net_adjust_hdr(struct sk_buff *skb, struct net_device *dev)
}
void isdn_net_tx_timeout(struct net_device * ndev)
void isdn_net_tx_timeout(struct net_device *dev)
{
isdn_net_local *lp = ndev->priv;
isdn_net_dev *idev = lp->netdev;
printk(KERN_WARNING "isdn_tx_timeout dev %s %d\n",
ndev->name, idev->dialstate);
printk(KERN_WARNING "isdn_tx_timeout dev %s\n", dev->name);
netif_wake_queue(ndev);
netif_wake_queue(dev);
}
static int
isdn_net_autodial(struct sk_buff *skb, struct net_device *ndev)
{
isdn_net_local *lp = ndev->priv;
isdn_net_dev *idev = lp->netdev;
isdn_net_local *mlp = ndev->priv;
isdn_net_dev *idev = list_entry(mlp->slaves.next, isdn_net_dev, slaves);
if (!(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_AUTO))
/* are we dialing already? */
if (isdn_net_bound(idev)) {
netif_stop_queue(ndev);
return 1;
}
if (ISDN_NET_DIALMODE(*mlp) != ISDN_NET_DM_AUTO)
goto discard;
if (idev->dialwait_timer <= 0)
if (idev->dialstarted > 0 && lp->dialtimeout > 0 && time_before(jiffies, idev->dialstarted + lp->dialtimeout + lp->dialwait))
idev->dialwait_timer = idev->dialstarted + lp->dialtimeout + lp->dialwait;
if (idev->dialstarted > 0 && mlp->dialtimeout > 0 &&
time_before(jiffies, idev->dialstarted + mlp->dialtimeout + mlp->dialwait))
idev->dialwait_timer = idev->dialstarted + mlp->dialtimeout + mlp->dialwait;
if (idev->dialwait_timer > 0) {
if(time_before(jiffies, idev->dialwait_timer))
......@@ -1056,7 +1029,7 @@ isdn_net_autodial(struct sk_buff *skb, struct net_device *ndev)
/* Log packet, which triggered dialing */
if (dev->net_verbose)
isdn_net_log_skb(skb, lp);
isdn_net_log_skb(skb, idev);
netif_stop_queue(ndev);
return 1;
......@@ -1076,27 +1049,22 @@ isdn_net_autodial(struct sk_buff *skb, struct net_device *ndev)
static int
isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
{
isdn_net_local *lp = ndev->priv;
isdn_net_dev *idev = lp->netdev;
isdn_net_local *mlp = ndev->priv;
int retval;
if (lp->p_encap == ISDN_NET_ENCAP_X25IFACE)
if (mlp->p_encap == ISDN_NET_ENCAP_X25IFACE)
return isdn_x25_start_xmit(skb, ndev);
/* auto-dialing xmit function */
isdn_net_adjust_hdr(skb, ndev);
isdn_dumppkt("S:", skb->data, skb->len, 40);
if (!isdn_net_bound(idev))
if (list_empty(&mlp->online))
return isdn_net_autodial(skb, ndev);
/* Device is bound to an ISDN channel */
ndev->trans_start = jiffies;
if (idev->dialstate != ST_ACTIVE) {
netif_stop_queue(ndev);
return 1;
}
/* ISDN connection is established, try sending */
retval = isdn_net_xmit(ndev, skb);
if (retval)
......@@ -1111,19 +1079,19 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
static int
isdn_net_close(struct net_device *dev)
{
isdn_net_local *lp = dev->priv;
isdn_net_dev *idev = lp->netdev;
isdn_net_local *mlp = dev->priv;
struct list_head *l, *n;
isdn_net_dev *sdev;
if (lp->ops->close)
lp->ops->close(lp);
if (mlp->ops->close)
mlp->ops->close(mlp);
netif_stop_queue(dev);
for (sdev = idev->slave; sdev; sdev = sdev->slave)
isdn_net_hangup(sdev);
isdn_net_hangup(idev);
list_for_each_safe(l, n, &mlp->online) {
sdev = list_entry(l, isdn_net_dev, online);
isdn_net_hangup(sdev);
}
isdn_MOD_DEC_USE_COUNT();
return 0;
}
......@@ -1144,27 +1112,18 @@ isdn_net_get_stats(struct net_device *dev)
static void
isdn_net_receive(isdn_net_dev *idev, struct sk_buff *skb)
{
isdn_net_local *lp;
struct net_device *ndev;
isdn_net_local *mlp = idev->mlp;
idev->transcount += skb->len;
if (idev->master) {
/* Bundling: If device is a slave-device, deliver to master, also
* handle master's statistics and hangup-timeout
*/
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;
mlp->stats.rx_packets++;
mlp->stats.rx_bytes += skb->len;
skb->dev = &mlp->dev;
skb->pkt_type = PACKET_HOST;
skb->mac.raw = skb->data;
isdn_dumppkt("R:", skb->data, skb->len, 40);
lp->ops->receive(lp, idev, skb);
mlp->ops->receive(mlp, idev, skb);
}
/*
......@@ -1207,16 +1166,16 @@ isdn_net_init(struct net_device *ndev)
}
static int
isdn_net_do_callback(isdn_net_local *lp)
isdn_net_do_callback(isdn_net_dev *idev)
{
isdn_net_dev *idev = lp->netdev;
isdn_net_local *mlp = idev->mlp;
int slot;
/*
* Is the state MANUAL?
* If so, no callback can be made,
* so reject actively.
*/
if (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF) {
if (ISDN_NET_DIALMODE(*mlp) == ISDN_NET_DM_OFF) {
printk(KERN_INFO "incoming call for callback, interface %s `off' -> rejected\n",
idev->name);
return 3;
......@@ -1224,22 +1183,22 @@ isdn_net_do_callback(isdn_net_local *lp)
printk(KERN_DEBUG "%s: start callback\n", idev->name);
/* Grab a free ISDN-Channel */
slot = isdn_get_free_slot(ISDN_USAGE_NET, lp->l2_proto, lp->l3_proto,
idev->pre_device, idev->pre_channel, lp->msn);
slot = isdn_get_free_slot(ISDN_USAGE_NET, mlp->l2_proto, mlp->l3_proto,
idev->pre_device, idev->pre_channel, mlp->msn);
if (slot < 0)
goto err;
if (isdn_net_bind_channel(lp, slot) < 0)
if (isdn_net_bind_channel(idev, slot) < 0)
goto err;
/* Setup dialstate. */
idev->dial_timer.expires = jiffies + lp->cbdelay;
idev->dial_timer.expires = jiffies + mlp->cbdelay;
idev->dial_event = EV_NET_TIMER_CB;
add_timer(&idev->dial_timer);
idev->dialstate = ST_WAIT_BEFORE_CB;
/* Initiate dialing by returning 2 or 4 */
return (lp->flags & ISDN_NET_CBHUP) ? 2 : 4;
return (mlp->flags & ISDN_NET_CBHUP) ? 2 : 4;
err:
return 0;
......@@ -1267,12 +1226,12 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
char *eaz;
unsigned char si1, si2;
int match_more = 0;
int retval;
struct list_head *l;
struct isdn_net_phone *n;
ulong flags;
char nr[32];
char *my_eaz;
int retval;
isdn_ctrl cmd;
int slot = isdn_dc2minor(di, ch);
......@@ -1311,13 +1270,13 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
list_for_each(l, &isdn_net_devs) {
isdn_net_dev *idev = list_entry(l, isdn_net_dev, global_list);
isdn_net_local *lp = &idev->local;
isdn_net_local *mlp = idev->mlp;
/* check acceptable call types for DOV */
dbg_net_icall("n_fi: if='%s', l.msn=%s, l.flags=%d, l.dstate=%d\n",
lp->name, lp->msn, lp->flags, lp->dialstate);
dbg_net_icall("n_fi: if='%s', l.msn=%s, l.flags=%#x, l.dstate=%d\n",
idev->name, mlp->msn, mlp->flags, idev->dialstate);
my_eaz = isdn_slot_map_eaz2msn(slot, lp->msn);
my_eaz = isdn_slot_map_eaz2msn(slot, mlp->msn);
if (si1 == 1) { /* it's a DOV call, check if we allow it */
if (*my_eaz == 'v' || *my_eaz == 'V' ||
*my_eaz == 'b' || *my_eaz == 'B')
......@@ -1344,7 +1303,7 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
continue;
dbg_net_icall("n_fi: match1, pdev=%d pch=%d\n",
lp->pre_device, lp->pre_channel);
idev->pre_device, idev->pre_channel);
if (isdn_slot_usage(idx) & ISDN_USAGE_EXCLUSIVE &&
(idev->pre_channel != ch || idev->pre_device != di)) {
......@@ -1352,15 +1311,15 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
continue;
}
dbg_net_icall("n_fi: match2\n");
if (lp->flags & ISDN_NET_SECURE) {
spin_lock_irqsave(&lp->lock, flags);
list_for_each_entry(n, &lp->phone[0], list) {
if (mlp->flags & ISDN_NET_SECURE) {
spin_lock_irqsave(&mlp->lock, flags);
list_for_each_entry(n, &mlp->phone[0], list) {
if (!isdn_msncmp(nr, n->num)) {
spin_unlock_irqrestore(&lp->lock, flags);
spin_unlock_irqrestore(&mlp->lock, flags);
goto found;
}
}
spin_unlock_irqrestore(&lp->lock, flags);
spin_unlock_irqrestore(&mlp->lock, flags);
continue;
}
found:
......@@ -1372,7 +1331,7 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
* If so, no dialin is allowed,
* so reject actively.
* */
if (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF) {
if (ISDN_NET_DIALMODE(*mlp) == ISDN_NET_DM_OFF) {
restore_flags(flags);
printk(KERN_INFO "incoming call, interface %s `stopped' -> rejected\n",
idev->name);
......@@ -1388,41 +1347,18 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
idev->name);
return 3;
}
/* 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 (idev->master) {
isdn_net_dev *pdev = idev->master->netdev;
printk(KERN_DEBUG "ICALLslv: %s\n", idev->name);
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 (pdev->slave) {
if (pdev->slave == idev)
break;
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(pdev));
if (!isdn_net_bound(pdev)) {
continue;
}
}
if (lp->flags & ISDN_NET_CALLBACK) {
retval = isdn_net_do_callback(lp);
restore_flags(flags);
return retval;
}
printk(KERN_DEBUG "%s: call from %s -> %s accepted\n", idev->name,
nr, eaz);
if (mlp->flags & ISDN_NET_CALLBACK) {
retval = isdn_net_do_callback(idev);
restore_flags(flags);
return retval;
}
printk(KERN_DEBUG "%s: call from %s -> %s accepted\n",
idev->name, nr, eaz);
strcpy(isdn_slot_num(idx), nr);
isdn_slot_set_usage(idx, (isdn_slot_usage(idx) & ISDN_USAGE_EXCLUSIVE) | ISDN_USAGE_NET);
isdn_net_bind_channel(lp, idx);
isdn_net_bind_channel(idev, idx);
idev->outgoing = 0;
idev->huptimer = 0;
......@@ -1430,9 +1366,9 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
/* Got incoming Call, setup L2 and L3 protocols,
* then wait for D-Channel-connect
*/
cmd.arg = lp->l2_proto << 8;
cmd.arg = mlp->l2_proto << 8;
isdn_slot_command(idev->isdn_slot, ISDN_CMD_SETL2, &cmd);
cmd.arg = lp->l3_proto << 8;
cmd.arg = mlp->l3_proto << 8;
isdn_slot_command(idev->isdn_slot, ISDN_CMD_SETL3, &cmd);
idev->dial_timer.expires = jiffies + 15 * HZ;
......@@ -1455,12 +1391,11 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
isdn_net_dev *
isdn_net_findif(char *name)
{
struct list_head *l;
isdn_net_dev *idev;
list_for_each(l, &isdn_net_devs) {
isdn_net_dev *p = list_entry(l, isdn_net_dev, global_list);
if (!strcmp(p->name, name))
return p;
list_for_each_entry(idev, &isdn_net_devs, global_list) {
if (!strcmp(idev->name, name))
return idev;
}
return NULL;
}
......@@ -1475,7 +1410,7 @@ isdn_net_force_dial_idev(isdn_net_dev *idev)
{
int slot;
unsigned long flags;
isdn_net_local *lp = &idev->local;
isdn_net_local *mlp = idev->mlp;
if (isdn_net_bound(idev))
return -EBUSY;
......@@ -1486,18 +1421,18 @@ isdn_net_force_dial_idev(isdn_net_dev *idev)
if (idev->exclusive >= 0)
slot = idev->exclusive;
else
slot = isdn_get_free_slot(ISDN_USAGE_NET, lp->l2_proto,
lp->l3_proto, idev->pre_device,
idev->pre_channel, lp->msn);
slot = isdn_get_free_slot(ISDN_USAGE_NET, mlp->l2_proto,
mlp->l3_proto, idev->pre_device,
idev->pre_channel, mlp->msn);
if (slot < 0)
goto err;
if (isdn_net_bind_channel(lp, slot) < 0)
if (isdn_net_bind_channel(idev, slot) < 0)
goto err;;
/* Initiate dialing */
restore_flags(flags);
init_dialout(lp);
init_dialout(idev);
return 0;
......@@ -1514,9 +1449,10 @@ isdn_net_force_dial_idev(isdn_net_dev *idev)
int
isdn_net_dial_req(isdn_net_dev *idev)
{
isdn_net_local *lp = &idev->local;
isdn_net_local *mlp = idev->mlp;
/* is there a better error code? */
if (!(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_AUTO)) return -EBUSY;
if (ISDN_NET_DIALMODE(*mlp) != ISDN_NET_DM_AUTO)
return -EBUSY;
return isdn_net_force_dial_idev(idev);
}
......@@ -1540,10 +1476,9 @@ isdn_net_force_dial(char *name)
* Allocate a new network-interface and initialize its data structures.
*/
int
isdn_net_new(char *name, struct net_device *master)
isdn_net_new(char *name, isdn_net_local *mlp)
{
int retval;
isdn_net_local *mlp = master->priv;
isdn_net_dev *netdev;
/* Avoid creating an existing interface */
......@@ -1551,46 +1486,62 @@ isdn_net_new(char *name, struct net_device *master)
printk(KERN_WARNING "isdn_net: interface %s already exists\n", name);
return -EEXIST;
}
if (!(netdev = kmalloc(sizeof(isdn_net_dev), GFP_KERNEL))) {
if (!(netdev = kmalloc(sizeof(*netdev), GFP_KERNEL))) {
printk(KERN_WARNING "isdn_net: Could not allocate net-device\n");
return -ENOMEM;
}
memset(netdev, 0, sizeof(isdn_net_dev));
memset(netdev, 0, sizeof(*netdev));
strcpy(netdev->name, name);
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 */
isdn_net_dev *p = mlp->netdev;
while (p->slave)
p = p->slave;
p->slave = netdev;
} else {
if (!mlp) {
/* Device shall be a master */
/*
* Watchdog timer (currently) for master only.
*/
netdev->local.dev.tx_timeout = isdn_net_tx_timeout;
netdev->local.dev.watchdog_timeo = ISDN_NET_TX_TIMEOUT;
retval = register_netdev(&netdev->local.dev);
mlp = kmalloc(sizeof(*mlp), GFP_KERNEL);
if (!mlp)
return -ENOMEM;
memset(mlp, 0, sizeof(*mlp));
mlp->magic = ISDN_NET_MAGIC;
mlp->dev.tx_timeout = isdn_net_tx_timeout;
mlp->dev.watchdog_timeo = ISDN_NET_TX_TIMEOUT;
strcpy(mlp->dev.name, name);
mlp->dev.priv = mlp;
mlp->dev.init = isdn_net_init;
INIT_LIST_HEAD(&mlp->slaves);
INIT_LIST_HEAD(&mlp->online);
spin_lock_init(&mlp->lock);
mlp->p_encap = -1;
mlp->l2_proto = ISDN_PROTO_L2_X75I;
mlp->l3_proto = ISDN_PROTO_L3_TRANS;
mlp->triggercps = 6000;
mlp->slavedelay = 10 * HZ;
mlp->hupflags = ISDN_INHUP; /* Do hangup even on incoming calls */
mlp->onhtime = 10; /* Default hangup-time for saving costs
of those who forget configuring this */
mlp->dialmax = 1;
mlp->flags = ISDN_NET_CBHUP | ISDN_NET_DM_MANUAL; /* Hangup before Callback, manual dial */
mlp->cbdelay = 5 * HZ; /* Wait 5 secs before Callback */
mlp->dialtimeout = -1; /* Infinite Dial-Timeout */
mlp->dialwait = 5 * HZ; /* Wait 5 sec. after failed dial */
spin_lock_init(&mlp->lock);
INIT_LIST_HEAD(&mlp->phone[0]);
INIT_LIST_HEAD(&mlp->phone[1]);
isdn_net_set_encap(mlp, ISDN_NET_ENCAP_RAWIP);
retval = register_netdev(&mlp->dev);
if (retval) {
printk(KERN_WARNING "isdn_net: Could not register net-device\n");
kfree(netdev);
return retval;
}
}
netdev->local.magic = ISDN_NET_MAGIC;
INIT_LIST_HEAD(&netdev->local.online);
spin_lock_init(&netdev->local.online_lock);
netdev->local.netdev = netdev;
netdev->mlp = mlp;
list_add_tail(&netdev->slaves, &mlp->slaves);
tasklet_init(&netdev->tlet, isdn_net_tasklet, (unsigned long) netdev);
spin_lock_init(&netdev->xmit_lock);
skb_queue_head_init(&netdev->super_tx_queue);
netdev->isdn_slot = -1;
netdev->pre_device = -1;
......@@ -1600,20 +1551,6 @@ isdn_net_new(char *name, struct net_device *master)
netdev->ppp_slot = -1;
netdev->pppbind = -1;
netdev->local.p_encap = -1;
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;
netdev->local.slavedelay = 10 * HZ;
netdev->local.hupflags = ISDN_INHUP; /* Do hangup even on incoming calls */
netdev->local.onhtime = 10; /* Default hangup-time for saving costs
of those who forget configuring this */
netdev->local.dialmax = 1;
netdev->local.flags = ISDN_NET_CBHUP | ISDN_NET_DM_MANUAL; /* Hangup before Callback, manual dial */
netdev->local.cbdelay = 5 * HZ; /* Wait 5 secs before Callback */
netdev->local.dialtimeout = -1; /* Infinite Dial-Timeout */
netdev->local.dialwait = 5 * HZ; /* Wait 5 sec. after failed dial */
netdev->dialstarted = 0; /* Jiffies of last dial-start */
netdev->dialwait_timer = 0; /* Jiffies of earliest next dial-start */
......@@ -1623,10 +1560,6 @@ isdn_net_new(char *name, struct net_device *master)
init_timer(&netdev->hup_timer);
netdev->hup_timer.data = (unsigned long) netdev;
netdev->hup_timer.function = isdn_net_hup_timer;
spin_lock_init(&netdev->local.lock);
INIT_LIST_HEAD(&netdev->local.phone[0]);
INIT_LIST_HEAD(&netdev->local.phone[1]);
isdn_net_set_encap(netdev, ISDN_NET_ENCAP_RAWIP);
/* Put into to netdev-chain */
list_add(&netdev->global_list, &isdn_net_devs);
......@@ -1647,20 +1580,16 @@ isdn_net_newslave(char *parm)
/* Master must already exist */
if (!(m = isdn_net_findif(parm)))
return -ESRCH;
/* Master must be a real interface, not a slave */
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->local.dev);
return isdn_net_new(p+1, m->mlp);
}
static int
isdn_net_set_encap(isdn_net_dev *idev, int encap)
isdn_net_set_encap(isdn_net_local *lp, int encap)
{
isdn_net_local *lp = &idev->local;
int retval = 0;
if (lp->p_encap == encap){
......@@ -1668,7 +1597,7 @@ isdn_net_set_encap(isdn_net_dev *idev, int encap)
retval = 0;
goto out;
}
if (isdn_net_device_started(idev)) {
if (netif_running(&lp->dev)) {
retval = -EBUSY;
goto out;
}
......@@ -1704,7 +1633,7 @@ isdn_net_set_encap(isdn_net_dev *idev, int encap)
static int
isdn_net_bind(isdn_net_dev *idev, isdn_net_ioctl_cfg *cfg)
{
isdn_net_local *lp = &idev->local;
isdn_net_local *mlp = idev->mlp;
int i, retval;
int drvidx = -1;
int chidx = -1;
......@@ -1755,8 +1684,8 @@ isdn_net_bind(isdn_net_dev *idev, isdn_net_ioctl_cfg *cfg)
}
if (cfg->exclusive) {
/* If binding is exclusive, try to grab the channel */
idev->exclusive = isdn_get_free_slot(ISDN_USAGE_NET, lp->l2_proto,
lp->l3_proto, drvidx, chidx, cfg->eaz);
idev->exclusive = isdn_get_free_slot(ISDN_USAGE_NET, mlp->l2_proto,
mlp->l3_proto, drvidx, chidx, cfg->eaz);
if (idev->exclusive < 0) {
/* Grab failed, because desired channel is in use */
retval = -EBUSY;
......@@ -1782,7 +1711,7 @@ int
isdn_net_setcfg(isdn_net_ioctl_cfg *cfg)
{
isdn_net_dev *idev = isdn_net_findif(cfg->name);
isdn_net_local *lp = &idev->local;
isdn_net_local *mlp = idev->mlp;
ulong features;
int i, retval;
......@@ -1804,7 +1733,7 @@ isdn_net_setcfg(isdn_net_ioctl_cfg *cfg)
goto out;
}
retval = isdn_net_set_encap(idev, cfg->p_encap);
retval = isdn_net_set_encap(mlp, cfg->p_encap);
if (retval)
goto out;
......@@ -1812,64 +1741,64 @@ isdn_net_setcfg(isdn_net_ioctl_cfg *cfg)
if (retval)
goto out;
strncpy(lp->msn, cfg->eaz, ISDN_MSNLEN-1);
lp->msn[ISDN_MSNLEN-1] = 0;
lp->onhtime = cfg->onhtime;
strncpy(mlp->msn, cfg->eaz, ISDN_MSNLEN-1);
mlp->msn[ISDN_MSNLEN-1] = 0;
mlp->onhtime = cfg->onhtime;
idev->charge = cfg->charge;
lp->l2_proto = cfg->l2_proto;
lp->l3_proto = cfg->l3_proto;
lp->cbdelay = cfg->cbdelay * HZ / 5;
lp->dialmax = cfg->dialmax;
lp->triggercps = cfg->triggercps;
lp->slavedelay = cfg->slavedelay * HZ;
mlp->l2_proto = cfg->l2_proto;
mlp->l3_proto = cfg->l3_proto;
mlp->cbdelay = cfg->cbdelay * HZ / 5;
mlp->dialmax = cfg->dialmax;
mlp->triggercps = cfg->triggercps;
mlp->slavedelay = cfg->slavedelay * HZ;
idev->pppbind = cfg->pppbind;
lp->dialtimeout = cfg->dialtimeout >= 0 ? cfg->dialtimeout * HZ : -1;
lp->dialwait = cfg->dialwait * HZ;
mlp->dialtimeout = cfg->dialtimeout >= 0 ? cfg->dialtimeout * HZ : -1;
mlp->dialwait = cfg->dialwait * HZ;
if (cfg->secure)
lp->flags |= ISDN_NET_SECURE;
mlp->flags |= ISDN_NET_SECURE;
else
lp->flags &= ~ISDN_NET_SECURE;
mlp->flags &= ~ISDN_NET_SECURE;
if (cfg->cbhup)
lp->flags |= ISDN_NET_CBHUP;
mlp->flags |= ISDN_NET_CBHUP;
else
lp->flags &= ~ISDN_NET_CBHUP;
mlp->flags &= ~ISDN_NET_CBHUP;
switch (cfg->callback) {
case 0:
lp->flags &= ~(ISDN_NET_CALLBACK | ISDN_NET_CBOUT);
mlp->flags &= ~(ISDN_NET_CALLBACK | ISDN_NET_CBOUT);
break;
case 1:
lp->flags |= ISDN_NET_CALLBACK;
lp->flags &= ~ISDN_NET_CBOUT;
mlp->flags |= ISDN_NET_CALLBACK;
mlp->flags &= ~ISDN_NET_CBOUT;
break;
case 2:
lp->flags |= ISDN_NET_CBOUT;
lp->flags &= ~ISDN_NET_CALLBACK;
mlp->flags |= ISDN_NET_CBOUT;
mlp->flags &= ~ISDN_NET_CALLBACK;
break;
}
lp->flags &= ~ISDN_NET_DIALMODE_MASK; /* first all bits off */
mlp->flags &= ~ISDN_NET_DIALMODE_MASK; /* first all bits off */
if (cfg->dialmode && !(cfg->dialmode & ISDN_NET_DIALMODE_MASK)) {
retval = -EINVAL;
goto out;
}
lp->flags |= cfg->dialmode; /* turn on selected bits */
if (lp->flags & ISDN_NET_DM_OFF)
mlp->flags |= cfg->dialmode; /* turn on selected bits */
if (mlp->flags & ISDN_NET_DM_OFF)
isdn_net_hangup(idev);
if (cfg->chargehup)
lp->hupflags |= ISDN_CHARGEHUP;
mlp->hupflags |= ISDN_CHARGEHUP;
else
lp->hupflags &= ~ISDN_CHARGEHUP;
mlp->hupflags &= ~ISDN_CHARGEHUP;
if (cfg->ihup)
lp->hupflags |= ISDN_INHUP;
mlp->hupflags |= ISDN_INHUP;
else
lp->hupflags &= ~ISDN_INHUP;
mlp->hupflags &= ~ISDN_INHUP;
if (cfg->chargeint > 10) {
idev->chargeint = cfg->chargeint * HZ;
idev->charge_state = ST_CHARGE_HAVE_CINT;
lp->hupflags |= ISDN_MANCHARGE;
mlp->hupflags |= ISDN_MANCHARGE;
}
retval = 0;
......@@ -1884,48 +1813,51 @@ int
isdn_net_getcfg(isdn_net_ioctl_cfg * cfg)
{
isdn_net_dev *idev = isdn_net_findif(cfg->name);
isdn_net_local *lp = &idev->local;
isdn_net_local *mlp;
if (!idev)
return -ENODEV;
strcpy(cfg->eaz, lp->msn);
mlp = idev->mlp;
strcpy(cfg->eaz, mlp->msn);
cfg->exclusive = idev->exclusive >= 0;
if (idev->pre_device >= 0) {
sprintf(cfg->drvid, "%s,%d", dev->drvid[idev->pre_device],
idev->pre_channel);
} else
cfg->drvid[0] = '\0';
cfg->onhtime = lp->onhtime;
cfg->onhtime = mlp->onhtime;
cfg->charge = idev->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->l2_proto = mlp->l2_proto;
cfg->l3_proto = mlp->l3_proto;
cfg->p_encap = mlp->p_encap;
cfg->secure = (mlp->flags & ISDN_NET_SECURE) ? 1 : 0;
cfg->callback = 0;
if (lp->flags & ISDN_NET_CALLBACK)
if (mlp->flags & ISDN_NET_CALLBACK)
cfg->callback = 1;
if (lp->flags & ISDN_NET_CBOUT)
if (mlp->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 & ISDN_CHARGEHUP) ? 1 : 0;
cfg->ihup = (lp->hupflags & ISDN_INHUP) ? 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) ?
cfg->cbhup = (mlp->flags & ISDN_NET_CBHUP) ? 1 : 0;
cfg->dialmode = mlp->flags & ISDN_NET_DIALMODE_MASK;
cfg->chargehup = (mlp->hupflags & ISDN_CHARGEHUP) ? 1 : 0;
cfg->ihup = (mlp->hupflags & ISDN_INHUP) ? 1 : 0;
cfg->cbdelay = mlp->cbdelay * 5 / HZ;
cfg->dialmax = mlp->dialmax;
cfg->triggercps = mlp->triggercps;
cfg->slavedelay = mlp->slavedelay / HZ;
cfg->chargeint = (mlp->hupflags & ISDN_CHARGEHUP) ?
(idev->chargeint / HZ) : 0;
cfg->pppbind = idev->pppbind;
cfg->dialtimeout = lp->dialtimeout >= 0 ? lp->dialtimeout / HZ : -1;
cfg->dialwait = lp->dialwait / HZ;
if (idev->slave)
strcpy(cfg->slave, idev->slave->name);
cfg->dialtimeout = mlp->dialtimeout >= 0 ? mlp->dialtimeout / HZ : -1;
cfg->dialwait = mlp->dialwait / HZ;
if (idev->slaves.next != &mlp->slaves)
strcpy(cfg->slave, list_entry(idev->slaves.next, isdn_net_dev, slaves)->name);
else
cfg->slave[0] = '\0';
if (idev->master)
strcpy(cfg->master, idev->master->netdev->name);
if (strcmp(mlp->dev.name, idev->name))
strcpy(cfg->master, mlp->dev.name);
else
cfg->master[0] = '\0';
......@@ -1938,11 +1870,12 @@ isdn_net_getcfg(isdn_net_ioctl_cfg * cfg)
int
isdn_net_addphone(isdn_net_ioctl_phone * phone)
{
isdn_net_dev *p = isdn_net_findif(phone->name);
isdn_net_dev *idev = isdn_net_findif(phone->name);
isdn_net_local *mlp;
unsigned long flags;
struct isdn_net_phone *n;
if (!p)
if (!idev)
return -ENODEV;
n = kmalloc(sizeof(*n), GFP_KERNEL);
......@@ -1950,9 +1883,10 @@ isdn_net_addphone(isdn_net_ioctl_phone * phone)
return -ENOMEM;
strcpy(n->num, phone->phone);
spin_lock_irqsave(&p->local.lock, flags);
list_add_tail(&n->list, &p->local.phone[phone->outgoing & 1]);
spin_unlock_irqrestore(&p->local.lock, flags);
mlp = idev->mlp;
spin_lock_irqsave(&mlp->lock, flags);
list_add_tail(&n->list, &mlp->phone[phone->outgoing & 1]);
spin_unlock_irqrestore(&mlp->lock, flags);
return 0;
}
......@@ -1963,29 +1897,31 @@ isdn_net_addphone(isdn_net_ioctl_phone * phone)
int
isdn_net_getphones(isdn_net_ioctl_phone * phone, char *phones)
{
isdn_net_dev *p = isdn_net_findif(phone->name);
isdn_net_dev *idev = isdn_net_findif(phone->name);
isdn_net_local *mlp;
unsigned long flags;
int inout = phone->outgoing & 1;
int count = 0;
char *buf = (char *)__get_free_page(GFP_KERNEL);
struct isdn_net_phone *n;
if (!p)
if (!idev)
return -ENODEV;
if (!buf)
return -ENOMEM;
mlp = idev->mlp;
inout &= 1;
spin_lock_irqsave(&p->local.lock, flags);
list_for_each_entry(n, &p->local.phone[inout], list) {
spin_lock_irqsave(&mlp->lock, flags);
list_for_each_entry(n, &mlp->phone[inout], list) {
strcpy(&buf[count], n->num);
count += strlen(n->num);
buf[count++] = ' ';
if (count > PAGE_SIZE - ISDN_MSNLEN - 1)
break;
}
spin_unlock_irqrestore(&p->local.lock, flags);
spin_unlock_irqrestore(&mlp->lock, flags);
if (!count)
count++;
......@@ -2030,18 +1966,20 @@ isdn_net_getpeer(isdn_net_ioctl_phone *phone, isdn_net_ioctl_phone *peer)
int
isdn_net_delphone(isdn_net_ioctl_phone * phone)
{
isdn_net_dev *p = isdn_net_findif(phone->name);
isdn_net_dev *idev = isdn_net_findif(phone->name);
isdn_net_local *mlp;
int inout = phone->outgoing & 1;
struct isdn_net_phone *n;
unsigned long flags;
int retval;
if (!p)
if (!idev)
return -ENODEV;
mlp = idev->mlp;
retval = -EINVAL;
spin_lock_irqsave(&p->local.lock, flags);
list_for_each_entry(n, &p->local.phone[inout], list) {
spin_lock_irqsave(&mlp->lock, flags);
list_for_each_entry(n, &mlp->phone[inout], list) {
if (!strcmp(n->num, phone->phone)) {
list_del(&n->list);
kfree(n);
......@@ -2049,7 +1987,7 @@ isdn_net_delphone(isdn_net_ioctl_phone * phone)
break;
}
}
spin_unlock_irqrestore(&p->local.lock, flags);
spin_unlock_irqrestore(&mlp->lock, flags);
return retval;
}
......@@ -2057,21 +1995,22 @@ isdn_net_delphone(isdn_net_ioctl_phone * phone)
* Delete all phone-numbers of an interface.
*/
static int
isdn_net_rmallphone(isdn_net_dev * p)
isdn_net_rmallphone(isdn_net_dev *idev)
{
isdn_net_local *mlp = idev->mlp;
struct isdn_net_phone *n;
unsigned long flags;
int i;
spin_lock_irqsave(&p->local.lock, flags);
spin_lock_irqsave(&mlp->lock, flags);
for (i = 0; i < 2; i++) {
while (!list_empty(&p->local.phone[i])) {
n = list_entry(p->local.phone[i].next, struct isdn_net_phone, list);
while (!list_empty(&mlp->phone[i])) {
n = list_entry(mlp->phone[i].next, struct isdn_net_phone, list);
list_del(&n->list);
kfree(n);
}
}
spin_lock_irqsave(&p->local.lock, flags);
spin_lock_irqsave(&mlp->lock, flags);
return 0;
}
......@@ -2114,35 +2053,21 @@ isdn_net_realrm(isdn_net_dev *p)
restore_flags(flags);
return -EBUSY;
}
isdn_net_set_encap(p, -1);
isdn_net_set_encap(p->mlp, -1);
/* Free all phone-entries */
isdn_net_rmallphone(p);
/* If interface is bound exclusive, free channel-usage */
if (p->exclusive >= 0)
isdn_unexclusive_channel(p->pre_device, p->pre_channel);
if (p->master) {
/* It's a slave-device, so update master's slave-pointer if necessary */
if (p->master->netdev->slave == p)
p->master->netdev->slave = p->slave;
} else {
/* Unregister only if it's a master-device */
unregister_netdev(&p->local.dev);
}
/* Unlink device from chain */
list_del(&p->global_list);
if (p->slave) {
/* If this interface has a slave, remove it also */
char *slavename = p->slave->name;
struct list_head *l;
list_for_each(l, &isdn_net_devs) {
isdn_net_dev *n = list_entry(l, isdn_net_dev, global_list);
if (!strcmp(n->name, slavename)) {
isdn_net_realrm(n);
break;
}
}
list_del(&p->slaves);
if (list_empty(&p->mlp->slaves)) {
unregister_netdev(&p->mlp->dev);
kfree(p->mlp);
}
restore_flags(flags);
kfree(p);
......@@ -2156,15 +2081,15 @@ isdn_net_realrm(isdn_net_dev *p)
int
isdn_net_rm(char *name)
{
struct list_head *l;
/* FIXME: For compatibility, if a master isdn_net_dev is rm'ed,
* kill all slaves, too */
/* Search name in netdev-chain */
list_for_each(l, &isdn_net_devs) {
isdn_net_dev *p = list_entry(l, isdn_net_dev, global_list);
if (!strcmp(p->name, name))
return isdn_net_realrm(p);
}
return -ENODEV;
isdn_net_dev *idev = isdn_net_findif(name);
if (!idev)
return -ENODEV;
return isdn_net_realrm(idev);
}
/*
......@@ -2174,24 +2099,19 @@ int
isdn_net_rmall(void)
{
unsigned long flags;
int ret;
int ret = 0;
/* Walk through netdev-chain */
save_flags(flags);
cli();
while (!list_empty(&isdn_net_devs)) {
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->master) {
if ((ret = isdn_net_realrm(p))) {
restore_flags(flags);
return ret;
}
}
isdn_net_dev *idev = list_entry(isdn_net_devs.next, isdn_net_dev, global_list);
ret = isdn_net_realrm(idev);
if (ret)
break;
}
restore_flags(flags);
return 0;
return ret;
}
// ISDN_NET_ENCAP_IPTYP
......@@ -2211,7 +2131,7 @@ static void
isdn_iptyp_receive(isdn_net_local *lp, isdn_net_dev *idev,
struct sk_buff *skb)
{
isdn_net_reset_huptimer(lp, idev);
idev->huptimer = 0;
get_u16(skb->data, &skb->protocol);
skb_pull(skb, 2);
netif_rx(skb);
......@@ -2242,7 +2162,7 @@ static void
isdn_uihdlc_receive(isdn_net_local *lp, isdn_net_dev *idev,
struct sk_buff *skb)
{
isdn_net_reset_huptimer(lp, idev);
idev->huptimer = 0;
skb_pull(skb, 2);
skb->protocol = htons(ETH_P_IP);
netif_rx(skb);
......@@ -2264,7 +2184,7 @@ static void
isdn_rawip_receive(isdn_net_local *lp, isdn_net_dev *idev,
struct sk_buff *skb)
{
isdn_net_reset_huptimer(lp, idev);
idev->huptimer = 0;
skb->protocol = htons(ETH_P_IP);
netif_rx(skb);
}
......@@ -2337,7 +2257,7 @@ static void
isdn_ether_receive(isdn_net_local *lp, isdn_net_dev *idev,
struct sk_buff *skb)
{
isdn_net_reset_huptimer(lp, idev);
idev->huptimer = 0;
skb->protocol = isdn_eth_type_trans(skb, skb->dev);
netif_rx(skb);
}
......
......@@ -34,7 +34,7 @@
extern void isdn_net_init_module(void);
extern int isdn_net_new(char *, struct net_device *);
extern int isdn_net_new(char *, isdn_net_local *);
extern int isdn_net_newslave(char *);
extern int isdn_net_rm(char *);
extern int isdn_net_rmall(void);
......@@ -57,13 +57,6 @@ 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_local *lp, isdn_net_dev *idev)
{
lp->netdev->huptimer = 0;
idev->huptimer = 0;
}
#define ISDN_NET_MAX_QUEUE_LENGTH 2
/*
......@@ -125,14 +118,9 @@ isdn_net_add_to_bundle(isdn_net_local *mlp, isdn_net_dev *idev)
static inline void
isdn_net_rm_from_bundle(isdn_net_dev *idev)
{
isdn_net_local *mlp;
isdn_net_local *mlp = idev->mlp;
unsigned long flags;
if (idev->master)
mlp = idev->master;
else
mlp = &idev->local;
spin_lock_irqsave(&mlp->online_lock, flags);
list_del(&idev->online);
spin_unlock_irqrestore(&mlp->online_lock, flags);
......@@ -145,10 +133,7 @@ isdn_net_rm_from_bundle(isdn_net_dev *idev)
static inline void
isdn_net_dev_wake_queue(isdn_net_dev *idev)
{
if (idev->master)
netif_wake_queue(&idev->master->dev);
else
netif_wake_queue(&idev->local.dev);
netif_wake_queue(&idev->mlp->dev);
}
static inline int
......
......@@ -100,9 +100,8 @@ isdn_ppp_frame_log(char *info, char *data, int len, int maxlen,int unit,int slot
* in this case we bind another lp to the master device
*/
static void
isdn_ppp_free(isdn_net_local * lp)
isdn_ppp_free(isdn_net_dev *idev)
{
isdn_net_dev *idev = lp->netdev;
unsigned long flags;
struct ippp_struct *is;
......@@ -116,7 +115,7 @@ isdn_ppp_free(isdn_net_local * lp)
cli();
#ifdef CONFIG_ISDN_MPP
spin_lock(&lp->netdev->pb->lock);
spin_lock(&idev->pb->lock);
#endif
isdn_net_rm_from_bundle(idev);
#ifdef CONFIG_ISDN_MPP
......@@ -139,7 +138,7 @@ isdn_ppp_free(isdn_net_local * lp)
is->state = IPPP_OPEN; /* fallback to 'OPEN but not ASSIGNED' state */
if (is->debug & 0x1)
printk(KERN_DEBUG "isdn_ppp_free %d %p %p\n", idev->ppp_slot, lp, is->idev);
printk(KERN_DEBUG "isdn_ppp_free %d %p\n", idev->ppp_slot, is->idev);
is->idev = NULL; /* link is down .. set lp to NULL */
idev->ppp_slot = -1; /* is this OK ?? */
......@@ -152,9 +151,8 @@ isdn_ppp_free(isdn_net_local * lp)
* bind isdn_net_local <=> ippp-device
*/
int
isdn_ppp_bind(isdn_net_local * lp)
isdn_ppp_bind(isdn_net_dev *idev)
{
isdn_net_dev *idev = lp->netdev;
int i;
int unit = 0;
long flags;
......@@ -226,10 +224,8 @@ isdn_ppp_bind(isdn_net_local * lp)
*/
static void
isdn_ppp_wakeup_daemon(isdn_net_local *lp)
isdn_ppp_wakeup_daemon(isdn_net_dev *idev)
{
isdn_net_dev *idev = lp->netdev;
if (idev->ppp_slot < 0 || idev->ppp_slot >= ISDN_MAX_CHANNELS) {
printk(KERN_ERR "%s: ppp_slot(%d) out of range\n",
__FUNCTION__, idev->ppp_slot);
......@@ -477,7 +473,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->local.dev);
isdn_net_dev_wake_queue(idev);
}
}
is->pppcfg = val;
......@@ -552,14 +548,16 @@ isdn_ppp_ioctl(struct inode *ino, struct file *file, unsigned int cmd, unsigned
return isdn_ppp_set_compressor(is, &data);
case PPPIOCGCALLINFO:
{
isdn_net_local *mlp;
struct isdn_net_phone *phone;
struct pppcallinfo pci;
int i;
memset((char *) &pci,0,sizeof(struct pppcallinfo));
if(idev) {
strncpy(pci.local_num,idev->local.msn,63);
mlp = idev->mlp;
strncpy(pci.local_num, mlp->msn, 63);
i = 0;
list_for_each_entry(phone, &idev->local.phone[1], list) {
list_for_each_entry(phone, &mlp->phone[1], list) {
if (i++ == idev->dial) {
strncpy(pci.remote_num,phone->num,63);
break;
......@@ -570,7 +568,7 @@ isdn_ppp_ioctl(struct inode *ino, struct file *file, unsigned int cmd, unsigned
pci.calltype = CALLTYPE_OUTGOING;
else
pci.calltype = CALLTYPE_INCOMING;
if(idev->local.flags & ISDN_NET_CALLBACK)
if(mlp->flags & ISDN_NET_CALLBACK)
pci.calltype |= CALLTYPE_CALLBACK;
}
return set_arg((void *)arg,&pci,sizeof(struct pppcallinfo));
......@@ -779,7 +777,7 @@ isdn_ppp_write(struct file *file, const char *buf, size_t count, loff_t *off)
isdn_ppp_frame_log("xmit", skb->data, skb->len, 32,is->unit,idev->ppp_slot);
}
isdn_ppp_send_ccp(idev,&idev->local,skb); /* keeps CCP/compression states in sync */
isdn_ppp_send_ccp(idev,idev->mlp,skb); /* keeps CCP/compression states in sync */
isdn_net_write_super(idev, skb);
}
......@@ -914,7 +912,7 @@ static void isdn_ppp_receive(isdn_net_local *lp, isdn_net_dev *idev,
* huptimer on LCP packets.
*/
if (PPP_PROTOCOL(skb->data) != PPP_LCP)
isdn_net_reset_huptimer(lp, idev);
idev->huptimer = 0;
slot = idev->ppp_slot;
if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
......@@ -979,14 +977,6 @@ isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev,
}
is = ippp_table[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);
goto drop_packet;
}
}
mis = ippp_table[slot];
if (is->debug & 0x10) {
......@@ -1017,12 +1007,12 @@ isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev,
case PPP_VJC_UNCOMP:
if (is->debug & 0x20)
printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n");
if (lp->netdev->ppp_slot < 0) {
if (idev->ppp_slot < 0) {
printk(KERN_ERR "%s: net_dev->ppp_slot(%d) out of range\n",
__FUNCTION__ , lp->netdev->ppp_slot);
__FUNCTION__ , idev->ppp_slot);
goto drop_packet;
}
if (slhc_remember(ippp_table[lp->netdev->ppp_slot]->slcomp, skb->data, skb->len) <= 0) {
if (slhc_remember(ippp_table[idev->ppp_slot]->slcomp, skb->data, skb->len) <= 0) {
printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n");
goto drop_packet;
}
......@@ -1043,12 +1033,12 @@ isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev,
}
skb_put(skb, skb_old->len + 128);
memcpy(skb->data, skb_old->data, skb_old->len);
if (lp->netdev->ppp_slot < 0) {
if (idev->ppp_slot < 0) {
printk(KERN_ERR "%s: net_dev->ppp_slot(%d) out of range\n",
__FUNCTION__ , lp->netdev->ppp_slot);
__FUNCTION__ , idev->ppp_slot);
goto drop_packet;
}
pkt_len = slhc_uncompress(ippp_table[lp->netdev->ppp_slot]->slcomp,
pkt_len = slhc_uncompress(ippp_table[idev->ppp_slot]->slcomp,
skb->data, skb_old->len);
kfree_skb(skb_old);
if (pkt_len < 0)
......@@ -1061,7 +1051,7 @@ isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev,
#endif
case PPP_CCP:
case PPP_CCPFRAG:
isdn_ppp_receive_ccp(lp->netdev,lp,skb,proto);
isdn_ppp_receive_ccp(idev,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 ||
......@@ -1125,17 +1115,15 @@ 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 *mlp;
isdn_net_dev *idev;
isdn_net_dev *nd;
isdn_net_local *mlp = netdev->priv;
isdn_net_dev *idev = list_entry(mlp->online.next, isdn_net_dev, online);
unsigned int proto = PPP_IP; /* 0x21 */
struct ippp_struct *ipt,*ipts;
int slot;
mlp = netdev->priv;
nd = mlp->netdev; /* get master lp */
slot = nd->ppp_slot;
slot = idev->ppp_slot;
if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n",
slot);
......@@ -1779,7 +1767,7 @@ isdn_ppp_bundle(struct ippp_struct *is, int unit)
spin_lock_irqsave(&p->pb->lock, flags);
nidev = is->idev;
idev = list_entry(p->local.online.next, isdn_net_dev, online);
idev = list_entry(p->mlp->online.next, isdn_net_dev, online);
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",
......@@ -1789,7 +1777,7 @@ isdn_ppp_bundle(struct ippp_struct *is, int unit)
goto out;
}
isdn_net_add_to_bundle(&p->local, nidev);
isdn_net_add_to_bundle(p->mlp, nidev);
ippp_table[nidev->ppp_slot]->unit = ippp_table[idev->ppp_slot]->unit;
......@@ -1798,7 +1786,7 @@ isdn_ppp_bundle(struct ippp_struct *is, int unit)
(SC_ENABLE_IP | SC_NO_TCP_CCID | SC_REJ_COMP_TCP);
ippp_table[nidev->ppp_slot]->mpppcfg |= ippp_table[idev->ppp_slot]->mpppcfg &
(SC_MP_PROT | SC_REJ_MP_PROT | SC_OUT_SHORT_SEQ | SC_IN_SHORT_SEQ);
rc = isdn_ppp_mp_init(&nidev->local, p->pb);
rc = isdn_ppp_mp_init(nidev->mlp, p->pb);
out:
spin_unlock_irqrestore(&p->pb->lock, flags);
return rc;
......@@ -1871,7 +1859,7 @@ isdn_ppp_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
if(copy_to_user(r, PPP_VERSION, len)) error = -EFAULT;
break;
case SIOCGPPPSTATS:
error = isdn_ppp_dev_ioctl_stats(lp->netdev->ppp_slot, ifr, dev);
error = isdn_ppp_dev_ioctl_stats(0, ifr, dev);
break;
default:
error = -EINVAL;
......@@ -1912,14 +1900,12 @@ isdn_ppp_dial_slave(char *name)
{
#ifdef CONFIG_ISDN_MPP
isdn_net_dev *idev;
isdn_net_local *lp;
isdn_net_dev *sdev;
idev = isdn_net_findif(name);
if (!idev)
return 1;
lp = &idev->local;
if (!isdn_net_bound(idev))
return 5;
......@@ -2456,10 +2442,9 @@ static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in,int *proto,
* we received a CCP frame ..
* not a clean solution, but we MUST handle a few cases in the kernel
*/
static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,
static void isdn_ppp_receive_ccp(isdn_net_dev *idev, isdn_net_local *lp,
struct sk_buff *skb,int proto)
{
isdn_net_dev *idev = lp->netdev;
struct ippp_struct *is;
struct ippp_struct *mis;
int len;
......@@ -2476,16 +2461,7 @@ 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 (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);
return;
}
mis = ippp_table[slot];
} else
mis = is;
mis = is;
switch(skb->data[0]) {
case CCP_CONFREQ:
......@@ -2634,9 +2610,8 @@ static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,
* and I tried to modify this file according to that. --abp
*/
static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb)
static void isdn_ppp_send_ccp(isdn_net_dev *idev, isdn_net_local *lp, struct sk_buff *skb)
{
isdn_net_dev *idev = lp->netdev;
struct ippp_struct *mis,*is;
int proto, slot = idev->ppp_slot;
unsigned char *data;
......@@ -2664,16 +2639,7 @@ 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 (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);
return;
}
mis = ippp_table[slot];
} else
mis = is;
mis = is;
if (mis != is)
printk(KERN_DEBUG "isdn_ppp: Ouch! Master CCP sends on slave slot!\n");
......
......@@ -294,17 +294,17 @@ 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_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);
int (*bind)(struct isdn_net_local_s *lp);
void (*unbind)(struct isdn_net_local_s *lp);
int (*init)(struct isdn_net_local_s *lp);
void (*cleanup)(struct isdn_net_local_s *lp);
int (*open)(struct isdn_net_local_s *lp);
void (*close)(struct isdn_net_local_s *lp);
void (*receive)(struct isdn_net_local_s *,
struct isdn_net_dev_s *,
struct sk_buff *);
void (*connected)(struct isdn_net_dev_s *);
void (*disconnected)(struct isdn_net_dev_s *);
int (*bind)(struct isdn_net_dev_s *);
void (*unbind)(struct isdn_net_dev_s *);
int (*init)(struct isdn_net_local_s *);
void (*cleanup)(struct isdn_net_local_s *);
int (*open)(struct isdn_net_local_s *);
void (*close)(struct isdn_net_local_s *);
};
/* Local interface-data */
......@@ -313,7 +313,6 @@ typedef struct isdn_net_local_s {
spinlock_t lock;
struct net_device_stats stats; /* Ethernet Statistics */
int flags; /* Connection-flags */
int dialretry; /* Counter for Dialout-retries */
int dialmax; /* Max. Number of Dial-retries */
int dialtimeout; /* How long shall we try on dialing */
int dialwait; /* wait after failed attempt */
......@@ -334,8 +333,8 @@ typedef struct isdn_net_local_s {
struct list_head phone[2]; /* List of remote-phonenumbers */
/* phone[0] = Incoming Numbers */
/* phone[1] = Outgoing Numbers */
struct isdn_net_dev_s *netdev; /* Ptr to netdev */
struct list_head slaves; /* list of all bundled channels */
struct list_head online; /* circular list of all bundled
channels, which are currently
online */
......@@ -361,8 +360,6 @@ typedef struct isdn_net_local_s {
/* the interface itself */
typedef struct isdn_net_dev_s {
isdn_net_local local;
int isdn_slot; /* Index to isdn device/channel */
int pre_device; /* Preselected isdn-device */
int pre_channel; /* Preselected isdn-channel */
......@@ -375,6 +372,7 @@ typedef struct isdn_net_dev_s {
int outgoing; /* Flag: outgoing call */
unsigned long dialstarted; /* first dialing-attempt */
unsigned long dialwait_timer;/* earliest next dialing-attempt */
int dialretry; /* Counter for Dialout-retries */
int cps; /* current speed of this interface */
int transcount; /* byte-counter for cps-calculation */
......@@ -401,9 +399,10 @@ typedef struct isdn_net_dev_s {
/* queued in HL driver */
struct tasklet_struct tlet;
isdn_net_local *master; /* Ptr to Master device for slaves */
isdn_net_local *mlp; /* Ptr to master device for all devs*/
struct isdn_net_dev_s *slave; /* Ptr to Slave device for masters */
struct list_head slaves; /* Members of local->slaves */
struct list_head online; /* Members of local->online */
char name[10]; /* Name of device */
......
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