socket.c 17.4 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0-only
Karsten Keil's avatar
Karsten Keil committed
2
3
4
5
6
7
8
9
/*
 *
 * Author	Karsten Keil <kkeil@novell.com>
 *
 * Copyright 2008  by Karsten Keil <kkeil@novell.com>
 */

#include <linux/mISDNif.h>
10
#include <linux/slab.h>
11
#include <linux/export.h>
Karsten Keil's avatar
Karsten Keil committed
12
13
#include "core.h"

14
static u_int	*debug;
Karsten Keil's avatar
Karsten Keil committed
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96

static struct proto mISDN_proto = {
	.name		= "misdn",
	.owner		= THIS_MODULE,
	.obj_size	= sizeof(struct mISDN_sock)
};

#define _pms(sk)	((struct mISDN_sock *)sk)

static struct mISDN_sock_list	data_sockets = {
	.lock = __RW_LOCK_UNLOCKED(data_sockets.lock)
};

static struct mISDN_sock_list	base_sockets = {
	.lock = __RW_LOCK_UNLOCKED(base_sockets.lock)
};

#define L2_HEADER_LEN	4

static inline struct sk_buff *
_l2_alloc_skb(unsigned int len, gfp_t gfp_mask)
{
	struct sk_buff  *skb;

	skb = alloc_skb(len + L2_HEADER_LEN, gfp_mask);
	if (likely(skb))
		skb_reserve(skb, L2_HEADER_LEN);
	return skb;
}

static void
mISDN_sock_link(struct mISDN_sock_list *l, struct sock *sk)
{
	write_lock_bh(&l->lock);
	sk_add_node(sk, &l->head);
	write_unlock_bh(&l->lock);
}

static void mISDN_sock_unlink(struct mISDN_sock_list *l, struct sock *sk)
{
	write_lock_bh(&l->lock);
	sk_del_node_init(sk);
	write_unlock_bh(&l->lock);
}

static int
mISDN_send(struct mISDNchannel *ch, struct sk_buff *skb)
{
	struct mISDN_sock *msk;
	int	err;

	msk = container_of(ch, struct mISDN_sock, ch);
	if (*debug & DEBUG_SOCKET)
		printk(KERN_DEBUG "%s len %d %p\n", __func__, skb->len, skb);
	if (msk->sk.sk_state == MISDN_CLOSED)
		return -EUNATCH;
	__net_timestamp(skb);
	err = sock_queue_rcv_skb(&msk->sk, skb);
	if (err)
		printk(KERN_WARNING "%s: error %d\n", __func__, err);
	return err;
}

static int
mISDN_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
{
	struct mISDN_sock *msk;

	msk = container_of(ch, struct mISDN_sock, ch);
	if (*debug & DEBUG_SOCKET)
		printk(KERN_DEBUG "%s(%p, %x, %p)\n", __func__, ch, cmd, arg);
	switch (cmd) {
	case CLOSE_CHANNEL:
		msk->sk.sk_state = MISDN_CLOSED;
		break;
	}
	return 0;
}

static inline void
mISDN_sock_cmsg(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
{
97
	struct __kernel_old_timeval	tv;
Karsten Keil's avatar
Karsten Keil committed
98
99
100
101
102
103
104
105

	if (_pms(sk)->cmask & MISDN_TIME_STAMP) {
		skb_get_timestamp(skb, &tv);
		put_cmsg(msg, SOL_MISDN, MISDN_TIME_STAMP, sizeof(tv), &tv);
	}
}

static int
106
107
mISDN_sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
		   int flags)
