18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Author Karsten Keil <kkeil@novell.com> 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright 2008 by Karsten Keil <kkeil@novell.com> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/mISDNif.h> 108c2ecf20Sopenharmony_ci#include <linux/slab.h> 118c2ecf20Sopenharmony_ci#include <linux/export.h> 128c2ecf20Sopenharmony_ci#include "core.h" 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_cistatic u_int *debug; 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_cistatic struct proto mISDN_proto = { 178c2ecf20Sopenharmony_ci .name = "misdn", 188c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 198c2ecf20Sopenharmony_ci .obj_size = sizeof(struct mISDN_sock) 208c2ecf20Sopenharmony_ci}; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define _pms(sk) ((struct mISDN_sock *)sk) 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistatic struct mISDN_sock_list data_sockets = { 258c2ecf20Sopenharmony_ci .lock = __RW_LOCK_UNLOCKED(data_sockets.lock) 268c2ecf20Sopenharmony_ci}; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic struct mISDN_sock_list base_sockets = { 298c2ecf20Sopenharmony_ci .lock = __RW_LOCK_UNLOCKED(base_sockets.lock) 308c2ecf20Sopenharmony_ci}; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define L2_HEADER_LEN 4 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic inline struct sk_buff * 358c2ecf20Sopenharmony_ci_l2_alloc_skb(unsigned int len, gfp_t gfp_mask) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci struct sk_buff *skb; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci skb = alloc_skb(len + L2_HEADER_LEN, gfp_mask); 408c2ecf20Sopenharmony_ci if (likely(skb)) 418c2ecf20Sopenharmony_ci skb_reserve(skb, L2_HEADER_LEN); 428c2ecf20Sopenharmony_ci return skb; 438c2ecf20Sopenharmony_ci} 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic void 468c2ecf20Sopenharmony_cimISDN_sock_link(struct mISDN_sock_list *l, struct sock *sk) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci write_lock_bh(&l->lock); 498c2ecf20Sopenharmony_ci sk_add_node(sk, &l->head); 508c2ecf20Sopenharmony_ci write_unlock_bh(&l->lock); 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic void mISDN_sock_unlink(struct mISDN_sock_list *l, struct sock *sk) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci write_lock_bh(&l->lock); 568c2ecf20Sopenharmony_ci sk_del_node_init(sk); 578c2ecf20Sopenharmony_ci write_unlock_bh(&l->lock); 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic int 618c2ecf20Sopenharmony_cimISDN_send(struct mISDNchannel *ch, struct sk_buff *skb) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci struct mISDN_sock *msk; 648c2ecf20Sopenharmony_ci int err; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci msk = container_of(ch, struct mISDN_sock, ch); 678c2ecf20Sopenharmony_ci if (*debug & DEBUG_SOCKET) 688c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s len %d %p\n", __func__, skb->len, skb); 698c2ecf20Sopenharmony_ci if (msk->sk.sk_state == MISDN_CLOSED) 708c2ecf20Sopenharmony_ci return -EUNATCH; 718c2ecf20Sopenharmony_ci __net_timestamp(skb); 728c2ecf20Sopenharmony_ci err = sock_queue_rcv_skb(&msk->sk, skb); 738c2ecf20Sopenharmony_ci if (err) 748c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: error %d\n", __func__, err); 758c2ecf20Sopenharmony_ci return err; 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistatic int 798c2ecf20Sopenharmony_cimISDN_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci struct mISDN_sock *msk; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci msk = container_of(ch, struct mISDN_sock, ch); 848c2ecf20Sopenharmony_ci if (*debug & DEBUG_SOCKET) 858c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s(%p, %x, %p)\n", __func__, ch, cmd, arg); 868c2ecf20Sopenharmony_ci switch (cmd) { 878c2ecf20Sopenharmony_ci case CLOSE_CHANNEL: 888c2ecf20Sopenharmony_ci msk->sk.sk_state = MISDN_CLOSED; 898c2ecf20Sopenharmony_ci break; 908c2ecf20Sopenharmony_ci } 918c2ecf20Sopenharmony_ci return 0; 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic inline void 958c2ecf20Sopenharmony_cimISDN_sock_cmsg(struct sock *sk, struct msghdr *msg, struct sk_buff *skb) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci struct __kernel_old_timeval tv; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci if (_pms(sk)->cmask & MISDN_TIME_STAMP) { 1008c2ecf20Sopenharmony_ci skb_get_timestamp(skb, &tv); 1018c2ecf20Sopenharmony_ci put_cmsg(msg, SOL_MISDN, MISDN_TIME_STAMP, sizeof(tv), &tv); 1028c2ecf20Sopenharmony_ci } 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistatic int 1068c2ecf20Sopenharmony_cimISDN_sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, 1078c2ecf20Sopenharmony_ci int flags) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci struct sk_buff *skb; 1108c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci int copied, err; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci if (*debug & DEBUG_SOCKET) 1158c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: len %d, flags %x ch.nr %d, proto %x\n", 1168c2ecf20Sopenharmony_ci __func__, (int)len, flags, _pms(sk)->ch.nr, 1178c2ecf20Sopenharmony_ci sk->sk_protocol); 1188c2ecf20Sopenharmony_ci if (flags & (MSG_OOB)) 1198c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci if (sk->sk_state == MISDN_CLOSED) 1228c2ecf20Sopenharmony_ci return 0; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci skb = skb_recv_datagram(sk, flags, flags & MSG_DONTWAIT, &err); 1258c2ecf20Sopenharmony_ci if (!skb) 1268c2ecf20Sopenharmony_ci return err; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci if (msg->msg_name) { 1298c2ecf20Sopenharmony_ci DECLARE_SOCKADDR(struct sockaddr_mISDN *, maddr, msg->msg_name); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci maddr->family = AF_ISDN; 1328c2ecf20Sopenharmony_ci maddr->dev = _pms(sk)->dev->id; 1338c2ecf20Sopenharmony_ci if ((sk->sk_protocol == ISDN_P_LAPD_TE) || 1348c2ecf20Sopenharmony_ci (sk->sk_protocol == ISDN_P_LAPD_NT)) { 1358c2ecf20Sopenharmony_ci maddr->channel = (mISDN_HEAD_ID(skb) >> 16) & 0xff; 1368c2ecf20Sopenharmony_ci maddr->tei = (mISDN_HEAD_ID(skb) >> 8) & 0xff; 1378c2ecf20Sopenharmony_ci maddr->sapi = mISDN_HEAD_ID(skb) & 0xff; 1388c2ecf20Sopenharmony_ci } else { 1398c2ecf20Sopenharmony_ci maddr->channel = _pms(sk)->ch.nr; 1408c2ecf20Sopenharmony_ci maddr->sapi = _pms(sk)->ch.addr & 0xFF; 1418c2ecf20Sopenharmony_ci maddr->tei = (_pms(sk)->ch.addr >> 8) & 0xFF; 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci msg->msg_namelen = sizeof(*maddr); 1448c2ecf20Sopenharmony_ci } 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci copied = skb->len + MISDN_HEADER_LEN; 1478c2ecf20Sopenharmony_ci if (len < copied) { 1488c2ecf20Sopenharmony_ci if (flags & MSG_PEEK) 1498c2ecf20Sopenharmony_ci refcount_dec(&skb->users); 1508c2ecf20Sopenharmony_ci else 1518c2ecf20Sopenharmony_ci skb_queue_head(&sk->sk_receive_queue, skb); 1528c2ecf20Sopenharmony_ci return -ENOSPC; 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci memcpy(skb_push(skb, MISDN_HEADER_LEN), mISDN_HEAD_P(skb), 1558c2ecf20Sopenharmony_ci MISDN_HEADER_LEN); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci err = skb_copy_datagram_msg(skb, 0, msg, copied); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci mISDN_sock_cmsg(sk, msg, skb); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci skb_free_datagram(sk, skb); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci return err ? : copied; 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic int 1678c2ecf20Sopenharmony_cimISDN_sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 1708c2ecf20Sopenharmony_ci struct sk_buff *skb; 1718c2ecf20Sopenharmony_ci int err = -ENOMEM; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci if (*debug & DEBUG_SOCKET) 1748c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: len %d flags %x ch %d proto %x\n", 1758c2ecf20Sopenharmony_ci __func__, (int)len, msg->msg_flags, _pms(sk)->ch.nr, 1768c2ecf20Sopenharmony_ci sk->sk_protocol); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci if (msg->msg_flags & MSG_OOB) 1798c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci if (msg->msg_flags & ~(MSG_DONTWAIT | MSG_NOSIGNAL | MSG_ERRQUEUE)) 1828c2ecf20Sopenharmony_ci return -EINVAL; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci if (len < MISDN_HEADER_LEN) 1858c2ecf20Sopenharmony_ci return -EINVAL; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci if (sk->sk_state != MISDN_BOUND) 1888c2ecf20Sopenharmony_ci return -EBADFD; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci lock_sock(sk); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci skb = _l2_alloc_skb(len, GFP_KERNEL); 1938c2ecf20Sopenharmony_ci if (!skb) 1948c2ecf20Sopenharmony_ci goto done; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci if (memcpy_from_msg(skb_put(skb, len), msg, len)) { 1978c2ecf20Sopenharmony_ci err = -EFAULT; 1988c2ecf20Sopenharmony_ci goto done; 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci memcpy(mISDN_HEAD_P(skb), skb->data, MISDN_HEADER_LEN); 2028c2ecf20Sopenharmony_ci skb_pull(skb, MISDN_HEADER_LEN); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci if (msg->msg_namelen >= sizeof(struct sockaddr_mISDN)) { 2058c2ecf20Sopenharmony_ci /* if we have a address, we use it */ 2068c2ecf20Sopenharmony_ci DECLARE_SOCKADDR(struct sockaddr_mISDN *, maddr, msg->msg_name); 2078c2ecf20Sopenharmony_ci mISDN_HEAD_ID(skb) = maddr->channel; 2088c2ecf20Sopenharmony_ci } else { /* use default for L2 messages */ 2098c2ecf20Sopenharmony_ci if ((sk->sk_protocol == ISDN_P_LAPD_TE) || 2108c2ecf20Sopenharmony_ci (sk->sk_protocol == ISDN_P_LAPD_NT)) 2118c2ecf20Sopenharmony_ci mISDN_HEAD_ID(skb) = _pms(sk)->ch.nr; 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci if (*debug & DEBUG_SOCKET) 2158c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: ID:%x\n", 2168c2ecf20Sopenharmony_ci __func__, mISDN_HEAD_ID(skb)); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci err = -ENODEV; 2198c2ecf20Sopenharmony_ci if (!_pms(sk)->ch.peer) 2208c2ecf20Sopenharmony_ci goto done; 2218c2ecf20Sopenharmony_ci err = _pms(sk)->ch.recv(_pms(sk)->ch.peer, skb); 2228c2ecf20Sopenharmony_ci if (err) 2238c2ecf20Sopenharmony_ci goto done; 2248c2ecf20Sopenharmony_ci else { 2258c2ecf20Sopenharmony_ci skb = NULL; 2268c2ecf20Sopenharmony_ci err = len; 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_cidone: 2308c2ecf20Sopenharmony_ci kfree_skb(skb); 2318c2ecf20Sopenharmony_ci release_sock(sk); 2328c2ecf20Sopenharmony_ci return err; 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_cistatic int 2368c2ecf20Sopenharmony_cidata_sock_release(struct socket *sock) 2378c2ecf20Sopenharmony_ci{ 2388c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci if (*debug & DEBUG_SOCKET) 2418c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s(%p) sk=%p\n", __func__, sock, sk); 2428c2ecf20Sopenharmony_ci if (!sk) 2438c2ecf20Sopenharmony_ci return 0; 2448c2ecf20Sopenharmony_ci switch (sk->sk_protocol) { 2458c2ecf20Sopenharmony_ci case ISDN_P_TE_S0: 2468c2ecf20Sopenharmony_ci case ISDN_P_NT_S0: 2478c2ecf20Sopenharmony_ci case ISDN_P_TE_E1: 2488c2ecf20Sopenharmony_ci case ISDN_P_NT_E1: 2498c2ecf20Sopenharmony_ci if (sk->sk_state == MISDN_BOUND) 2508c2ecf20Sopenharmony_ci delete_channel(&_pms(sk)->ch); 2518c2ecf20Sopenharmony_ci else 2528c2ecf20Sopenharmony_ci mISDN_sock_unlink(&data_sockets, sk); 2538c2ecf20Sopenharmony_ci break; 2548c2ecf20Sopenharmony_ci case ISDN_P_LAPD_TE: 2558c2ecf20Sopenharmony_ci case ISDN_P_LAPD_NT: 2568c2ecf20Sopenharmony_ci case ISDN_P_B_RAW: 2578c2ecf20Sopenharmony_ci case ISDN_P_B_HDLC: 2588c2ecf20Sopenharmony_ci case ISDN_P_B_X75SLP: 2598c2ecf20Sopenharmony_ci case ISDN_P_B_L2DTMF: 2608c2ecf20Sopenharmony_ci case ISDN_P_B_L2DSP: 2618c2ecf20Sopenharmony_ci case ISDN_P_B_L2DSPHDLC: 2628c2ecf20Sopenharmony_ci delete_channel(&_pms(sk)->ch); 2638c2ecf20Sopenharmony_ci mISDN_sock_unlink(&data_sockets, sk); 2648c2ecf20Sopenharmony_ci break; 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci lock_sock(sk); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci sock_orphan(sk); 2708c2ecf20Sopenharmony_ci skb_queue_purge(&sk->sk_receive_queue); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci release_sock(sk); 2738c2ecf20Sopenharmony_ci sock_put(sk); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci return 0; 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_cistatic int 2798c2ecf20Sopenharmony_cidata_sock_ioctl_bound(struct sock *sk, unsigned int cmd, void __user *p) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci struct mISDN_ctrl_req cq; 2828c2ecf20Sopenharmony_ci int err = -EINVAL, val[2]; 2838c2ecf20Sopenharmony_ci struct mISDNchannel *bchan, *next; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci lock_sock(sk); 2868c2ecf20Sopenharmony_ci if (!_pms(sk)->dev) { 2878c2ecf20Sopenharmony_ci err = -ENODEV; 2888c2ecf20Sopenharmony_ci goto done; 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci switch (cmd) { 2918c2ecf20Sopenharmony_ci case IMCTRLREQ: 2928c2ecf20Sopenharmony_ci if (copy_from_user(&cq, p, sizeof(cq))) { 2938c2ecf20Sopenharmony_ci err = -EFAULT; 2948c2ecf20Sopenharmony_ci break; 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci if ((sk->sk_protocol & ~ISDN_P_B_MASK) == ISDN_P_B_START) { 2978c2ecf20Sopenharmony_ci list_for_each_entry_safe(bchan, next, 2988c2ecf20Sopenharmony_ci &_pms(sk)->dev->bchannels, list) { 2998c2ecf20Sopenharmony_ci if (bchan->nr == cq.channel) { 3008c2ecf20Sopenharmony_ci err = bchan->ctrl(bchan, 3018c2ecf20Sopenharmony_ci CONTROL_CHANNEL, &cq); 3028c2ecf20Sopenharmony_ci break; 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci } 3058c2ecf20Sopenharmony_ci } else 3068c2ecf20Sopenharmony_ci err = _pms(sk)->dev->D.ctrl(&_pms(sk)->dev->D, 3078c2ecf20Sopenharmony_ci CONTROL_CHANNEL, &cq); 3088c2ecf20Sopenharmony_ci if (err) 3098c2ecf20Sopenharmony_ci break; 3108c2ecf20Sopenharmony_ci if (copy_to_user(p, &cq, sizeof(cq))) 3118c2ecf20Sopenharmony_ci err = -EFAULT; 3128c2ecf20Sopenharmony_ci break; 3138c2ecf20Sopenharmony_ci case IMCLEAR_L2: 3148c2ecf20Sopenharmony_ci if (sk->sk_protocol != ISDN_P_LAPD_NT) { 3158c2ecf20Sopenharmony_ci err = -EINVAL; 3168c2ecf20Sopenharmony_ci break; 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci val[0] = cmd; 3198c2ecf20Sopenharmony_ci if (get_user(val[1], (int __user *)p)) { 3208c2ecf20Sopenharmony_ci err = -EFAULT; 3218c2ecf20Sopenharmony_ci break; 3228c2ecf20Sopenharmony_ci } 3238c2ecf20Sopenharmony_ci err = _pms(sk)->dev->teimgr->ctrl(_pms(sk)->dev->teimgr, 3248c2ecf20Sopenharmony_ci CONTROL_CHANNEL, val); 3258c2ecf20Sopenharmony_ci break; 3268c2ecf20Sopenharmony_ci case IMHOLD_L1: 3278c2ecf20Sopenharmony_ci if (sk->sk_protocol != ISDN_P_LAPD_NT 3288c2ecf20Sopenharmony_ci && sk->sk_protocol != ISDN_P_LAPD_TE) { 3298c2ecf20Sopenharmony_ci err = -EINVAL; 3308c2ecf20Sopenharmony_ci break; 3318c2ecf20Sopenharmony_ci } 3328c2ecf20Sopenharmony_ci val[0] = cmd; 3338c2ecf20Sopenharmony_ci if (get_user(val[1], (int __user *)p)) { 3348c2ecf20Sopenharmony_ci err = -EFAULT; 3358c2ecf20Sopenharmony_ci break; 3368c2ecf20Sopenharmony_ci } 3378c2ecf20Sopenharmony_ci err = _pms(sk)->dev->teimgr->ctrl(_pms(sk)->dev->teimgr, 3388c2ecf20Sopenharmony_ci CONTROL_CHANNEL, val); 3398c2ecf20Sopenharmony_ci break; 3408c2ecf20Sopenharmony_ci default: 3418c2ecf20Sopenharmony_ci err = -EINVAL; 3428c2ecf20Sopenharmony_ci break; 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_cidone: 3458c2ecf20Sopenharmony_ci release_sock(sk); 3468c2ecf20Sopenharmony_ci return err; 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_cistatic int 3508c2ecf20Sopenharmony_cidata_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) 3518c2ecf20Sopenharmony_ci{ 3528c2ecf20Sopenharmony_ci int err = 0, id; 3538c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 3548c2ecf20Sopenharmony_ci struct mISDNdevice *dev; 3558c2ecf20Sopenharmony_ci struct mISDNversion ver; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci switch (cmd) { 3588c2ecf20Sopenharmony_ci case IMGETVERSION: 3598c2ecf20Sopenharmony_ci ver.major = MISDN_MAJOR_VERSION; 3608c2ecf20Sopenharmony_ci ver.minor = MISDN_MINOR_VERSION; 3618c2ecf20Sopenharmony_ci ver.release = MISDN_RELEASE; 3628c2ecf20Sopenharmony_ci if (copy_to_user((void __user *)arg, &ver, sizeof(ver))) 3638c2ecf20Sopenharmony_ci err = -EFAULT; 3648c2ecf20Sopenharmony_ci break; 3658c2ecf20Sopenharmony_ci case IMGETCOUNT: 3668c2ecf20Sopenharmony_ci id = get_mdevice_count(); 3678c2ecf20Sopenharmony_ci if (put_user(id, (int __user *)arg)) 3688c2ecf20Sopenharmony_ci err = -EFAULT; 3698c2ecf20Sopenharmony_ci break; 3708c2ecf20Sopenharmony_ci case IMGETDEVINFO: 3718c2ecf20Sopenharmony_ci if (get_user(id, (int __user *)arg)) { 3728c2ecf20Sopenharmony_ci err = -EFAULT; 3738c2ecf20Sopenharmony_ci break; 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci dev = get_mdevice(id); 3768c2ecf20Sopenharmony_ci if (dev) { 3778c2ecf20Sopenharmony_ci struct mISDN_devinfo di; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci memset(&di, 0, sizeof(di)); 3808c2ecf20Sopenharmony_ci di.id = dev->id; 3818c2ecf20Sopenharmony_ci di.Dprotocols = dev->Dprotocols; 3828c2ecf20Sopenharmony_ci di.Bprotocols = dev->Bprotocols | get_all_Bprotocols(); 3838c2ecf20Sopenharmony_ci di.protocol = dev->D.protocol; 3848c2ecf20Sopenharmony_ci memcpy(di.channelmap, dev->channelmap, 3858c2ecf20Sopenharmony_ci sizeof(di.channelmap)); 3868c2ecf20Sopenharmony_ci di.nrbchan = dev->nrbchan; 3878c2ecf20Sopenharmony_ci strscpy(di.name, dev_name(&dev->dev), sizeof(di.name)); 3888c2ecf20Sopenharmony_ci if (copy_to_user((void __user *)arg, &di, sizeof(di))) 3898c2ecf20Sopenharmony_ci err = -EFAULT; 3908c2ecf20Sopenharmony_ci } else 3918c2ecf20Sopenharmony_ci err = -ENODEV; 3928c2ecf20Sopenharmony_ci break; 3938c2ecf20Sopenharmony_ci default: 3948c2ecf20Sopenharmony_ci if (sk->sk_state == MISDN_BOUND) 3958c2ecf20Sopenharmony_ci err = data_sock_ioctl_bound(sk, cmd, 3968c2ecf20Sopenharmony_ci (void __user *)arg); 3978c2ecf20Sopenharmony_ci else 3988c2ecf20Sopenharmony_ci err = -ENOTCONN; 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci return err; 4018c2ecf20Sopenharmony_ci} 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_cistatic int data_sock_setsockopt(struct socket *sock, int level, int optname, 4048c2ecf20Sopenharmony_ci sockptr_t optval, unsigned int len) 4058c2ecf20Sopenharmony_ci{ 4068c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 4078c2ecf20Sopenharmony_ci int err = 0, opt = 0; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci if (*debug & DEBUG_SOCKET) 4108c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s(%p, %d, %x, optval, %d)\n", __func__, sock, 4118c2ecf20Sopenharmony_ci level, optname, len); 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci lock_sock(sk); 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci switch (optname) { 4168c2ecf20Sopenharmony_ci case MISDN_TIME_STAMP: 4178c2ecf20Sopenharmony_ci if (copy_from_sockptr(&opt, optval, sizeof(int))) { 4188c2ecf20Sopenharmony_ci err = -EFAULT; 4198c2ecf20Sopenharmony_ci break; 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci if (opt) 4238c2ecf20Sopenharmony_ci _pms(sk)->cmask |= MISDN_TIME_STAMP; 4248c2ecf20Sopenharmony_ci else 4258c2ecf20Sopenharmony_ci _pms(sk)->cmask &= ~MISDN_TIME_STAMP; 4268c2ecf20Sopenharmony_ci break; 4278c2ecf20Sopenharmony_ci default: 4288c2ecf20Sopenharmony_ci err = -ENOPROTOOPT; 4298c2ecf20Sopenharmony_ci break; 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci release_sock(sk); 4328c2ecf20Sopenharmony_ci return err; 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_cistatic int data_sock_getsockopt(struct socket *sock, int level, int optname, 4368c2ecf20Sopenharmony_ci char __user *optval, int __user *optlen) 4378c2ecf20Sopenharmony_ci{ 4388c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 4398c2ecf20Sopenharmony_ci int len, opt; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci if (get_user(len, optlen)) 4428c2ecf20Sopenharmony_ci return -EFAULT; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci if (len != sizeof(char)) 4458c2ecf20Sopenharmony_ci return -EINVAL; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci switch (optname) { 4488c2ecf20Sopenharmony_ci case MISDN_TIME_STAMP: 4498c2ecf20Sopenharmony_ci if (_pms(sk)->cmask & MISDN_TIME_STAMP) 4508c2ecf20Sopenharmony_ci opt = 1; 4518c2ecf20Sopenharmony_ci else 4528c2ecf20Sopenharmony_ci opt = 0; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci if (put_user(opt, optval)) 4558c2ecf20Sopenharmony_ci return -EFAULT; 4568c2ecf20Sopenharmony_ci break; 4578c2ecf20Sopenharmony_ci default: 4588c2ecf20Sopenharmony_ci return -ENOPROTOOPT; 4598c2ecf20Sopenharmony_ci } 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci return 0; 4628c2ecf20Sopenharmony_ci} 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_cistatic int 4658c2ecf20Sopenharmony_cidata_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len) 4668c2ecf20Sopenharmony_ci{ 4678c2ecf20Sopenharmony_ci struct sockaddr_mISDN *maddr = (struct sockaddr_mISDN *) addr; 4688c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 4698c2ecf20Sopenharmony_ci struct sock *csk; 4708c2ecf20Sopenharmony_ci int err = 0; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci if (*debug & DEBUG_SOCKET) 4738c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s(%p) sk=%p\n", __func__, sock, sk); 4748c2ecf20Sopenharmony_ci if (addr_len != sizeof(struct sockaddr_mISDN)) 4758c2ecf20Sopenharmony_ci return -EINVAL; 4768c2ecf20Sopenharmony_ci if (!maddr || maddr->family != AF_ISDN) 4778c2ecf20Sopenharmony_ci return -EINVAL; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci lock_sock(sk); 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci if (_pms(sk)->dev) { 4828c2ecf20Sopenharmony_ci err = -EALREADY; 4838c2ecf20Sopenharmony_ci goto done; 4848c2ecf20Sopenharmony_ci } 4858c2ecf20Sopenharmony_ci _pms(sk)->dev = get_mdevice(maddr->dev); 4868c2ecf20Sopenharmony_ci if (!_pms(sk)->dev) { 4878c2ecf20Sopenharmony_ci err = -ENODEV; 4888c2ecf20Sopenharmony_ci goto done; 4898c2ecf20Sopenharmony_ci } 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci if (sk->sk_protocol < ISDN_P_B_START) { 4928c2ecf20Sopenharmony_ci read_lock_bh(&data_sockets.lock); 4938c2ecf20Sopenharmony_ci sk_for_each(csk, &data_sockets.head) { 4948c2ecf20Sopenharmony_ci if (sk == csk) 4958c2ecf20Sopenharmony_ci continue; 4968c2ecf20Sopenharmony_ci if (_pms(csk)->dev != _pms(sk)->dev) 4978c2ecf20Sopenharmony_ci continue; 4988c2ecf20Sopenharmony_ci if (csk->sk_protocol >= ISDN_P_B_START) 4998c2ecf20Sopenharmony_ci continue; 5008c2ecf20Sopenharmony_ci if (IS_ISDN_P_TE(csk->sk_protocol) 5018c2ecf20Sopenharmony_ci == IS_ISDN_P_TE(sk->sk_protocol)) 5028c2ecf20Sopenharmony_ci continue; 5038c2ecf20Sopenharmony_ci read_unlock_bh(&data_sockets.lock); 5048c2ecf20Sopenharmony_ci err = -EBUSY; 5058c2ecf20Sopenharmony_ci goto done; 5068c2ecf20Sopenharmony_ci } 5078c2ecf20Sopenharmony_ci read_unlock_bh(&data_sockets.lock); 5088c2ecf20Sopenharmony_ci } 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci _pms(sk)->ch.send = mISDN_send; 5118c2ecf20Sopenharmony_ci _pms(sk)->ch.ctrl = mISDN_ctrl; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci switch (sk->sk_protocol) { 5148c2ecf20Sopenharmony_ci case ISDN_P_TE_S0: 5158c2ecf20Sopenharmony_ci case ISDN_P_NT_S0: 5168c2ecf20Sopenharmony_ci case ISDN_P_TE_E1: 5178c2ecf20Sopenharmony_ci case ISDN_P_NT_E1: 5188c2ecf20Sopenharmony_ci mISDN_sock_unlink(&data_sockets, sk); 5198c2ecf20Sopenharmony_ci err = connect_layer1(_pms(sk)->dev, &_pms(sk)->ch, 5208c2ecf20Sopenharmony_ci sk->sk_protocol, maddr); 5218c2ecf20Sopenharmony_ci if (err) 5228c2ecf20Sopenharmony_ci mISDN_sock_link(&data_sockets, sk); 5238c2ecf20Sopenharmony_ci break; 5248c2ecf20Sopenharmony_ci case ISDN_P_LAPD_TE: 5258c2ecf20Sopenharmony_ci case ISDN_P_LAPD_NT: 5268c2ecf20Sopenharmony_ci err = create_l2entity(_pms(sk)->dev, &_pms(sk)->ch, 5278c2ecf20Sopenharmony_ci sk->sk_protocol, maddr); 5288c2ecf20Sopenharmony_ci break; 5298c2ecf20Sopenharmony_ci case ISDN_P_B_RAW: 5308c2ecf20Sopenharmony_ci case ISDN_P_B_HDLC: 5318c2ecf20Sopenharmony_ci case ISDN_P_B_X75SLP: 5328c2ecf20Sopenharmony_ci case ISDN_P_B_L2DTMF: 5338c2ecf20Sopenharmony_ci case ISDN_P_B_L2DSP: 5348c2ecf20Sopenharmony_ci case ISDN_P_B_L2DSPHDLC: 5358c2ecf20Sopenharmony_ci err = connect_Bstack(_pms(sk)->dev, &_pms(sk)->ch, 5368c2ecf20Sopenharmony_ci sk->sk_protocol, maddr); 5378c2ecf20Sopenharmony_ci break; 5388c2ecf20Sopenharmony_ci default: 5398c2ecf20Sopenharmony_ci err = -EPROTONOSUPPORT; 5408c2ecf20Sopenharmony_ci } 5418c2ecf20Sopenharmony_ci if (err) 5428c2ecf20Sopenharmony_ci goto done; 5438c2ecf20Sopenharmony_ci sk->sk_state = MISDN_BOUND; 5448c2ecf20Sopenharmony_ci _pms(sk)->ch.protocol = sk->sk_protocol; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_cidone: 5478c2ecf20Sopenharmony_ci release_sock(sk); 5488c2ecf20Sopenharmony_ci return err; 5498c2ecf20Sopenharmony_ci} 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_cistatic int 5528c2ecf20Sopenharmony_cidata_sock_getname(struct socket *sock, struct sockaddr *addr, 5538c2ecf20Sopenharmony_ci int peer) 5548c2ecf20Sopenharmony_ci{ 5558c2ecf20Sopenharmony_ci struct sockaddr_mISDN *maddr = (struct sockaddr_mISDN *) addr; 5568c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci if (!_pms(sk)->dev) 5598c2ecf20Sopenharmony_ci return -EBADFD; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci lock_sock(sk); 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci maddr->family = AF_ISDN; 5648c2ecf20Sopenharmony_ci maddr->dev = _pms(sk)->dev->id; 5658c2ecf20Sopenharmony_ci maddr->channel = _pms(sk)->ch.nr; 5668c2ecf20Sopenharmony_ci maddr->sapi = _pms(sk)->ch.addr & 0xff; 5678c2ecf20Sopenharmony_ci maddr->tei = (_pms(sk)->ch.addr >> 8) & 0xff; 5688c2ecf20Sopenharmony_ci release_sock(sk); 5698c2ecf20Sopenharmony_ci return sizeof(*maddr); 5708c2ecf20Sopenharmony_ci} 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_cistatic const struct proto_ops data_sock_ops = { 5738c2ecf20Sopenharmony_ci .family = PF_ISDN, 5748c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 5758c2ecf20Sopenharmony_ci .release = data_sock_release, 5768c2ecf20Sopenharmony_ci .ioctl = data_sock_ioctl, 5778c2ecf20Sopenharmony_ci .bind = data_sock_bind, 5788c2ecf20Sopenharmony_ci .getname = data_sock_getname, 5798c2ecf20Sopenharmony_ci .sendmsg = mISDN_sock_sendmsg, 5808c2ecf20Sopenharmony_ci .recvmsg = mISDN_sock_recvmsg, 5818c2ecf20Sopenharmony_ci .poll = datagram_poll, 5828c2ecf20Sopenharmony_ci .listen = sock_no_listen, 5838c2ecf20Sopenharmony_ci .shutdown = sock_no_shutdown, 5848c2ecf20Sopenharmony_ci .setsockopt = data_sock_setsockopt, 5858c2ecf20Sopenharmony_ci .getsockopt = data_sock_getsockopt, 5868c2ecf20Sopenharmony_ci .connect = sock_no_connect, 5878c2ecf20Sopenharmony_ci .socketpair = sock_no_socketpair, 5888c2ecf20Sopenharmony_ci .accept = sock_no_accept, 5898c2ecf20Sopenharmony_ci .mmap = sock_no_mmap 5908c2ecf20Sopenharmony_ci}; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_cistatic int 5938c2ecf20Sopenharmony_cidata_sock_create(struct net *net, struct socket *sock, int protocol, int kern) 5948c2ecf20Sopenharmony_ci{ 5958c2ecf20Sopenharmony_ci struct sock *sk; 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci if (sock->type != SOCK_DGRAM) 5988c2ecf20Sopenharmony_ci return -ESOCKTNOSUPPORT; 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci sk = sk_alloc(net, PF_ISDN, GFP_KERNEL, &mISDN_proto, kern); 6018c2ecf20Sopenharmony_ci if (!sk) 6028c2ecf20Sopenharmony_ci return -ENOMEM; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci sock_init_data(sock, sk); 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci sock->ops = &data_sock_ops; 6078c2ecf20Sopenharmony_ci sock->state = SS_UNCONNECTED; 6088c2ecf20Sopenharmony_ci sock_reset_flag(sk, SOCK_ZAPPED); 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci sk->sk_protocol = protocol; 6118c2ecf20Sopenharmony_ci sk->sk_state = MISDN_OPEN; 6128c2ecf20Sopenharmony_ci mISDN_sock_link(&data_sockets, sk); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci return 0; 6158c2ecf20Sopenharmony_ci} 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_cistatic int 6188c2ecf20Sopenharmony_cibase_sock_release(struct socket *sock) 6198c2ecf20Sopenharmony_ci{ 6208c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s(%p) sk=%p\n", __func__, sock, sk); 6238c2ecf20Sopenharmony_ci if (!sk) 6248c2ecf20Sopenharmony_ci return 0; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci mISDN_sock_unlink(&base_sockets, sk); 6278c2ecf20Sopenharmony_ci sock_orphan(sk); 6288c2ecf20Sopenharmony_ci sock_put(sk); 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci return 0; 6318c2ecf20Sopenharmony_ci} 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_cistatic int 6348c2ecf20Sopenharmony_cibase_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) 6358c2ecf20Sopenharmony_ci{ 6368c2ecf20Sopenharmony_ci int err = 0, id; 6378c2ecf20Sopenharmony_ci struct mISDNdevice *dev; 6388c2ecf20Sopenharmony_ci struct mISDNversion ver; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci switch (cmd) { 6418c2ecf20Sopenharmony_ci case IMGETVERSION: 6428c2ecf20Sopenharmony_ci ver.major = MISDN_MAJOR_VERSION; 6438c2ecf20Sopenharmony_ci ver.minor = MISDN_MINOR_VERSION; 6448c2ecf20Sopenharmony_ci ver.release = MISDN_RELEASE; 6458c2ecf20Sopenharmony_ci if (copy_to_user((void __user *)arg, &ver, sizeof(ver))) 6468c2ecf20Sopenharmony_ci err = -EFAULT; 6478c2ecf20Sopenharmony_ci break; 6488c2ecf20Sopenharmony_ci case IMGETCOUNT: 6498c2ecf20Sopenharmony_ci id = get_mdevice_count(); 6508c2ecf20Sopenharmony_ci if (put_user(id, (int __user *)arg)) 6518c2ecf20Sopenharmony_ci err = -EFAULT; 6528c2ecf20Sopenharmony_ci break; 6538c2ecf20Sopenharmony_ci case IMGETDEVINFO: 6548c2ecf20Sopenharmony_ci if (get_user(id, (int __user *)arg)) { 6558c2ecf20Sopenharmony_ci err = -EFAULT; 6568c2ecf20Sopenharmony_ci break; 6578c2ecf20Sopenharmony_ci } 6588c2ecf20Sopenharmony_ci dev = get_mdevice(id); 6598c2ecf20Sopenharmony_ci if (dev) { 6608c2ecf20Sopenharmony_ci struct mISDN_devinfo di; 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci memset(&di, 0, sizeof(di)); 6638c2ecf20Sopenharmony_ci di.id = dev->id; 6648c2ecf20Sopenharmony_ci di.Dprotocols = dev->Dprotocols; 6658c2ecf20Sopenharmony_ci di.Bprotocols = dev->Bprotocols | get_all_Bprotocols(); 6668c2ecf20Sopenharmony_ci di.protocol = dev->D.protocol; 6678c2ecf20Sopenharmony_ci memcpy(di.channelmap, dev->channelmap, 6688c2ecf20Sopenharmony_ci sizeof(di.channelmap)); 6698c2ecf20Sopenharmony_ci di.nrbchan = dev->nrbchan; 6708c2ecf20Sopenharmony_ci strscpy(di.name, dev_name(&dev->dev), sizeof(di.name)); 6718c2ecf20Sopenharmony_ci if (copy_to_user((void __user *)arg, &di, sizeof(di))) 6728c2ecf20Sopenharmony_ci err = -EFAULT; 6738c2ecf20Sopenharmony_ci } else 6748c2ecf20Sopenharmony_ci err = -ENODEV; 6758c2ecf20Sopenharmony_ci break; 6768c2ecf20Sopenharmony_ci case IMSETDEVNAME: 6778c2ecf20Sopenharmony_ci { 6788c2ecf20Sopenharmony_ci struct mISDN_devrename dn; 6798c2ecf20Sopenharmony_ci if (copy_from_user(&dn, (void __user *)arg, 6808c2ecf20Sopenharmony_ci sizeof(dn))) { 6818c2ecf20Sopenharmony_ci err = -EFAULT; 6828c2ecf20Sopenharmony_ci break; 6838c2ecf20Sopenharmony_ci } 6848c2ecf20Sopenharmony_ci dn.name[sizeof(dn.name) - 1] = '\0'; 6858c2ecf20Sopenharmony_ci dev = get_mdevice(dn.id); 6868c2ecf20Sopenharmony_ci if (dev) 6878c2ecf20Sopenharmony_ci err = device_rename(&dev->dev, dn.name); 6888c2ecf20Sopenharmony_ci else 6898c2ecf20Sopenharmony_ci err = -ENODEV; 6908c2ecf20Sopenharmony_ci } 6918c2ecf20Sopenharmony_ci break; 6928c2ecf20Sopenharmony_ci default: 6938c2ecf20Sopenharmony_ci err = -EINVAL; 6948c2ecf20Sopenharmony_ci } 6958c2ecf20Sopenharmony_ci return err; 6968c2ecf20Sopenharmony_ci} 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_cistatic int 6998c2ecf20Sopenharmony_cibase_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len) 7008c2ecf20Sopenharmony_ci{ 7018c2ecf20Sopenharmony_ci struct sockaddr_mISDN *maddr = (struct sockaddr_mISDN *) addr; 7028c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 7038c2ecf20Sopenharmony_ci int err = 0; 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci if (addr_len < sizeof(struct sockaddr_mISDN)) 7068c2ecf20Sopenharmony_ci return -EINVAL; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci if (!maddr || maddr->family != AF_ISDN) 7098c2ecf20Sopenharmony_ci return -EINVAL; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci lock_sock(sk); 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci if (_pms(sk)->dev) { 7148c2ecf20Sopenharmony_ci err = -EALREADY; 7158c2ecf20Sopenharmony_ci goto done; 7168c2ecf20Sopenharmony_ci } 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci _pms(sk)->dev = get_mdevice(maddr->dev); 7198c2ecf20Sopenharmony_ci if (!_pms(sk)->dev) { 7208c2ecf20Sopenharmony_ci err = -ENODEV; 7218c2ecf20Sopenharmony_ci goto done; 7228c2ecf20Sopenharmony_ci } 7238c2ecf20Sopenharmony_ci sk->sk_state = MISDN_BOUND; 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_cidone: 7268c2ecf20Sopenharmony_ci release_sock(sk); 7278c2ecf20Sopenharmony_ci return err; 7288c2ecf20Sopenharmony_ci} 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_cistatic const struct proto_ops base_sock_ops = { 7318c2ecf20Sopenharmony_ci .family = PF_ISDN, 7328c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 7338c2ecf20Sopenharmony_ci .release = base_sock_release, 7348c2ecf20Sopenharmony_ci .ioctl = base_sock_ioctl, 7358c2ecf20Sopenharmony_ci .bind = base_sock_bind, 7368c2ecf20Sopenharmony_ci .getname = sock_no_getname, 7378c2ecf20Sopenharmony_ci .sendmsg = sock_no_sendmsg, 7388c2ecf20Sopenharmony_ci .recvmsg = sock_no_recvmsg, 7398c2ecf20Sopenharmony_ci .listen = sock_no_listen, 7408c2ecf20Sopenharmony_ci .shutdown = sock_no_shutdown, 7418c2ecf20Sopenharmony_ci .connect = sock_no_connect, 7428c2ecf20Sopenharmony_ci .socketpair = sock_no_socketpair, 7438c2ecf20Sopenharmony_ci .accept = sock_no_accept, 7448c2ecf20Sopenharmony_ci .mmap = sock_no_mmap 7458c2ecf20Sopenharmony_ci}; 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_cistatic int 7498c2ecf20Sopenharmony_cibase_sock_create(struct net *net, struct socket *sock, int protocol, int kern) 7508c2ecf20Sopenharmony_ci{ 7518c2ecf20Sopenharmony_ci struct sock *sk; 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci if (sock->type != SOCK_RAW) 7548c2ecf20Sopenharmony_ci return -ESOCKTNOSUPPORT; 7558c2ecf20Sopenharmony_ci if (!capable(CAP_NET_RAW)) 7568c2ecf20Sopenharmony_ci return -EPERM; 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci sk = sk_alloc(net, PF_ISDN, GFP_KERNEL, &mISDN_proto, kern); 7598c2ecf20Sopenharmony_ci if (!sk) 7608c2ecf20Sopenharmony_ci return -ENOMEM; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci sock_init_data(sock, sk); 7638c2ecf20Sopenharmony_ci sock->ops = &base_sock_ops; 7648c2ecf20Sopenharmony_ci sock->state = SS_UNCONNECTED; 7658c2ecf20Sopenharmony_ci sock_reset_flag(sk, SOCK_ZAPPED); 7668c2ecf20Sopenharmony_ci sk->sk_protocol = protocol; 7678c2ecf20Sopenharmony_ci sk->sk_state = MISDN_OPEN; 7688c2ecf20Sopenharmony_ci mISDN_sock_link(&base_sockets, sk); 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci return 0; 7718c2ecf20Sopenharmony_ci} 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_cistatic int 7748c2ecf20Sopenharmony_cimISDN_sock_create(struct net *net, struct socket *sock, int proto, int kern) 7758c2ecf20Sopenharmony_ci{ 7768c2ecf20Sopenharmony_ci int err = -EPROTONOSUPPORT; 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci switch (proto) { 7798c2ecf20Sopenharmony_ci case ISDN_P_BASE: 7808c2ecf20Sopenharmony_ci err = base_sock_create(net, sock, proto, kern); 7818c2ecf20Sopenharmony_ci break; 7828c2ecf20Sopenharmony_ci case ISDN_P_TE_S0: 7838c2ecf20Sopenharmony_ci case ISDN_P_NT_S0: 7848c2ecf20Sopenharmony_ci case ISDN_P_TE_E1: 7858c2ecf20Sopenharmony_ci case ISDN_P_NT_E1: 7868c2ecf20Sopenharmony_ci case ISDN_P_LAPD_TE: 7878c2ecf20Sopenharmony_ci case ISDN_P_LAPD_NT: 7888c2ecf20Sopenharmony_ci case ISDN_P_B_RAW: 7898c2ecf20Sopenharmony_ci case ISDN_P_B_HDLC: 7908c2ecf20Sopenharmony_ci case ISDN_P_B_X75SLP: 7918c2ecf20Sopenharmony_ci case ISDN_P_B_L2DTMF: 7928c2ecf20Sopenharmony_ci case ISDN_P_B_L2DSP: 7938c2ecf20Sopenharmony_ci case ISDN_P_B_L2DSPHDLC: 7948c2ecf20Sopenharmony_ci err = data_sock_create(net, sock, proto, kern); 7958c2ecf20Sopenharmony_ci break; 7968c2ecf20Sopenharmony_ci default: 7978c2ecf20Sopenharmony_ci return err; 7988c2ecf20Sopenharmony_ci } 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci return err; 8018c2ecf20Sopenharmony_ci} 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_cistatic const struct net_proto_family mISDN_sock_family_ops = { 8048c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 8058c2ecf20Sopenharmony_ci .family = PF_ISDN, 8068c2ecf20Sopenharmony_ci .create = mISDN_sock_create, 8078c2ecf20Sopenharmony_ci}; 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ciint 8108c2ecf20Sopenharmony_cimisdn_sock_init(u_int *deb) 8118c2ecf20Sopenharmony_ci{ 8128c2ecf20Sopenharmony_ci int err; 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci debug = deb; 8158c2ecf20Sopenharmony_ci err = sock_register(&mISDN_sock_family_ops); 8168c2ecf20Sopenharmony_ci if (err) 8178c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: error(%d)\n", __func__, err); 8188c2ecf20Sopenharmony_ci return err; 8198c2ecf20Sopenharmony_ci} 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_civoid 8228c2ecf20Sopenharmony_cimisdn_sock_cleanup(void) 8238c2ecf20Sopenharmony_ci{ 8248c2ecf20Sopenharmony_ci sock_unregister(PF_ISDN); 8258c2ecf20Sopenharmony_ci} 826