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