Karsten Keil's avatar
Karsten Keil committed
108
109
110
111
112
113
114
115
{
	struct sk_buff		*skb;
	struct sock		*sk = sock->sk;

	int		copied, err;

	if (*debug & DEBUG_SOCKET)
		printk(KERN_DEBUG "%s: len %d, flags %x ch.nr %d, proto %x\n",
116
117
		       __func__, (int)len, flags, _pms(sk)->ch.nr,
		       sk->sk_protocol);
Karsten Keil's avatar
Karsten Keil committed
118
119
120
121
122
123
124
125
126
127
	if (flags & (MSG_OOB))
		return -EOPNOTSUPP;

	if (sk->sk_state == MISDN_CLOSED)
		return 0;

	skb = skb_recv_datagram(sk, flags, flags & MSG_DONTWAIT, &err);
	if (!skb)
		return err;

128
	if (msg->msg_name) {
129
		DECLARE_SOCKADDR(struct sockaddr_mISDN *, maddr, msg->msg_name);
130

Karsten Keil's avatar
Karsten Keil committed
131
132
133
134
135
136
137
138
139
140
141
142
		maddr->family = AF_ISDN;
		maddr->dev = _pms(sk)->dev->id;
		if ((sk->sk_protocol == ISDN_P_LAPD_TE) ||
		    (sk->sk_protocol == ISDN_P_LAPD_NT)) {
			maddr->channel = (mISDN_HEAD_ID(skb) >> 16) & 0xff;
			maddr->tei =  (mISDN_HEAD_ID(skb) >> 8) & 0xff;
			maddr->sapi = mISDN_HEAD_ID(skb) & 0xff;
		} else {
			maddr->channel = _pms(sk)->ch.nr;
			maddr->sapi = _pms(sk)->ch.addr & 0xFF;
			maddr->tei =  (_pms(sk)->ch.addr >> 8) & 0xFF;
		}
143
		msg->msg_namelen = sizeof(*maddr);
Karsten Keil's avatar
Karsten Keil committed
144
145
146
147
148
	}

	copied = skb->len + MISDN_HEADER_LEN;
	if (len < copied) {
		if (flags & MSG_PEEK)
149
			refcount_dec(&skb->users);
Karsten Keil's avatar
Karsten Keil committed
150
151
152
153
154
		else
			skb_queue_head(&sk->sk_receive_queue, skb);
		return -ENOSPC;
	}
	memcpy(skb_push(skb, MISDN_HEADER_LEN), mISDN_HEAD_P(skb),
155
	       MISDN_HEADER_LEN);
Karsten Keil's avatar
Karsten Keil committed
156

157
	err = skb_copy_datagram_msg(skb, 0, msg, copied);
Karsten Keil's avatar
Karsten Keil committed
158
159
160
161
162
163
164
165
166

	mISDN_sock_cmsg(sk, msg, skb);

	skb_free_datagram(sk, skb);

	return err ? : copied;
}

