mISDN: Added layer-1-hold feature
authorAndreas Eversberg <andreas@eversberg.eu>
Fri, 22 May 2009 11:04:48 +0000 (11:04 +0000)
committerDavid S. Miller <davem@davemloft.net>
Mon, 25 May 2009 07:51:33 +0000 (00:51 -0700)
Add IMHOLD_L1 ioctl.
The feature will be disabled on closing.

Signed-off-by: Andreas Eversberg <andreas@eversberg.eu>
Signed-off-by: Karsten Keil <keil@b1-systems.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/isdn/mISDN/socket.c
drivers/isdn/mISDN/tei.c
include/linux/mISDNif.h

index 508945d1b9c1a4b3ac18a31471179f13097a8cc3..530f68977361f9d58077df3bea0f3d5c091bca22 100644 (file)
@@ -292,7 +292,7 @@ static int
 data_sock_ioctl_bound(struct sock *sk, unsigned int cmd, void __user *p)
 {
        struct mISDN_ctrl_req   cq;
-       int                     err = -EINVAL, val;
+       int                     err = -EINVAL, val[2];
        struct mISDNchannel     *bchan, *next;
 
        lock_sock(sk);
@@ -328,12 +328,27 @@ data_sock_ioctl_bound(struct sock *sk, unsigned int cmd, void __user *p)
                        err = -EINVAL;
                        break;
                }
-               if (get_user(val, (int __user *)p)) {
+               val[0] = cmd;
+               if (get_user(val[1], (int __user *)p)) {
                        err = -EFAULT;
                        break;
                }
                err = _pms(sk)->dev->teimgr->ctrl(_pms(sk)->dev->teimgr,
-                   CONTROL_CHANNEL, &val);
+                   CONTROL_CHANNEL, val);
+               break;
+       case IMHOLD_L1:
+               if (sk->sk_protocol != ISDN_P_LAPD_NT
+                && sk->sk_protocol != ISDN_P_LAPD_TE) {
+                       err = -EINVAL;
+                       break;
+               }
+               val[0] = cmd;
+               if (get_user(val[1], (int __user *)p)) {
+                       err = -EFAULT;
+                       break;
+               }
+               err = _pms(sk)->dev->teimgr->ctrl(_pms(sk)->dev->teimgr,
+                   CONTROL_CHANNEL, val);
                break;
        default:
                err = -EINVAL;
index b452dead8fd04e3fc782ec81fe68914c75f7b6b5..c75af762a067a10c08b94e56c6b6c195708680bc 100644 (file)
@@ -122,8 +122,11 @@ da_deactivate(struct FsmInst *fi, int event, void *arg)
        }
        read_unlock_irqrestore(&mgr->lock, flags);
        /* All TEI are inactiv */
-       mISDN_FsmAddTimer(&mgr->datimer, DATIMER_VAL, EV_DATIMER, NULL, 1);
-       mISDN_FsmChangeState(fi, ST_L1_DEACT_PENDING);
+       if (!test_bit(OPTION_L1_HOLD, &mgr->options)) {
+               mISDN_FsmAddTimer(&mgr->datimer, DATIMER_VAL, EV_DATIMER,
+                       NULL, 1);
+               mISDN_FsmChangeState(fi, ST_L1_DEACT_PENDING);
+       }
 }
 
 static void
@@ -132,9 +135,11 @@ da_ui(struct FsmInst *fi, int event, void *arg)
        struct manager  *mgr = fi->userdata;
 
        /* restart da timer */
-       mISDN_FsmDelTimer(&mgr->datimer, 2);
-       mISDN_FsmAddTimer(&mgr->datimer, DATIMER_VAL, EV_DATIMER, NULL, 2);
-
+       if (!test_bit(OPTION_L1_HOLD, &mgr->options)) {
+               mISDN_FsmDelTimer(&mgr->datimer, 2);
+               mISDN_FsmAddTimer(&mgr->datimer, DATIMER_VAL, EV_DATIMER,
+                       NULL, 2);
+       }
 }
 
 static void
@@ -1103,6 +1108,7 @@ free_teimanager(struct manager *mgr)
 {
        struct layer2   *l2, *nl2;
 
+       test_and_clear_bit(OPTION_L1_HOLD, &mgr->options);
        if (test_bit(MGR_OPT_NETWORK, &mgr->options)) {
                /* not locked lock is taken in release tei */
                mgr->up = NULL;
@@ -1133,13 +1139,26 @@ static int
 ctrl_teimanager(struct manager *mgr, void *arg)
 {
        /* currently we only have one option */
-       int     clean = *((int *)arg);
-
-       if (clean)
-               test_and_set_bit(OPTION_L2_CLEANUP, &mgr->options);
-       else
-               test_and_clear_bit(OPTION_L2_CLEANUP, &mgr->options);
-       return 0;
+       int     *val = (int *)arg;
+       int     ret = 0;
+
+       switch (val[0]) {
+       case IMCLEAR_L2:
+               if (val[1])
+                       test_and_set_bit(OPTION_L2_CLEANUP, &mgr->options);
+               else
+                       test_and_clear_bit(OPTION_L2_CLEANUP, &mgr->options);
+               break;
+       case IMHOLD_L1:
+               if (val[1])
+                       test_and_set_bit(OPTION_L1_HOLD, &mgr->options);
+               else
+                       test_and_clear_bit(OPTION_L1_HOLD, &mgr->options);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+       return ret;
 }
 
 /* This function does create a L2 for fixed TEI in NT Mode */
index cf974593a99e7cbfaab3d1a7c5dabd11b0fe4d0e..0b28fd1e39385a09ccd5875e302b27c7324d7b45 100644 (file)
 #define OPTION_L2_PTP          2
 #define OPTION_L2_FIXEDTEI     3
 #define OPTION_L2_CLEANUP      4
+#define OPTION_L1_HOLD         5
 
 /* should be in sync with linux/kobject.h:KOBJ_NAME_LEN */
 #define MISDN_MAX_IDLEN                20
@@ -317,6 +318,7 @@ struct ph_info {
 #define IMCTRLREQ      _IOR('I', 69, int)
 #define IMCLEAR_L2     _IOR('I', 70, int)
 #define IMSETDEVNAME   _IOR('I', 71, struct mISDN_devrename)
+#define IMHOLD_L1      _IOR('I', 72, int)
 
 static inline int
 test_channelmap(u_int nr, u_char *map)