11b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil/*
21b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil *
31b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil * Author	Karsten Keil <kkeil@novell.com>
41b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil *
51b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil * Copyright 2008  by Karsten Keil <kkeil@novell.com>
61b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil *
71b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil * This program is free software; you can redistribute it and/or modify
81b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil * it under the terms of the GNU General Public License version 2 as
91b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil * published by the Free Software Foundation.
101b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil *
111b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil * This program is distributed in the hope that it will be useful,
121b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil * but WITHOUT ANY WARRANTY; without even the implied warranty of
131b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
141b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil * GNU General Public License for more details.
151b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil *
161b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil */
171b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
181b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil#include <linux/mISDNif.h>
195a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
205d76fc219ce38a226314436563f6b9d405bb6db1Paul Gortmaker#include <linux/export.h>
211b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil#include "core.h"
221b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
23dfa96ec1bb83641242c48883c2bae8f1f30483b2Hannes Ederstatic u_int	*debug;
241b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
251b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilstatic struct proto mISDN_proto = {
261b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.name		= "misdn",
271b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.owner		= THIS_MODULE,
281b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.obj_size	= sizeof(struct mISDN_sock)
291b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil};
301b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
311b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil#define _pms(sk)	((struct mISDN_sock *)sk)
321b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
331b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilstatic struct mISDN_sock_list	data_sockets = {
341b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.lock = __RW_LOCK_UNLOCKED(data_sockets.lock)
351b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil};
361b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
371b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilstatic struct mISDN_sock_list	base_sockets = {
381b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.lock = __RW_LOCK_UNLOCKED(base_sockets.lock)
391b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil};
401b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
411b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil#define L2_HEADER_LEN	4
421b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
431b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilstatic inline struct sk_buff *
441b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil_l2_alloc_skb(unsigned int len, gfp_t gfp_mask)
451b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
461b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct sk_buff  *skb;
471b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
481b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	skb = alloc_skb(len + L2_HEADER_LEN, gfp_mask);
491b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (likely(skb))
501b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		skb_reserve(skb, L2_HEADER_LEN);
511b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	return skb;
521b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
531b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
541b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilstatic void
551b2b03f8e514e4f68e293846ba511a948b80243cKarsten KeilmISDN_sock_link(struct mISDN_sock_list *l, struct sock *sk)
561b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
571b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	write_lock_bh(&l->lock);
581b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	sk_add_node(sk, &l->head);
591b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	write_unlock_bh(&l->lock);
601b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
611b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
621b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilstatic void mISDN_sock_unlink(struct mISDN_sock_list *l, struct sock *sk)
631b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
641b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	write_lock_bh(&l->lock);
651b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	sk_del_node_init(sk);
661b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	write_unlock_bh(&l->lock);
671b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
681b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
691b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilstatic int
701b2b03f8e514e4f68e293846ba511a948b80243cKarsten KeilmISDN_send(struct mISDNchannel *ch, struct sk_buff *skb)
711b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
721b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct mISDN_sock *msk;
731b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	int	err;
741b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
751b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	msk = container_of(ch, struct mISDN_sock, ch);
761b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (*debug & DEBUG_SOCKET)
771b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		printk(KERN_DEBUG "%s len %d %p\n", __func__, skb->len, skb);
781b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (msk->sk.sk_state == MISDN_CLOSED)
791b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		return -EUNATCH;
801b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	__net_timestamp(skb);
811b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	err = sock_queue_rcv_skb(&msk->sk, skb);
821b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (err)
831b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		printk(KERN_WARNING "%s: error %d\n", __func__, err);
841b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	return err;
851b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
861b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
871b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilstatic int
881b2b03f8e514e4f68e293846ba511a948b80243cKarsten KeilmISDN_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
891b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
901b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct mISDN_sock *msk;
911b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
921b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	msk = container_of(ch, struct mISDN_sock, ch);
931b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (*debug & DEBUG_SOCKET)
941b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		printk(KERN_DEBUG "%s(%p, %x, %p)\n", __func__, ch, cmd, arg);
951b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	switch (cmd) {
961b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case CLOSE_CHANNEL:
971b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		msk->sk.sk_state = MISDN_CLOSED;
981b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		break;
991b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	}
1001b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	return 0;
1011b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
1021b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
1031b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilstatic inline void
1041b2b03f8e514e4f68e293846ba511a948b80243cKarsten KeilmISDN_sock_cmsg(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
1051b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
1061b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct timeval	tv;
1071b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
1081b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (_pms(sk)->cmask & MISDN_TIME_STAMP) {
1091b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		skb_get_timestamp(skb, &tv);
1101b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		put_cmsg(msg, SOL_MISDN, MISDN_TIME_STAMP, sizeof(tv), &tv);
1111b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	}
1121b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
1131b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
1141b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilstatic int
1151b2b03f8e514e4f68e293846ba511a948b80243cKarsten KeilmISDN_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
116475be4d85a274d0961593db41cf85689db1d583cJoe Perches		   struct msghdr *msg, size_t len, int flags)
1171b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
1181b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct sk_buff		*skb;
1191b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct sock		*sk = sock->sk;
1201b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct sockaddr_mISDN	*maddr;
1211b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
1221b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	int		copied, err;
1231b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
1241b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (*debug & DEBUG_SOCKET)
1251b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		printk(KERN_DEBUG "%s: len %d, flags %x ch.nr %d, proto %x\n",
126475be4d85a274d0961593db41cf85689db1d583cJoe Perches		       __func__, (int)len, flags, _pms(sk)->ch.nr,
127475be4d85a274d0961593db41cf85689db1d583cJoe Perches		       sk->sk_protocol);
1281b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (flags & (MSG_OOB))
1291b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		return -EOPNOTSUPP;
1301b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
1311b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (sk->sk_state == MISDN_CLOSED)
1321b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		return 0;
1331b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
1341b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	skb = skb_recv_datagram(sk, flags, flags & MSG_DONTWAIT, &err);
1351b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (!skb)
1361b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		return err;
1371b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
1381b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (msg->msg_namelen >= sizeof(struct sockaddr_mISDN)) {
1391b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		msg->msg_namelen = sizeof(struct sockaddr_mISDN);
1401b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		maddr = (struct sockaddr_mISDN *)msg->msg_name;
1411b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		maddr->family = AF_ISDN;
1421b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		maddr->dev = _pms(sk)->dev->id;
1431b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if ((sk->sk_protocol == ISDN_P_LAPD_TE) ||
1441b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		    (sk->sk_protocol == ISDN_P_LAPD_NT)) {
1451b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			maddr->channel = (mISDN_HEAD_ID(skb) >> 16) & 0xff;
1461b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			maddr->tei =  (mISDN_HEAD_ID(skb) >> 8) & 0xff;
1471b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			maddr->sapi = mISDN_HEAD_ID(skb) & 0xff;
1481b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		} else {
1491b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			maddr->channel = _pms(sk)->ch.nr;
1501b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			maddr->sapi = _pms(sk)->ch.addr & 0xFF;
1511b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			maddr->tei =  (_pms(sk)->ch.addr >> 8) & 0xFF;
1521b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		}
1531b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	} else {
1541b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (msg->msg_namelen)
1551b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			printk(KERN_WARNING "%s: too small namelen %d\n",
156475be4d85a274d0961593db41cf85689db1d583cJoe Perches			       __func__, msg->msg_namelen);
1571b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		msg->msg_namelen = 0;
1581b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	}
1591b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
1601b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	copied = skb->len + MISDN_HEADER_LEN;
1611b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (len < copied) {
1621b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (flags & MSG_PEEK)
1631b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			atomic_dec(&skb->users);
1641b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		else
1651b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			skb_queue_head(&sk->sk_receive_queue, skb);
1661b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		return -ENOSPC;
1671b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	}
1681b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	memcpy(skb_push(skb, MISDN_HEADER_LEN), mISDN_HEAD_P(skb),
169475be4d85a274d0961593db41cf85689db1d583cJoe Perches	       MISDN_HEADER_LEN);
1701b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
1711b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
1721b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
1731b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	mISDN_sock_cmsg(sk, msg, skb);
1741b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
1751b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	skb_free_datagram(sk, skb);
1761b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
1771b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	return err ? : copied;
1781b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
1791b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
1801b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilstatic int
1811b2b03f8e514e4f68e293846ba511a948b80243cKarsten KeilmISDN_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
182475be4d85a274d0961593db41cf85689db1d583cJoe Perches		   struct msghdr *msg, size_t len)
1831b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
1841b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct sock		*sk = sock->sk;
1851b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct sk_buff		*skb;
1861b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	int			err = -ENOMEM;
1871b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct sockaddr_mISDN	*maddr;
1881b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
1891b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (*debug & DEBUG_SOCKET)
1901b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		printk(KERN_DEBUG "%s: len %d flags %x ch %d proto %x\n",
191475be4d85a274d0961593db41cf85689db1d583cJoe Perches		       __func__, (int)len, msg->msg_flags, _pms(sk)->ch.nr,
192475be4d85a274d0961593db41cf85689db1d583cJoe Perches		       sk->sk_protocol);
1931b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
1941b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (msg->msg_flags & MSG_OOB)
1951b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		return -EOPNOTSUPP;
1961b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
197475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if (msg->msg_flags & ~(MSG_DONTWAIT | MSG_NOSIGNAL | MSG_ERRQUEUE))
1981b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		return -EINVAL;
1991b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
2001b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (len < MISDN_HEADER_LEN)
2011b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		return -EINVAL;
2021b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
2031b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (sk->sk_state != MISDN_BOUND)
2041b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		return -EBADFD;
2051b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
2061b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	lock_sock(sk);
2071b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
2081b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	skb = _l2_alloc_skb(len, GFP_KERNEL);
2091b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (!skb)
2101b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		goto done;
2111b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
2121b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
2131b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		err = -EFAULT;
2145df3b8bcc7826b85a2d233dd20da3ed247e1dc1dKarsten Keil		goto done;
2151b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	}
2161b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
2171b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	memcpy(mISDN_HEAD_P(skb), skb->data, MISDN_HEADER_LEN);
2181b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	skb_pull(skb, MISDN_HEADER_LEN);
2191b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
2201b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (msg->msg_namelen >= sizeof(struct sockaddr_mISDN)) {
2211b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		/* if we have a address, we use it */
2221b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		maddr = (struct sockaddr_mISDN *)msg->msg_name;
2231b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		mISDN_HEAD_ID(skb) = maddr->channel;
2241b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	} else { /* use default for L2 messages */
2251b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if ((sk->sk_protocol == ISDN_P_LAPD_TE) ||
2261b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		    (sk->sk_protocol == ISDN_P_LAPD_NT))
227eac74af9b547e29c9634ed5eff4d514349e73310Karsten Keil			mISDN_HEAD_ID(skb) = _pms(sk)->ch.nr;
2281b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	}
2291b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
2301b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (*debug & DEBUG_SOCKET)
2311b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		printk(KERN_DEBUG "%s: ID:%x\n",
232475be4d85a274d0961593db41cf85689db1d583cJoe Perches		       __func__, mISDN_HEAD_ID(skb));
2331b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
2341b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	err = -ENODEV;
2355df3b8bcc7826b85a2d233dd20da3ed247e1dc1dKarsten Keil	if (!_pms(sk)->ch.peer)
2365df3b8bcc7826b85a2d233dd20da3ed247e1dc1dKarsten Keil		goto done;
2375df3b8bcc7826b85a2d233dd20da3ed247e1dc1dKarsten Keil	err = _pms(sk)->ch.recv(_pms(sk)->ch.peer, skb);
2385df3b8bcc7826b85a2d233dd20da3ed247e1dc1dKarsten Keil	if (err)
2395df3b8bcc7826b85a2d233dd20da3ed247e1dc1dKarsten Keil		goto done;
2405df3b8bcc7826b85a2d233dd20da3ed247e1dc1dKarsten Keil	else {
2415df3b8bcc7826b85a2d233dd20da3ed247e1dc1dKarsten Keil		skb = NULL;
2425df3b8bcc7826b85a2d233dd20da3ed247e1dc1dKarsten Keil		err = len;
2435df3b8bcc7826b85a2d233dd20da3ed247e1dc1dKarsten Keil	}
2441b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
2451b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keildone:
2465df3b8bcc7826b85a2d233dd20da3ed247e1dc1dKarsten Keil	if (skb)
2475df3b8bcc7826b85a2d233dd20da3ed247e1dc1dKarsten Keil		kfree_skb(skb);
2481b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	release_sock(sk);
2491b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	return err;
2501b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
2511b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
2521b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilstatic int
2531b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keildata_sock_release(struct socket *sock)
2541b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
2551b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct sock *sk = sock->sk;
2561b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
2571b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (*debug & DEBUG_SOCKET)
2581b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		printk(KERN_DEBUG "%s(%p) sk=%p\n", __func__, sock, sk);
2591b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (!sk)
2601b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		return 0;
2611b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	switch (sk->sk_protocol) {
2621b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_TE_S0:
2631b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_NT_S0:
2641b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_TE_E1:
2651b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_NT_E1:
2661b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (sk->sk_state == MISDN_BOUND)
2671b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			delete_channel(&_pms(sk)->ch);
2681b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		else
2691b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			mISDN_sock_unlink(&data_sockets, sk);
2701b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		break;
2711b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_LAPD_TE:
2721b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_LAPD_NT:
2731b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_B_RAW:
2741b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_B_HDLC:
2751b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_B_X75SLP:
2761b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_B_L2DTMF:
2771b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_B_L2DSP:
2781b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_B_L2DSPHDLC:
2791b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		delete_channel(&_pms(sk)->ch);
2801b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		mISDN_sock_unlink(&data_sockets, sk);
2811b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		break;
2821b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	}
2831b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
2841b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	lock_sock(sk);
2851b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
2861b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	sock_orphan(sk);
2871b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	skb_queue_purge(&sk->sk_receive_queue);
2881b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
2891b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	release_sock(sk);
2901b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	sock_put(sk);
2911b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
2921b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	return 0;
2931b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
2941b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
2951b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilstatic int
2961b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keildata_sock_ioctl_bound(struct sock *sk, unsigned int cmd, void __user *p)
2971b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
2981b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct mISDN_ctrl_req	cq;
299e73f6b2260daf02793071e5ce06ea87df762920aAndreas Eversberg	int			err = -EINVAL, val[2];
3001b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct mISDNchannel	*bchan, *next;
3011b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
3021b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	lock_sock(sk);
3031b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (!_pms(sk)->dev) {
3041b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		err = -ENODEV;
3051b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		goto done;
3061b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	}
3071b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	switch (cmd) {
3081b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case IMCTRLREQ:
3091b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (copy_from_user(&cq, p, sizeof(cq))) {
3101b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			err = -EFAULT;
3111b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			break;
3121b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		}
3131b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if ((sk->sk_protocol & ~ISDN_P_B_MASK) == ISDN_P_B_START) {
3141b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			list_for_each_entry_safe(bchan, next,
315475be4d85a274d0961593db41cf85689db1d583cJoe Perches						 &_pms(sk)->dev->bchannels, list) {
3161b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil				if (bchan->nr == cq.channel) {
3171b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil					err = bchan->ctrl(bchan,
318475be4d85a274d0961593db41cf85689db1d583cJoe Perches							  CONTROL_CHANNEL, &cq);
3191b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil					break;
3201b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil				}
3211b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			}
3221b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		} else
3231b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			err = _pms(sk)->dev->D.ctrl(&_pms(sk)->dev->D,
324475be4d85a274d0961593db41cf85689db1d583cJoe Perches						    CONTROL_CHANNEL, &cq);
3251b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (err)
3261b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			break;
3271b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (copy_to_user(p, &cq, sizeof(cq)))
3281b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			err = -EFAULT;
3291b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		break;
3301b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case IMCLEAR_L2:
3311b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (sk->sk_protocol != ISDN_P_LAPD_NT) {
3321b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			err = -EINVAL;
3331b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			break;
3341b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		}
335e73f6b2260daf02793071e5ce06ea87df762920aAndreas Eversberg		val[0] = cmd;
336e73f6b2260daf02793071e5ce06ea87df762920aAndreas Eversberg		if (get_user(val[1], (int __user *)p)) {
3371b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			err = -EFAULT;
3381b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			break;
3391b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		}
3401b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		err = _pms(sk)->dev->teimgr->ctrl(_pms(sk)->dev->teimgr,
341475be4d85a274d0961593db41cf85689db1d583cJoe Perches						  CONTROL_CHANNEL, val);
342e73f6b2260daf02793071e5ce06ea87df762920aAndreas Eversberg		break;
343e73f6b2260daf02793071e5ce06ea87df762920aAndreas Eversberg	case IMHOLD_L1:
344e73f6b2260daf02793071e5ce06ea87df762920aAndreas Eversberg		if (sk->sk_protocol != ISDN_P_LAPD_NT
345475be4d85a274d0961593db41cf85689db1d583cJoe Perches		    && sk->sk_protocol != ISDN_P_LAPD_TE) {
346e73f6b2260daf02793071e5ce06ea87df762920aAndreas Eversberg			err = -EINVAL;
347e73f6b2260daf02793071e5ce06ea87df762920aAndreas Eversberg			break;
348e73f6b2260daf02793071e5ce06ea87df762920aAndreas Eversberg		}
349e73f6b2260daf02793071e5ce06ea87df762920aAndreas Eversberg		val[0] = cmd;
350e73f6b2260daf02793071e5ce06ea87df762920aAndreas Eversberg		if (get_user(val[1], (int __user *)p)) {
351e73f6b2260daf02793071e5ce06ea87df762920aAndreas Eversberg			err = -EFAULT;
352e73f6b2260daf02793071e5ce06ea87df762920aAndreas Eversberg			break;
353e73f6b2260daf02793071e5ce06ea87df762920aAndreas Eversberg		}
354e73f6b2260daf02793071e5ce06ea87df762920aAndreas Eversberg		err = _pms(sk)->dev->teimgr->ctrl(_pms(sk)->dev->teimgr,
355475be4d85a274d0961593db41cf85689db1d583cJoe Perches						  CONTROL_CHANNEL, val);
3561b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		break;
3571b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	default:
3581b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		err = -EINVAL;
3591b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		break;
3601b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	}
3611b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keildone:
3621b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	release_sock(sk);
3631b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	return err;
3641b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
3651b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
3661b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilstatic int
3671b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keildata_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
3681b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
369475be4d85a274d0961593db41cf85689db1d583cJoe Perches	int			err = 0, id;
3701b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct sock		*sk = sock->sk;
3711b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct mISDNdevice	*dev;
3721b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct mISDNversion	ver;
3731b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
3741b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	switch (cmd) {
3751b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case IMGETVERSION:
3761b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		ver.major = MISDN_MAJOR_VERSION;
3771b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		ver.minor = MISDN_MINOR_VERSION;
3781b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		ver.release = MISDN_RELEASE;
3791b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (copy_to_user((void __user *)arg, &ver, sizeof(ver)))
3801b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			err = -EFAULT;
3811b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		break;
3821b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case IMGETCOUNT:
3831b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		id = get_mdevice_count();
3841b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (put_user(id, (int __user *)arg))
3851b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			err = -EFAULT;
3861b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		break;
3871b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case IMGETDEVINFO:
3881b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (get_user(id, (int __user *)arg)) {
3891b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			err = -EFAULT;
3901b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			break;
3911b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		}
3921b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		dev = get_mdevice(id);
3931b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (dev) {
3941b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			struct mISDN_devinfo di;
3951b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
396ce384d91cd7a4269a1ed5d4307a70aa4c6fa14f2Kulikov Vasiliy			memset(&di, 0, sizeof(di));
3971b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			di.id = dev->id;
3981b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			di.Dprotocols = dev->Dprotocols;
3991b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			di.Bprotocols = dev->Bprotocols | get_all_Bprotocols();
4001b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			di.protocol = dev->D.protocol;
4011b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			memcpy(di.channelmap, dev->channelmap,
402475be4d85a274d0961593db41cf85689db1d583cJoe Perches			       sizeof(di.channelmap));
4031b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			di.nrbchan = dev->nrbchan;
404837468d135dcc49cdabc9fa92fc9550479f60704Matthias Urlichs			strcpy(di.name, dev_name(&dev->dev));
4051b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			if (copy_to_user((void __user *)arg, &di, sizeof(di)))
4061b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil				err = -EFAULT;
4071b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		} else
4081b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			err = -ENODEV;
4091b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		break;
4101b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	default:
4111b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (sk->sk_state == MISDN_BOUND)
4121b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			err = data_sock_ioctl_bound(sk, cmd,
413475be4d85a274d0961593db41cf85689db1d583cJoe Perches						    (void __user *)arg);
4141b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		else
4151b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			err = -ENOTCONN;
4161b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	}
4171b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	return err;
4181b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
4191b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
4201b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilstatic int data_sock_setsockopt(struct socket *sock, int level, int optname,
421475be4d85a274d0961593db41cf85689db1d583cJoe Perches				char __user *optval, unsigned int len)
4221b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
4231b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct sock *sk = sock->sk;
4241b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	int err = 0, opt = 0;
4251b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
4261b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (*debug & DEBUG_SOCKET)
4271b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		printk(KERN_DEBUG "%s(%p, %d, %x, %p, %d)\n", __func__, sock,
428475be4d85a274d0961593db41cf85689db1d583cJoe Perches		       level, optname, optval, len);
4291b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
4301b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	lock_sock(sk);
4311b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
4321b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	switch (optname) {
4331b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case MISDN_TIME_STAMP:
4341b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (get_user(opt, (int __user *)optval)) {
4351b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			err = -EFAULT;
4361b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			break;
4371b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		}
4381b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
4391b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (opt)
4401b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			_pms(sk)->cmask |= MISDN_TIME_STAMP;
4411b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		else
4421b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			_pms(sk)->cmask &= ~MISDN_TIME_STAMP;
4431b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		break;
4441b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	default:
4451b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		err = -ENOPROTOOPT;
4461b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		break;
4471b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	}
4481b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	release_sock(sk);
4491b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	return err;
4501b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
4511b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
4521b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilstatic int data_sock_getsockopt(struct socket *sock, int level, int optname,
453475be4d85a274d0961593db41cf85689db1d583cJoe Perches				char __user *optval, int __user *optlen)
4541b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
4551b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct sock *sk = sock->sk;
4561b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	int len, opt;
4571b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
4581b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (get_user(len, optlen))
4591b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		return -EFAULT;
4601b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
46181b424d9e2ef815b2035d4c2be0bc41dddbebc06David S. Miller	if (len != sizeof(char))
46281b424d9e2ef815b2035d4c2be0bc41dddbebc06David S. Miller		return -EINVAL;
46381b424d9e2ef815b2035d4c2be0bc41dddbebc06David S. Miller
4641b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	switch (optname) {
4651b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case MISDN_TIME_STAMP:
4661b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (_pms(sk)->cmask & MISDN_TIME_STAMP)
4671b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			opt = 1;
4681b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		else
4691b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			opt = 0;
4701b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
4711b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (put_user(opt, optval))
4721b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			return -EFAULT;
4731b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		break;
4741b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	default:
4751b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		return -ENOPROTOOPT;
4761b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	}
4771b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
4781b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	return 0;
4791b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
4801b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
4811b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilstatic int
4821b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keildata_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
4831b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
4841b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct sockaddr_mISDN *maddr = (struct sockaddr_mISDN *) addr;
4851b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct sock *sk = sock->sk;
4861b4d33121f1d991f6ae226cc3333428ff87627bbAndreas Eversberg	struct hlist_node *node;
4871b4d33121f1d991f6ae226cc3333428ff87627bbAndreas Eversberg	struct sock *csk;
4881b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	int err = 0;
4891b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
4901b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (*debug & DEBUG_SOCKET)
4911b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		printk(KERN_DEBUG "%s(%p) sk=%p\n", __func__, sock, sk);
4921b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (addr_len != sizeof(struct sockaddr_mISDN))
4931b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		return -EINVAL;
4941b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (!maddr || maddr->family != AF_ISDN)
4951b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		return -EINVAL;
4961b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
4971b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	lock_sock(sk);
4981b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
4991b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (_pms(sk)->dev) {
5001b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		err = -EALREADY;
5011b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		goto done;
5021b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	}
5031b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	_pms(sk)->dev = get_mdevice(maddr->dev);
5041b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (!_pms(sk)->dev) {
5051b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		err = -ENODEV;
5061b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		goto done;
5071b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	}
5081b4d33121f1d991f6ae226cc3333428ff87627bbAndreas Eversberg
5099a812553bdc097a566aa79df7fae3457449c555bAndreas Eversberg	if (sk->sk_protocol < ISDN_P_B_START) {
5109a812553bdc097a566aa79df7fae3457449c555bAndreas Eversberg		read_lock_bh(&data_sockets.lock);
5119a812553bdc097a566aa79df7fae3457449c555bAndreas Eversberg		sk_for_each(csk, node, &data_sockets.head) {
5129a812553bdc097a566aa79df7fae3457449c555bAndreas Eversberg			if (sk == csk)
5139a812553bdc097a566aa79df7fae3457449c555bAndreas Eversberg				continue;
5149a812553bdc097a566aa79df7fae3457449c555bAndreas Eversberg			if (_pms(csk)->dev != _pms(sk)->dev)
5159a812553bdc097a566aa79df7fae3457449c555bAndreas Eversberg				continue;
5169a812553bdc097a566aa79df7fae3457449c555bAndreas Eversberg			if (csk->sk_protocol >= ISDN_P_B_START)
5179a812553bdc097a566aa79df7fae3457449c555bAndreas Eversberg				continue;
5189a812553bdc097a566aa79df7fae3457449c555bAndreas Eversberg			if (IS_ISDN_P_TE(csk->sk_protocol)
519475be4d85a274d0961593db41cf85689db1d583cJoe Perches			    == IS_ISDN_P_TE(sk->sk_protocol))
5209a812553bdc097a566aa79df7fae3457449c555bAndreas Eversberg				continue;
5219a812553bdc097a566aa79df7fae3457449c555bAndreas Eversberg			read_unlock_bh(&data_sockets.lock);
5229a812553bdc097a566aa79df7fae3457449c555bAndreas Eversberg			err = -EBUSY;
5239a812553bdc097a566aa79df7fae3457449c555bAndreas Eversberg			goto done;
5249a812553bdc097a566aa79df7fae3457449c555bAndreas Eversberg		}
5251b4d33121f1d991f6ae226cc3333428ff87627bbAndreas Eversberg		read_unlock_bh(&data_sockets.lock);
5261b4d33121f1d991f6ae226cc3333428ff87627bbAndreas Eversberg	}
5271b4d33121f1d991f6ae226cc3333428ff87627bbAndreas Eversberg
5281b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	_pms(sk)->ch.send = mISDN_send;
5291b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	_pms(sk)->ch.ctrl = mISDN_ctrl;
5301b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
5311b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	switch (sk->sk_protocol) {
5321b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_TE_S0:
5331b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_NT_S0:
5341b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_TE_E1:
5351b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_NT_E1:
5361b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		mISDN_sock_unlink(&data_sockets, sk);
5371b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		err = connect_layer1(_pms(sk)->dev, &_pms(sk)->ch,
538475be4d85a274d0961593db41cf85689db1d583cJoe Perches				     sk->sk_protocol, maddr);
5391b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (err)
5401b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			mISDN_sock_link(&data_sockets, sk);
5411b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		break;
5421b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_LAPD_TE:
5431b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_LAPD_NT:
5441b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		err = create_l2entity(_pms(sk)->dev, &_pms(sk)->ch,
545475be4d85a274d0961593db41cf85689db1d583cJoe Perches				      sk->sk_protocol, maddr);
5461b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		break;
5471b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_B_RAW:
5481b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_B_HDLC:
5491b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_B_X75SLP:
5501b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_B_L2DTMF:
5511b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_B_L2DSP:
5521b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_B_L2DSPHDLC:
5531b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		err = connect_Bstack(_pms(sk)->dev, &_pms(sk)->ch,
554475be4d85a274d0961593db41cf85689db1d583cJoe Perches				     sk->sk_protocol, maddr);
5551b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		break;
5561b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	default:
5571b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		err = -EPROTONOSUPPORT;
5581b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	}
5591b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (err)
5601b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		goto done;
5611b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	sk->sk_state = MISDN_BOUND;
5621b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	_pms(sk)->ch.protocol = sk->sk_protocol;
5631b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
5641b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keildone:
5651b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	release_sock(sk);
5661b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	return err;
5671b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
5681b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
5691b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilstatic int
5701b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keildata_sock_getname(struct socket *sock, struct sockaddr *addr,
571475be4d85a274d0961593db41cf85689db1d583cJoe Perches		  int *addr_len, int peer)
5721b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
573475be4d85a274d0961593db41cf85689db1d583cJoe Perches	struct sockaddr_mISDN	*maddr = (struct sockaddr_mISDN *) addr;
5741b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct sock		*sk = sock->sk;
5751b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
5761b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (!_pms(sk)->dev)
5771b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		return -EBADFD;
5781b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
5791b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	lock_sock(sk);
5801b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
5811b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	*addr_len = sizeof(*maddr);
5821b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	maddr->dev = _pms(sk)->dev->id;
5831b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	maddr->channel = _pms(sk)->ch.nr;
5841b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	maddr->sapi = _pms(sk)->ch.addr & 0xff;
5851b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	maddr->tei = (_pms(sk)->ch.addr >> 8) & 0xff;
5861b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	release_sock(sk);
5871b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	return 0;
5881b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
5891b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
5901b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilstatic const struct proto_ops data_sock_ops = {
5911b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.family		= PF_ISDN,
5921b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.owner		= THIS_MODULE,
5931b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.release	= data_sock_release,
5941b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.ioctl		= data_sock_ioctl,
5951b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.bind		= data_sock_bind,
5961b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.getname	= data_sock_getname,
5971b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.sendmsg	= mISDN_sock_sendmsg,
5981b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.recvmsg	= mISDN_sock_recvmsg,
5991b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.poll		= datagram_poll,
6001b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.listen		= sock_no_listen,
6011b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.shutdown	= sock_no_shutdown,
6021b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.setsockopt	= data_sock_setsockopt,
6031b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.getsockopt	= data_sock_getsockopt,
6041b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.connect	= sock_no_connect,
6051b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.socketpair	= sock_no_socketpair,
6061b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.accept		= sock_no_accept,
6071b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.mmap		= sock_no_mmap
6081b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil};
6091b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
6101b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilstatic int
6111b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keildata_sock_create(struct net *net, struct socket *sock, int protocol)
6121b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
6131b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct sock *sk;
6141b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
6151b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (sock->type != SOCK_DGRAM)
6161b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		return -ESOCKTNOSUPPORT;
6171b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
6181b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	sk = sk_alloc(net, PF_ISDN, GFP_KERNEL, &mISDN_proto);
6191b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (!sk)
6201b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		return -ENOMEM;
6211b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
6221b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	sock_init_data(sock, sk);
6231b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
6241b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	sock->ops = &data_sock_ops;
6251b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	sock->state = SS_UNCONNECTED;
6261b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	sock_reset_flag(sk, SOCK_ZAPPED);
6271b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
6281b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	sk->sk_protocol = protocol;
6291b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	sk->sk_state    = MISDN_OPEN;
6301b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	mISDN_sock_link(&data_sockets, sk);
6311b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
6321b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	return 0;
6331b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
6341b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
6351b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilstatic int
6361b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilbase_sock_release(struct socket *sock)
6371b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
6381b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct sock *sk = sock->sk;
6391b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
6401b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	printk(KERN_DEBUG "%s(%p) sk=%p\n", __func__, sock, sk);
6411b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (!sk)
6421b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		return 0;
6431b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
6441b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	mISDN_sock_unlink(&base_sockets, sk);
6451b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	sock_orphan(sk);
6461b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	sock_put(sk);
6471b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
6481b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	return 0;
6491b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
6501b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
6511b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilstatic int
6521b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilbase_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
6531b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
654475be4d85a274d0961593db41cf85689db1d583cJoe Perches	int			err = 0, id;
6551b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct mISDNdevice	*dev;
6561b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct mISDNversion	ver;
6571b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
6581b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	switch (cmd) {
6591b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case IMGETVERSION:
6601b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		ver.major = MISDN_MAJOR_VERSION;
6611b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		ver.minor = MISDN_MINOR_VERSION;
6621b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		ver.release = MISDN_RELEASE;
6631b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (copy_to_user((void __user *)arg, &ver, sizeof(ver)))
6641b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			err = -EFAULT;
6651b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		break;
6661b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case IMGETCOUNT:
6671b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		id = get_mdevice_count();
6681b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (put_user(id, (int __user *)arg))
6691b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			err = -EFAULT;
6701b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		break;
6711b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case IMGETDEVINFO:
6721b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (get_user(id, (int __user *)arg)) {
6731b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			err = -EFAULT;
6741b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			break;
6751b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		}
6761b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		dev = get_mdevice(id);
6771b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (dev) {
6781b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			struct mISDN_devinfo di;
6791b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
680ce384d91cd7a4269a1ed5d4307a70aa4c6fa14f2Kulikov Vasiliy			memset(&di, 0, sizeof(di));
6811b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			di.id = dev->id;
6821b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			di.Dprotocols = dev->Dprotocols;
6831b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			di.Bprotocols = dev->Bprotocols | get_all_Bprotocols();
6841b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			di.protocol = dev->D.protocol;
6851b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			memcpy(di.channelmap, dev->channelmap,
686475be4d85a274d0961593db41cf85689db1d583cJoe Perches			       sizeof(di.channelmap));
6871b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			di.nrbchan = dev->nrbchan;
688837468d135dcc49cdabc9fa92fc9550479f60704Matthias Urlichs			strcpy(di.name, dev_name(&dev->dev));
6891b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			if (copy_to_user((void __user *)arg, &di, sizeof(di)))
6901b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil				err = -EFAULT;
6911b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		} else
6921b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			err = -ENODEV;
6931b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		break;
6948b6015f736125050722dbe59c4f943e78cd626f0Matthias Urlichs	case IMSETDEVNAME:
695475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{
696475be4d85a274d0961593db41cf85689db1d583cJoe Perches		struct mISDN_devrename dn;
697475be4d85a274d0961593db41cf85689db1d583cJoe Perches		if (copy_from_user(&dn, (void __user *)arg,
698475be4d85a274d0961593db41cf85689db1d583cJoe Perches				   sizeof(dn))) {
699475be4d85a274d0961593db41cf85689db1d583cJoe Perches			err = -EFAULT;
700475be4d85a274d0961593db41cf85689db1d583cJoe Perches			break;
7018b6015f736125050722dbe59c4f943e78cd626f0Matthias Urlichs		}
702475be4d85a274d0961593db41cf85689db1d583cJoe Perches		dev = get_mdevice(dn.id);
703475be4d85a274d0961593db41cf85689db1d583cJoe Perches		if (dev)
704475be4d85a274d0961593db41cf85689db1d583cJoe Perches			err = device_rename(&dev->dev, dn.name);
705475be4d85a274d0961593db41cf85689db1d583cJoe Perches		else
706475be4d85a274d0961593db41cf85689db1d583cJoe Perches			err = -ENODEV;
707475be4d85a274d0961593db41cf85689db1d583cJoe Perches	}
708475be4d85a274d0961593db41cf85689db1d583cJoe Perches	break;
7091b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	default:
7101b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		err = -EINVAL;
7111b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	}
7121b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	return err;
7131b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
7141b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
7151b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilstatic int
7161b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilbase_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
7171b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
7181b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct sockaddr_mISDN *maddr = (struct sockaddr_mISDN *) addr;
7191b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct sock *sk = sock->sk;
7201b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	int err = 0;
7211b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
7221b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (!maddr || maddr->family != AF_ISDN)
7231b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		return -EINVAL;
7241b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
7251b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	lock_sock(sk);
7261b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
7271b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (_pms(sk)->dev) {
7281b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		err = -EALREADY;
7291b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		goto done;
7301b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	}
7311b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
7321b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	_pms(sk)->dev = get_mdevice(maddr->dev);
7331b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (!_pms(sk)->dev) {
7341b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		err = -ENODEV;
7351b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		goto done;
7361b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	}
7371b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	sk->sk_state = MISDN_BOUND;
7381b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
7391b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keildone:
7401b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	release_sock(sk);
7411b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	return err;
7421b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
7431b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
7441b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilstatic const struct proto_ops base_sock_ops = {
7451b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.family		= PF_ISDN,
7461b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.owner		= THIS_MODULE,
7471b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.release	= base_sock_release,
7481b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.ioctl		= base_sock_ioctl,
7491b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.bind		= base_sock_bind,
7501b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.getname	= sock_no_getname,
7511b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.sendmsg	= sock_no_sendmsg,
7521b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.recvmsg	= sock_no_recvmsg,
7531b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.poll		= sock_no_poll,
7541b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.listen		= sock_no_listen,
7551b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.shutdown	= sock_no_shutdown,
7561b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.setsockopt	= sock_no_setsockopt,
7571b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.getsockopt	= sock_no_getsockopt,
7581b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.connect	= sock_no_connect,
7591b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.socketpair	= sock_no_socketpair,
7601b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.accept		= sock_no_accept,
7611b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.mmap		= sock_no_mmap
7621b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil};
7631b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
7641b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
7651b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilstatic int
7661b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilbase_sock_create(struct net *net, struct socket *sock, int protocol)
7671b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
7681b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct sock *sk;
7691b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
7701b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (sock->type != SOCK_RAW)
7711b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		return -ESOCKTNOSUPPORT;
7721b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
7731b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	sk = sk_alloc(net, PF_ISDN, GFP_KERNEL, &mISDN_proto);
7741b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (!sk)
7751b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		return -ENOMEM;
7761b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
7771b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	sock_init_data(sock, sk);
7781b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	sock->ops = &base_sock_ops;
7791b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	sock->state = SS_UNCONNECTED;
7801b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	sock_reset_flag(sk, SOCK_ZAPPED);
7811b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	sk->sk_protocol = protocol;
7821b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	sk->sk_state    = MISDN_OPEN;
7831b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	mISDN_sock_link(&base_sockets, sk);
7841b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
7851b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	return 0;
7861b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
7871b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
7881b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilstatic int
7893f378b684453f2a028eda463ce383370545d9cc9Eric ParismISDN_sock_create(struct net *net, struct socket *sock, int proto, int kern)
7901b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
7911b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	int err = -EPROTONOSUPPORT;
7921b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
793475be4d85a274d0961593db41cf85689db1d583cJoe Perches	switch (proto) {
7941b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_BASE:
7951b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		err = base_sock_create(net, sock, proto);
7961b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		break;
7971b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_TE_S0:
7981b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_NT_S0:
7991b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_TE_E1:
8001b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_NT_E1:
8011b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_LAPD_TE:
8021b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_LAPD_NT:
8031b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_B_RAW:
8041b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_B_HDLC:
8051b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_B_X75SLP:
8061b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_B_L2DTMF:
8071b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_B_L2DSP:
8081b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case ISDN_P_B_L2DSPHDLC:
8091b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		err = data_sock_create(net, sock, proto);
8101b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		break;
8111b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	default:
8121b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		return err;
8131b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	}
8141b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
8151b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	return err;
8161b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
8171b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
818ec1b4cf74c81bfd0fbe5bf62bafc86c45917e72fStephen Hemmingerstatic const struct net_proto_family mISDN_sock_family_ops = {
8191b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.owner  = THIS_MODULE,
8201b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.family = PF_ISDN,
8211b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.create = mISDN_sock_create,
8221b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil};
8231b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
8241b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilint
8251b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilmisdn_sock_init(u_int *deb)
8261b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
8271b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	int err;
8281b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
8291b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	debug = deb;
8301b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	err = sock_register(&mISDN_sock_family_ops);
8311b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (err)
8321b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		printk(KERN_ERR "%s: error(%d)\n", __func__, err);
8331b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	return err;
8341b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
8351b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
8361b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilvoid
8371b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilmisdn_sock_cleanup(void)
8381b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
8391b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	sock_unregister(PF_ISDN);
8401b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
841