static int
167
mISDN_sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
Karsten Keil's avatar
Karsten Keil committed
168
169
170
171
172
173
174
{
	struct sock		*sk = sock->sk;
	struct sk_buff		*skb;
	int			err = -ENOMEM;

	if (*debug & DEBUG_SOCKET)
		printk(KERN_DEBUG "%s: len %d flags %x ch %d proto %x\n",
175
176
		       __func__, (int)len, msg->msg_flags, _pms(sk)->ch.nr,
		       sk->sk_protocol);
Karsten Keil's avatar
Karsten Keil committed
177
178
179
180

	if (msg->msg_flags & MSG_OOB)
		return -EOPNOTSUPP;

181
	if (msg->msg_flags & ~(MSG_DONTWAIT | MSG_NOSIGNAL | MSG_ERRQUEUE))
Karsten Keil's avatar
Karsten Keil committed
182
183
184
185
186
187
188
189
190
191
192
193
194
195
		return -EINVAL;

	if (len < MISDN_HEADER_LEN)
		return -EINVAL;

	if (sk->sk_state != MISDN_BOUND)
		return -EBADFD;

	lock_sock(sk);

	skb = _l2_alloc_skb(len, GFP_KERNEL);
	if (!skb)
		goto done;

Al Viro's avatar
Al Viro committed
196
	if (memcpy_from_msg(skb_put(skb, len), msg, len)) {
Karsten Keil's avatar
Karsten Keil committed
197
		err = -EFAULT;
198
		goto done;
Karsten Keil's avatar
Karsten Keil committed
199
200
201
202
203
204
205
	}

	memcpy(mISDN_HEAD_P(skb), skb->data, MISDN_HEADER_LEN);
	skb_pull(skb, MISDN_HEADER_LEN);

	if (msg->msg_namelen >= sizeof(struct sockaddr_mISDN)) {
		/* if we have a address, we use it */
206
		DECLARE_SOCKADDR(struct sockaddr_mISDN *, maddr, msg->msg_name);
Karsten Keil's avatar
Karsten Keil committed
207
208
209
210
		mISDN_HEAD_ID(skb) = maddr->channel;
	} else { /* use default for L2 messages */
		if ((sk->sk_protocol == ISDN_P_LAPD_TE) ||
		    (sk->sk_protocol == ISDN_P_LAPD_NT))
Karsten Keil's avatar
Karsten Keil committed
211
			mISDN_HEAD_ID(skb) = _pms(sk)->ch.nr;
Karsten Keil's avatar
Karsten Keil committed
212
213
214
215
	}

	if (*debug & DEBUG_SOCKET)
		printk(KERN_DEBUG "%s: ID:%x\n",
216
		       __func__, mISDN_HEAD_ID(skb));
Karsten Keil's avatar
Karsten Keil committed
217
218

	err = -ENODEV;
219
220
221
222
223
224
225
226
227
	if (!_pms(sk)->ch.peer)
		goto done;
	err = _pms(sk)->ch.recv(_pms(sk)->ch.peer, skb);
	if (err)
		goto done;
	else {
		skb = NULL;
		err = len;
	}
Karsten Keil's avatar
Karsten Keil committed
228
229

done:
230
	kfree_skb(skb);
Karsten Keil's avatar
Karsten Keil committed
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
	release_sock(sk);
	return err;
}

static int
data_sock_release(struct socket *sock)
{
	struct sock *sk = sock->sk;

	if (*debug & DEBUG_SOCKET)
		printk(KERN_DEBUG "%s(%p) sk=%p\n", __func__, sock, sk);
	if (!sk)
		return 0;
	switch (sk->sk_protocol) {
	case ISDN_P_TE_S0:
	case ISDN_P_NT_S0:
	case ISDN_P_TE_E1:
	case ISDN_P_NT_E1:
		if (sk->sk_state == MISDN_BOUND)
			delete_channel(&_pms(sk)->ch);
		else
			mISDN_sock_unlink(&data_sockets, sk);
		break;
	case ISDN_P_LAPD_TE:
	case ISDN_P_LAPD_NT:
	case ISDN_P_B_RAW:
	case ISDN_P_B_HDLC:
	case ISDN_P_B_X75SLP:
	case ISDN_P_B_L2DTMF:
	case ISDN_P_B_L2DSP:
	case ISDN_P_B_L2DSPHDLC:
		delete_channel(&_pms(sk)->ch);
		mISDN_sock_unlink(&data_sockets, sk);
		break;
	}

	lock_sock(sk);

	sock_orphan(sk);
	skb_queue_purge(&sk->sk_receive_queue);

	release_sock(sk);
	sock_put(sk);

	return 0;
}

