aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/isdn/mISDN/socket.c21
-rw-r--r--drivers/isdn/mISDN/tei.c43
-rw-r--r--include/linux/mISDNif.h2
3 files changed, 51 insertions, 15 deletions
diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c
index 508945d1b9c1..530f68977361 100644
--- a/drivers/isdn/mISDN/socket.c
+++ b/drivers/isdn/mISDN/socket.c
@@ -292,7 +292,7 @@ static int
292data_sock_ioctl_bound(struct sock *sk, unsigned int cmd, void __user *p) 292data_sock_ioctl_bound(struct sock *sk, unsigned int cmd, void __user *p)
293{ 293{
294 struct mISDN_ctrl_req cq; 294 struct mISDN_ctrl_req cq;
295 int err = -EINVAL, val; 295 int err = -EINVAL, val[2];
296 struct mISDNchannel *bchan, *next; 296 struct mISDNchannel *bchan, *next;
297 297
298 lock_sock(sk); 298 lock_sock(sk);
@@ -328,12 +328,27 @@ data_sock_ioctl_bound(struct sock *sk, unsigned int cmd, void __user *p)
328 err = -EINVAL; 328 err = -EINVAL;
329 break; 329 break;
330 } 330 }
331 if (get_user(val, (int __user *)p)) { 331 val[0] = cmd;
332 if (get_user(val[1], (int __user *)p)) {
332 err = -EFAULT; 333 err = -EFAULT;
333 break; 334 break;
334 } 335 }
335 err = _pms(sk)->dev->teimgr->ctrl(_pms(sk)->dev->teimgr, 336 err = _pms(sk)->dev->teimgr->ctrl(_pms(sk)->dev->teimgr,
336 CONTROL_CHANNEL, &val); 337 CONTROL_CHANNEL, val);
338 break;
339 case IMHOLD_L1:
340 if (sk->sk_protocol != ISDN_P_LAPD_NT
341 && sk->sk_protocol != ISDN_P_LAPD_TE) {
342 err = -EINVAL;
343 break;
344 }
345 val[0] = cmd;
346 if (get_user(val[1], (int __user *)p)) {
347 err = -EFAULT;
348 break;
349 }
350 err = _pms(sk)->dev->teimgr->ctrl(_pms(sk)->dev->teimgr,
351 CONTROL_CHANNEL, val);
337 break; 352 break;
338 default: 353 default:
339 err = -EINVAL; 354 err = -EINVAL;
diff --git a/drivers/isdn/mISDN/tei.c b/drivers/isdn/mISDN/tei.c
index b452dead8fd0..c75af762a067 100644
--- a/drivers/isdn/mISDN/tei.c
+++ b/drivers/isdn/mISDN/tei.c
@@ -122,8 +122,11 @@ da_deactivate(struct FsmInst *fi, int event, void *arg)
122 } 122 }
123 read_unlock_irqrestore(&mgr->lock, flags); 123 read_unlock_irqrestore(&mgr->lock, flags);
124 /* All TEI are inactiv */ 124 /* All TEI are inactiv */
125 mISDN_FsmAddTimer(&mgr->datimer, DATIMER_VAL, EV_DATIMER, NULL, 1); 125 if (!test_bit(OPTION_L1_HOLD, &mgr->options)) {
126 mISDN_FsmChangeState(fi, ST_L1_DEACT_PENDING); 126 mISDN_FsmAddTimer(&mgr->datimer, DATIMER_VAL, EV_DATIMER,
127 NULL, 1);
128 mISDN_FsmChangeState(fi, ST_L1_DEACT_PENDING);
129 }
127} 130}
128 131
129static void 132static void
@@ -132,9 +135,11 @@ da_ui(struct FsmInst *fi, int event, void *arg)
132 struct manager *mgr = fi->userdata; 135 struct manager *mgr = fi->userdata;
133 136
134 /* restart da timer */ 137 /* restart da timer */
135 mISDN_FsmDelTimer(&mgr->datimer, 2); 138 if (!test_bit(OPTION_L1_HOLD, &mgr->options)) {
136 mISDN_FsmAddTimer(&mgr->datimer, DATIMER_VAL, EV_DATIMER, NULL, 2); 139 mISDN_FsmDelTimer(&mgr->datimer, 2);
137 140 mISDN_FsmAddTimer(&mgr->datimer, DATIMER_VAL, EV_DATIMER,
141 NULL, 2);
142 }
138} 143}
139 144
140static void 145static void
@@ -1103,6 +1108,7 @@ free_teimanager(struct manager *mgr)
1103{ 1108{
1104 struct layer2 *l2, *nl2; 1109 struct layer2 *l2, *nl2;
1105 1110
1111 test_and_clear_bit(OPTION_L1_HOLD, &mgr->options);
1106 if (test_bit(MGR_OPT_NETWORK, &mgr->options)) { 1112 if (test_bit(MGR_OPT_NETWORK, &mgr->options)) {
1107 /* not locked lock is taken in release tei */ 1113 /* not locked lock is taken in release tei */
1108 mgr->up = NULL; 1114 mgr->up = NULL;
@@ -1133,13 +1139,26 @@ static int
1133ctrl_teimanager(struct manager *mgr, void *arg) 1139ctrl_teimanager(struct manager *mgr, void *arg)
1134{ 1140{
1135 /* currently we only have one option */ 1141 /* currently we only have one option */
1136 int clean = *((int *)arg); 1142 int *val = (int *)arg;
1137 1143 int ret = 0;
1138 if (clean) 1144
1139 test_and_set_bit(OPTION_L2_CLEANUP, &mgr->options); 1145 switch (val[0]) {
1140 else 1146 case IMCLEAR_L2:
1141 test_and_clear_bit(OPTION_L2_CLEANUP, &mgr->options); 1147 if (val[1])
1142 return 0; 1148 test_and_set_bit(OPTION_L2_CLEANUP, &mgr->options);
1149 else
1150 test_and_clear_bit(OPTION_L2_CLEANUP, &mgr->options);
1151 break;
1152 case IMHOLD_L1:
1153 if (val[1])
1154 test_and_set_bit(OPTION_L1_HOLD, &mgr->options);
1155 else
1156 test_and_clear_bit(OPTION_L1_HOLD, &mgr->options);
1157 break;
1158 default:
1159 ret = -EINVAL;
1160 }
1161 return ret;
1143} 1162}
1144 1163
1145/* This function does create a L2 for fixed TEI in NT Mode */ 1164/* This function does create a L2 for fixed TEI in NT Mode */
diff --git a/include/linux/mISDNif.h b/include/linux/mISDNif.h
index cf974593a99e..0b28fd1e3938 100644
--- a/include/linux/mISDNif.h
+++ b/include/linux/mISDNif.h
@@ -229,6 +229,7 @@
229#define OPTION_L2_PTP 2 229#define OPTION_L2_PTP 2
230#define OPTION_L2_FIXEDTEI 3 230#define OPTION_L2_FIXEDTEI 3
231#define OPTION_L2_CLEANUP 4 231#define OPTION_L2_CLEANUP 4
232#define OPTION_L1_HOLD 5
232 233
233/* should be in sync with linux/kobject.h:KOBJ_NAME_LEN */ 234/* should be in sync with linux/kobject.h:KOBJ_NAME_LEN */
234#define MISDN_MAX_IDLEN 20 235#define MISDN_MAX_IDLEN 20
@@ -317,6 +318,7 @@ struct ph_info {
317#define IMCTRLREQ _IOR('I', 69, int) 318#define IMCTRLREQ _IOR('I', 69, int)
318#define IMCLEAR_L2 _IOR('I', 70, int) 319#define IMCLEAR_L2 _IOR('I', 70, int)
319#define IMSETDEVNAME _IOR('I', 71, struct mISDN_devrename) 320#define IMSETDEVNAME _IOR('I', 71, struct mISDN_devrename)
321#define IMHOLD_L1 _IOR('I', 72, int)
320 322
321static inline int 323static inline int
322test_channelmap(u_int nr, u_char *map) 324test_channelmap(u_int nr, u_char *map)