Commit b1fde668 authored by Kai Germaschewski's avatar Kai Germaschewski

ISDN: Move binding the interface into state machine

Again, let's do as much as possible inside the state machine..
parent 80a78a60
...@@ -43,8 +43,6 @@ extern int register_isdn_netif(int encap, struct isdn_netif_ops *ops); ...@@ -43,8 +43,6 @@ extern int register_isdn_netif(int encap, struct isdn_netif_ops *ops);
extern int isdn_net_autodial(struct sk_buff *skb, struct net_device *ndev); extern int isdn_net_autodial(struct sk_buff *skb, struct net_device *ndev);
extern int isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev); extern int isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev);
extern int isdn_net_bind_channel(isdn_net_dev *idev, int slot);
extern void isdn_net_unbind_channel(isdn_net_dev *idev);
extern int isdn_net_dial(isdn_net_dev *idev); extern int isdn_net_dial(isdn_net_dev *idev);
extern int isdn_net_bsent(isdn_net_dev *idev, isdn_ctrl *c); extern int isdn_net_bsent(isdn_net_dev *idev, isdn_ctrl *c);
......
...@@ -66,6 +66,7 @@ static struct fsm isdn_net_fsm; ...@@ -66,6 +66,7 @@ static struct fsm isdn_net_fsm;
enum { enum {
ST_NULL, ST_NULL,
ST_OUT_BOUND,
ST_OUT_WAIT_DCONN, ST_OUT_WAIT_DCONN,
ST_OUT_WAIT_BCONN, ST_OUT_WAIT_BCONN,
ST_IN_WAIT_DCONN, ST_IN_WAIT_DCONN,
...@@ -78,6 +79,7 @@ enum { ...@@ -78,6 +79,7 @@ enum {
static char *isdn_net_st_str[] = { static char *isdn_net_st_str[] = {
"ST_NULL", "ST_NULL",
"ST_OUT_BOUND",
"ST_OUT_WAIT_DCONN", "ST_OUT_WAIT_DCONN",
"ST_OUT_WAIT_BCONN", "ST_OUT_WAIT_BCONN",
"ST_IN_WAIT_DCONN", "ST_IN_WAIT_DCONN",
...@@ -446,7 +448,7 @@ isdn_net_dev_delete(isdn_net_dev *idev) ...@@ -446,7 +448,7 @@ isdn_net_dev_delete(isdn_net_dev *idev)
isdn_net_rmallphone(idev); isdn_net_rmallphone(idev);
if (idev->exclusive >= 0) if (idev->exclusive >= 0)
isdn_free_slot(idev->exclusive); isdn_slot_free(idev->exclusive);
list_del(&idev->slaves); list_del(&idev->slaves);
...@@ -1155,43 +1157,13 @@ isdn_net_dial_timer(unsigned long data) ...@@ -1155,43 +1157,13 @@ isdn_net_dial_timer(unsigned long data)
isdn_net_handle_event(idev, idev->dial_event, NULL); isdn_net_handle_event(idev, idev->dial_event, NULL);
} }
/*
* Assign an ISDN-channel to a net-interface
*/
int
isdn_net_bind_channel(isdn_net_dev *idev, int slot)
{
isdn_net_local *mlp = idev->mlp;
int retval = 0;
unsigned long flags;
save_flags(flags);
cli();
idev->isdn_slot = slot;
isdn_slot_set_idev(idev->isdn_slot, idev);
if (mlp->ops->bind)
retval = mlp->ops->bind(idev);
if (retval < 0)
isdn_net_unbind_channel(idev);
restore_flags(flags);
return retval;
}
/* /*
* Unbind a net-interface * Unbind a net-interface
*/ */
void static void
isdn_net_unbind_channel(isdn_net_dev *idev) isdn_net_unbind_channel(isdn_net_dev *idev)
{ {
isdn_net_local *mlp = idev->mlp; isdn_net_local *mlp = idev->mlp;
ulong flags;
save_flags(flags);
cli();
if (idev->isdn_slot < 0) { if (idev->isdn_slot < 0) {
isdn_BUG(); isdn_BUG();
...@@ -1201,46 +1173,49 @@ isdn_net_unbind_channel(isdn_net_dev *idev) ...@@ -1201,46 +1173,49 @@ isdn_net_unbind_channel(isdn_net_dev *idev)
if (mlp->ops->unbind) if (mlp->ops->unbind)
mlp->ops->unbind(idev); mlp->ops->unbind(idev);
skb_queue_purge(&idev->super_tx_queue); isdn_slot_set_idev(idev->isdn_slot, NULL);
fsm_change_state(&idev->fi, ST_NULL); skb_queue_purge(&idev->super_tx_queue);
isdn_slot_set_idev(idev->isdn_slot, NULL); if (idev->isdn_slot != idev->exclusive)
isdn_slot_free(idev->isdn_slot); isdn_slot_free(idev->isdn_slot);
idev->isdn_slot = -1; idev->isdn_slot = -1;
restore_flags(flags); fsm_change_state(&idev->fi, ST_NULL);
} }
int /*
isdn_net_dial(isdn_net_dev *idev) * Assign an ISDN-channel to a net-interface
*/
static int
isdn_net_bind_channel(isdn_net_dev *idev, int slot)
{ {
int slot;
isdn_net_local *mlp = idev->mlp; isdn_net_local *mlp = idev->mlp;
int retval = 0;
if (isdn_net_bound(idev)) idev->isdn_slot = slot;
return -EBUSY; isdn_slot_set_idev(idev->isdn_slot, idev);
if (idev->exclusive >= 0) if (mlp->ops->bind)
slot = idev->exclusive; retval = mlp->ops->bind(idev);
else
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(idev, slot) < 0) if (retval < 0)
goto err; isdn_net_unbind_channel(idev);
// FIXME do the above in state machine return retval;
/* Initiate dialing */ }
fsm_event(&idev->fi, EV_DO_DIAL, NULL);
return 0;
err: int
return -EAGAIN; isdn_net_dial(isdn_net_dev *idev)
{
int retval;
retval = fsm_event(&idev->fi, EV_DO_DIAL, NULL);
if (retval == -ESRCH) /* event not handled in this state */
retval = -EBUSY;
return retval;
} }
static int static int
...@@ -1251,8 +1226,6 @@ accept_icall(struct fsm_inst *fi, int pr, void *arg) ...@@ -1251,8 +1226,6 @@ accept_icall(struct fsm_inst *fi, int pr, void *arg)
isdn_ctrl cmd; isdn_ctrl cmd;
int slot = (int) arg; int slot = (int) arg;
// FIXME this really should be done in generic code
isdn_net_bind_channel(idev, slot); isdn_net_bind_channel(idev, slot);
idev->outgoing = 0; idev->outgoing = 0;
...@@ -1276,36 +1249,15 @@ static int ...@@ -1276,36 +1249,15 @@ static int
do_callback(struct fsm_inst *fi, int pr, void *arg) do_callback(struct fsm_inst *fi, int pr, void *arg)
{ {
isdn_net_dev *idev = fi->userdata; isdn_net_dev *idev = fi->userdata;
isdn_net_local *mlp = idev->mlp;
int slot;
/* Is the state MANUAL?
* If so, no callback can be made */
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;
}
printk(KERN_DEBUG "%s: start callback\n", idev->name);
/* Grab a free ISDN-Channel */
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(idev, slot) < 0) printk(KERN_DEBUG "%s: start callback\n", idev->name);
goto err;
/* Setup dialstate. */
idev->dial_timer.expires = jiffies + mlp->cbdelay; idev->dial_timer.expires = jiffies + mlp->cbdelay;
idev->dial_event = EV_TIMER_CB_IN; idev->dial_event = EV_TIMER_CB_IN;
add_timer(&idev->dial_timer); add_timer(&idev->dial_timer);
fsm_change_state(&idev->fi, ST_WAIT_BEFORE_CB); fsm_change_state(&idev->fi, ST_WAIT_BEFORE_CB);
return 0; return 0;
err:
return -EBUSY;
} }
static int static int
...@@ -1501,18 +1453,33 @@ dialout_first(struct fsm_inst *fi, int pr, void *arg) ...@@ -1501,18 +1453,33 @@ dialout_first(struct fsm_inst *fi, int pr, void *arg)
{ {
isdn_net_dev *idev = fi->userdata; isdn_net_dev *idev = fi->userdata;
isdn_net_local *mlp = idev->mlp; isdn_net_local *mlp = idev->mlp;
int slot;
if (ISDN_NET_DIALMODE(*mlp) == ISDN_NET_DM_OFF) { if (ISDN_NET_DIALMODE(*mlp) == ISDN_NET_DM_OFF)
isdn_net_unbind_channel(idev);
return -EPERM; return -EPERM;
}
if (list_empty(&mlp->phone[1])) { if (list_empty(&mlp->phone[1])) /* no number to dial ? */
isdn_net_unbind_channel(idev);
return -EINVAL; return -EINVAL;
if (idev->exclusive >= 0)
slot = idev->exclusive;
else
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)
return -EAGAIN;
if (isdn_net_bind_channel(idev, slot) < 0) {
/* has freed the slot as well */
return -EAGAIN;
} }
fsm_change_state(fi, ST_OUT_BOUND);
idev->dial = 0; idev->dial = 0;
idev->dialretry = 0; idev->dialretry = 0;
return dialout_next(fi, pr, arg); return dialout_next(fi, pr, arg);
} }
......
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