static int
data_sock_ioctl_bound(struct sock *sk, unsigned int cmd, void __user *p)
{
	struct mISDN_ctrl_req	cq;
282
	int			err = -EINVAL, val[2];
Karsten Keil's avatar
Karsten Keil committed
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
	struct mISDNchannel	*bchan, *next;

	lock_sock(sk);
	if (!_pms(sk)->dev) {
		err = -ENODEV;
		goto done;
	}
	switch (cmd) {
	case IMCTRLREQ:
		if (copy_from_user(&cq, p, sizeof(cq))) {
			err = -EFAULT;
			break;
		}
		if ((sk->sk_protocol & ~ISDN_P_B_MASK) == ISDN_P_B_START) {
			list_for_each_entry_safe(bchan, next,
298
						 &_pms(sk)->dev->bchannels, list) {
Karsten Keil's avatar
Karsten Keil committed
299
300
				if (bchan->nr == cq.channel) {
					err = bchan->ctrl(bchan,
301
							  CONTROL_CHANNEL, &cq);
Karsten Keil's avatar
Karsten Keil committed
302
303
304
305
306
					break;
				}
			}
		} else
			err = _pms(sk)->dev->D.ctrl(&_pms(sk)->dev->D,
307
						    CONTROL_CHANNEL, &cq);
Karsten Keil's avatar
Karsten Keil committed
308
309
310
311
312
313
314
315
316
317
		if (err)
			break;
		if (copy_to_user(p, &cq, sizeof(cq)))
			err = -EFAULT;
		break;
	case IMCLEAR_L2:
		if (sk->sk_protocol != ISDN_P_LAPD_NT) {
			err = -EINVAL;
			break;
		}
318
319
		val[0] = cmd;
		if (get_user(val[1], (int __user *)p)) {
Karsten Keil's avatar
Karsten Keil committed
320
321
322
323
			err = -EFAULT;
			break;
		}
		err = _pms(sk)->dev->teimgr->ctrl(_pms(sk)->dev->teimgr,
324
						  CONTROL_CHANNEL, val);
325
326
327
		break;
	case IMHOLD_L1:
		if (sk->sk_protocol != ISDN_P_LAPD_NT
328
		    && sk->sk_protocol != ISDN_P_LAPD_TE) {
329
330
331
332
333
334
335
336
337
			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,
338
						  CONTROL_CHANNEL, val);
Karsten Keil's avatar
Karsten Keil committed
339
340
341
342
343
344
345
346
347
348
349
350
351
		break;
	default:
		err = -EINVAL;
		break;
	}
done:
	release_sock(sk);
	return err;
}

static int
data_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{
352
	int			err = 0, id;
Karsten Keil's avatar
Karsten Keil committed
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
	struct sock		*sk = sock->sk;
	struct mISDNdevice	*dev;
	struct mISDNversion	ver;

	switch (cmd) {
	case IMGETVERSION:
		ver.major = MISDN_MAJOR_VERSION;
		ver.minor = MISDN_MINOR_VERSION;
		ver.release = MISDN_RELEASE;
		if (copy_to_user((void __user *)arg, &ver, sizeof(ver)))
			err = -EFAULT;
		break;
	case IMGETCOUNT:
		id = get_mdevice_count();
		if (put_user(id, (int __user *)arg))
			err = -EFAULT;
		break;
	case IMGETDEVINFO:
		if (get_user(id, (int __user *)arg)) {
			err = -EFAULT;
			break;
		}
		dev = get_mdevice(id);
		if (dev) {
			struct mISDN_devinfo di;

379
			memset(&di, 0, sizeof(di));
Karsten Keil's avatar
Karsten Keil committed
380
381
382
383
384
			di.id = dev->id;
			di.Dprotocols = dev->Dprotocols;
			di.Bprotocols = dev->Bprotocols | get_all_Bprotocols();
			di.protocol = dev->D.protocol;
			memcpy(di.channelmap, dev->channelmap,
385
			       sizeof(di.channelmap));
Karsten Keil's avatar
Karsten Keil committed
386
			di.nrbchan = dev->nrbchan;
387
			strscpy(di.name, dev_name(&dev->dev), sizeof(di.name));
Karsten Keil's avatar
Karsten Keil committed
388
389
390
391
392
393
394
395
			if (copy_to_user((void __user *)arg, &di, sizeof(di)))
				err = -EFAULT;
		} else
			err = -ENODEV;
		break;
	default:
		if (sk->sk_state == MISDN_BOUND)
			err = data_sock_ioctl_bound(sk, cmd,
396
						    (void __user *)arg);
Karsten Keil's avatar
Karsten Keil committed
397
398
399
400
401
402
403
		else
			err = -ENOTCONN;
	}
	return err;
}

static int data_sock_setsockopt(struct socket *sock, int level, int optname,
404
				char __user *optval, unsigned int len)
Karsten Keil's avatar
Karsten Keil committed
405
406
407
408
409
410
{
	struct sock *sk = sock->sk;
	int err = 0, opt = 0;

	if (*debug & DEBUG_SOCKET)
		printk(KERN_DEBUG "%s(%p, %d, %x, %p, %d)\n", __func__, sock,
411
		       level, optname, optval, len);
Karsten Keil's avatar
Karsten Keil committed
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435

	lock_sock(sk);

	switch (optname) {
	case MISDN_TIME_STAMP:
		if (get_user(opt, (int __user *)optval)) {
			err = -EFAULT;
			break;
		}

		if (opt)
			_pms(sk)->cmask |= MISDN_TIME_STAMP;
		else
			_pms(sk)->cmask &= ~MISDN_TIME_STAMP;
		break;
	default:
		err = -ENOPROTOOPT;
		break;
	}
	release_sock(sk);
	return err;
}

static int data_sock_getsockopt(struct socket *sock, int level, int optname,
436
				char __user *optval, int __user *optlen)
Karsten Keil's avatar
Karsten Keil committed
437
438
439
440
441
442
443
{
	struct sock *sk = sock->sk;
	int len, opt;

	if (get_user(len, optlen))
		return -EFAULT;

444
445
446
	if (len != sizeof(char))
		return -EINVAL;

Karsten Keil's avatar
Karsten Keil committed
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
	switch (optname) {
	case MISDN_TIME_STAMP:
		if (_pms(sk)->cmask & MISDN_TIME_STAMP)
			opt = 1;
		else
			opt = 0;

		if (put_user(opt, optval))
			return -EFAULT;
		break;
	default:
		return -ENOPROTOOPT;
	}

	return 0;
}

static int
data_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
{
	struct sockaddr_mISDN *maddr = (struct sockaddr_mISDN *) addr;
	struct sock *sk = sock->sk;
469
	struct sock *csk;
Karsten Keil's avatar
Karsten Keil committed
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
	int err = 0;

	if (*debug & DEBUG_SOCKET)
		printk(KERN_DEBUG "%s(%p) sk=%p\n", __func__, sock, sk);
	if (addr_len != sizeof(struct sockaddr_mISDN))
		return -EINVAL;
	if (!maddr || maddr->family != AF_ISDN)
		return -EINVAL;

	lock_sock(sk);

	if (_pms(sk)->dev) {
		err = -EALREADY;
		goto done;
	}
	_pms(sk)->dev = get_mdevice(maddr->dev);
	if (!_pms(sk)->dev) {
		err = -ENODEV;
		goto done;
	}
490

491
492
	if (sk->sk_protocol < ISDN_P_B_START) {
		read_lock_bh(&data_sockets.lock);
493
		sk_for_each(csk, &data_sockets.head) {
494
495
496
497
498
499
500
			if (sk == csk)
				continue;
			if (_pms(csk)->dev != _pms(sk)->dev)
				continue;
			if (csk->sk_protocol >= ISDN_P_B_START)
				continue;
			if (IS_ISDN_P_TE(csk->sk_protocol)
501
			    == IS_ISDN_P_TE(sk->sk_protocol))
502
503
504
505
506
				continue;
			read_unlock_bh(&data_sockets.lock);
			err = -EBUSY;
			goto done;
		}
507
508
509
		read_unlock_bh(&data_sockets.lock);
	}

Karsten Keil's avatar
Karsten Keil committed
510
511
512
513
514
515
516
517
518
519
	_pms(sk)->ch.send = mISDN_send;
	_pms(sk)->ch.ctrl = mISDN_ctrl;

	switch (sk->sk_protocol) {
	case ISDN_P_TE_S0:
	case ISDN_P_NT_S0:
	case ISDN_P_TE_E1:
	case ISDN_P_NT_E1:
		mISDN_sock_unlink(&data_sockets, sk);
		err = connect_layer1(_pms(sk)->dev, &_pms(sk)->ch,
520
				     sk->sk_protocol, maddr);
Karsten Keil's avatar
Karsten Keil committed
521
522
523
524
525
526
		if (err)
			mISDN_sock_link(&data_sockets, sk);
		break;
	case ISDN_P_LAPD_TE:
	case ISDN_P_LAPD_NT:
		err = create_l2entity(_pms(sk)->dev, &_pms(sk)->ch,
527
				      sk->sk_protocol, maddr);
Karsten Keil's avatar
Karsten Keil committed
528
529
530
531
532
533
534
535
		break;
	case ISDN_P_B_RAW:
	case ISDN_P_B_HDLC:
	case ISDN_P_B_X75SLP:
	case ISDN_P_B_L2DTMF:
	case ISDN_P_B_L2DSP:
	case ISDN_P_B_L2DSPHDLC:
		err = connect_Bstack(_pms(sk)->dev, &_pms(sk)->ch,
536
				     sk->sk_protocol, maddr);
Karsten Keil's avatar
Karsten Keil committed
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
		break;
	default:
		err = -EPROTONOSUPPORT;
	}
	if (err)
		goto done;
	sk->sk_state = MISDN_BOUND;
	_pms(sk)->ch.protocol = sk->sk_protocol;

done:
	release_sock(sk);
	return err;
}

static int
data_sock_getname(struct socket *sock, struct sockaddr *addr,
553
		  int peer)
Karsten Keil's avatar
Karsten Keil committed
554
{
555
	struct sockaddr_mISDN	*maddr = (struct sockaddr_mISDN *) addr;
Karsten Keil's avatar
Karsten Keil committed
556
557
558
559
560
561
562
	struct sock		*sk = sock->sk;

	if (!_pms(sk)->dev)
		return -EBADFD;

	lock_sock(sk);

563
	maddr->family = AF_ISDN;
Karsten Keil's avatar
Karsten Keil committed
564
565
566
567
568
	maddr->dev = _pms(sk)->dev->id;
	maddr->channel = _pms(sk)->ch.nr;
	maddr->sapi = _pms(sk)->ch.addr & 0xff;
	maddr->tei = (_pms(sk)->ch.addr >> 8) & 0xff;
	release_sock(sk);
569
	return sizeof(*maddr);
Karsten Keil's avatar
Karsten Keil committed
570
571
572
573
574
575
576
577
578
579
580
}

static const struct proto_ops data_sock_ops = {
	.family		= PF_ISDN,
	.owner		= THIS_MODULE,
	.release	= data_sock_release,
	.ioctl		= data_sock_ioctl,
	.bind		= data_sock_bind,
	.getname	= data_sock_getname,
	.sendmsg	= mISDN_sock_sendmsg,
	.recvmsg	= mISDN_sock_recvmsg,
581
	.poll		= datagram_poll,
Karsten Keil's avatar
Karsten Keil committed
582
583
584
585
586
587
588
589
590
591
592
	.listen		= sock_no_listen,
	.shutdown	= sock_no_shutdown,
	.setsockopt	= data_sock_setsockopt,
	.getsockopt	= data_sock_getsockopt,
	.connect	= sock_no_connect,
	.socketpair	= sock_no_socketpair,
	.accept		= sock_no_accept,
	.mmap		= sock_no_mmap
};

static int
593
data_sock_create(struct net *net, struct socket *sock, int protocol, int kern)
Karsten Keil's avatar
Karsten Keil committed
594
595
596
597
598
599
{
	struct sock *sk;

	if (sock->type != SOCK_DGRAM)
		return -ESOCKTNOSUPPORT;

600
	sk = sk_alloc(net, PF_ISDN, GFP_KERNEL, &mISDN_proto, kern);
Karsten Keil's avatar
Karsten Keil committed
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
	if (!sk)
		return -ENOMEM;

	sock_init_data(sock, sk);

	sock->ops = &data_sock_ops;
	sock->state = SS_UNCONNECTED;
	sock_reset_flag(sk, SOCK_ZAPPED);

	sk->sk_protocol = protocol;
	sk->sk_state    = MISDN_OPEN;
	mISDN_sock_link(&data_sockets, sk);

	return 0;
}

static int
base_sock_release(struct socket *sock)
{
	struct sock *sk = sock->sk;

	printk(KERN_DEBUG "%s(%p) sk=%p\n", __func__, sock, sk);
	if (!sk)
		return 0;

	mISDN_sock_unlink(&base_sockets, sk);
	sock_orphan(sk);
	sock_put(sk);

	return 0;
}

static int
base_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{
636
	int			err = 0, id;
Karsten Keil's avatar
Karsten Keil committed
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
	struct mISDNdevice	*dev;
	struct mISDNversion	ver;

	switch (cmd) {
	case IMGETVERSION:
		ver.major = MISDN_MAJOR_VERSION;
		ver.minor = MISDN_MINOR_VERSION;
		ver.release = MISDN_RELEASE;
		if (copy_to_user((void __user *)arg, &ver, sizeof(ver)))
			err = -EFAULT;
		break;
	case IMGETCOUNT:
		id = get_mdevice_count();
		if (put_user(id, (int __user *)arg))
			err = -EFAULT;
		break;
	case IMGETDEVINFO:
		if (get_user(id, (int __user *)arg)) {
			err = -EFAULT;
			break;
		}
		dev = get_mdevice(id);
		if (dev) {
			struct mISDN_devinfo di;

662
			memset(&di, 0, sizeof(di));
Karsten Keil's avatar
Karsten Keil committed
663
664
665
666
667
			di.id = dev->id;
			di.Dprotocols = dev->Dprotocols;
			di.Bprotocols = dev->Bprotocols | get_all_Bprotocols();
			di.protocol = dev->D.protocol;
			memcpy(di.channelmap, dev->channelmap,
668
			       sizeof(di.channelmap));
Karsten Keil's avatar
Karsten Keil committed
669
			di.nrbchan = dev->nrbchan;
670
			strscpy(di.name, dev_name(&dev->dev), sizeof(di.name));
Karsten Keil's avatar
Karsten Keil committed
671
672
673
674
675
			if (copy_to_user((void __user *)arg, &di, sizeof(di)))
				err = -EFAULT;
		} else
			err = -ENODEV;
		break;
676
	case IMSETDEVNAME:
677
678
679
680
681
682
	{
		struct mISDN_devrename dn;
		if (copy_from_user(&dn, (void __user *)arg,
				   sizeof(dn))) {
			err = -EFAULT;
			break;
683
		}
684
		dn.name[sizeof(dn.name) - 1] = '\0';
685
686
687
688
689
690
691
		dev = get_mdevice(dn.id);
		if (dev)
			err = device_rename(&dev->dev, dn.name);
		else
			err = -ENODEV;
	}
	break;
Karsten Keil's avatar
Karsten Keil committed
692
693
694
695
696
697
698
699
700
701
702
703
704
	default:
		err = -EINVAL;
	}
	return err;
}

static int
base_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
{
	struct sockaddr_mISDN *maddr = (struct sockaddr_mISDN *) addr;
	struct sock *sk = sock->sk;
	int err = 0;

705
	if (addr_len < sizeof(struct sockaddr_mISDN))
Karsten Keil's avatar
Karsten Keil committed
706
707
		return -EINVAL;

708
	if (!maddr || maddr->family != AF_ISDN)
709
710
		return -EINVAL;

Karsten Keil's avatar
Karsten Keil committed
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
	lock_sock(sk);

	if (_pms(sk)->dev) {
		err = -EALREADY;
		goto done;
	}

	_pms(sk)->dev = get_mdevice(maddr->dev);
	if (!_pms(sk)->dev) {
		err = -ENODEV;
		goto done;
	}
	sk->sk_state = MISDN_BOUND;

done:
	release_sock(sk);
	return err;
}

static const struct proto_ops base_sock_ops = {
	.family		= PF_ISDN,
	.owner		= THIS_MODULE,
	.release	= base_sock_release,
	.ioctl		= base_sock_ioctl,
	.bind		= base_sock_bind,
	.getname	= sock_no_getname,
	.sendmsg	= sock_no_sendmsg,
	.recvmsg	= sock_no_recvmsg,
	.listen		= sock_no_listen,
	.shutdown	= sock_no_shutdown,
	.setsockopt	= sock_no_setsockopt,
	.getsockopt	= sock_no_getsockopt,
	.connect	= sock_no_connect,
	.socketpair	= sock_no_socketpair,
	.accept		= sock_no_accept,
	.mmap		= sock_no_mmap
};


static int
751
base_sock_create(struct net *net, struct socket *sock, int protocol, int kern)
Karsten Keil's avatar
Karsten Keil committed
752
753
754
755
756
{
	struct sock *sk;

	if (sock->type != SOCK_RAW)
		return -ESOCKTNOSUPPORT;
757
758
	if (!capable(CAP_NET_RAW))
		return -EPERM;
Karsten Keil's avatar
Karsten Keil committed
759

760
	sk = sk_alloc(net, PF_ISDN, GFP_KERNEL, &mISDN_proto, kern);
Karsten Keil's avatar
Karsten Keil committed
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
	if (!sk)
		return -ENOMEM;

	sock_init_data(sock, sk);
	sock->ops = &base_sock_ops;
	sock->state = SS_UNCONNECTED;
	sock_reset_flag(sk, SOCK_ZAPPED);
	sk->sk_protocol = protocol;
	sk->sk_state    = MISDN_OPEN;
	mISDN_sock_link(&base_sockets, sk);

	return 0;
}

static int
776
mISDN_sock_create(struct net *net, struct socket *sock, int proto, int kern)
Karsten Keil's avatar
Karsten Keil committed
777
778
779
{
	int err = -EPROTONOSUPPORT;

780
	switch (proto) {
Karsten Keil's avatar
Karsten Keil committed
781
	case ISDN_P_BASE:
782
		err = base_sock_create(net, sock, proto, kern);
Karsten Keil's avatar
Karsten Keil committed
783
784
785
786
787
788
789
790
791
792
793
794
795
		break;
	case ISDN_P_TE_S0:
	case ISDN_P_NT_S0:
	case ISDN_P_TE_E1:
	case ISDN_P_NT_E1:
	case ISDN_P_LAPD_TE:
	case ISDN_P_LAPD_NT:
	case ISDN_P_B_RAW:
	case ISDN_P_B_HDLC:
	case ISDN_P_B_X75SLP:
	case ISDN_P_B_L2DTMF:
	case ISDN_P_B_L2DSP:
	case ISDN_P_B_L2DSPHDLC:
796
		err = data_sock_create(net, sock, proto, kern);
Karsten Keil's avatar
Karsten Keil committed
797
798
799
800
801
802
803
804
		break;
	default:
		return err;
	}

	return err;
}

805
static const struct net_proto_family mISDN_sock_family_ops = {
Karsten Keil's avatar
Karsten Keil committed
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
	.owner  = THIS_MODULE,
	.family = PF_ISDN,
	.create = mISDN_sock_create,
};

int
misdn_sock_init(u_int *deb)
{
	int err;

	debug = deb;
	err = sock_register(&mISDN_sock_family_ops);
	if (err)
		printk(KERN_ERR "%s: error(%d)\n", __func__, err);
	return err;
}

void
misdn_sock_cleanup(void)
{
	sock_unregister(PF_ISDN);
}