📄 af_x25.c
字号:
if (msg->msg_flags & MSG_OOB) skb_queue_tail(&x25->interrupt_out_queue, skb); else { len = x25_output(sk, skb); if (len < 0) kfree_skb(skb); else if (x25->qbitincl) len++; } /* * lock_sock() is currently only used to serialize this x25_kick() * against input-driven x25_kick() calls. It currently only blocks * incoming packets for this socket and does not protect against * any other socket state changes and is not called from anywhere * else. As x25_kick() cannot block and as long as all socket * operations are BKL-wrapped, we don't need take to care about * purging the backlog queue in x25_release(). * * Using lock_sock() to protect all socket operations entirely * (and making the whole x25 stack SMP aware) unfortunately would * require major changes to {send,recv}msg and skb allocation methods. * -> 2.5 ;) */ lock_sock(sk); x25_kick(sk); release_sock(sk); rc = len;out: return rc;out_kfree_skb: kfree_skb(skb); goto out;}static int x25_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t size, int flags){ struct sock *sk = sock->sk; struct x25_sock *x25 = x25_sk(sk); struct sockaddr_x25 *sx25 = (struct sockaddr_x25 *)msg->msg_name; size_t copied; int qbit; struct sk_buff *skb; unsigned char *asmptr; int rc = -ENOTCONN; /* * This works for seqpacket too. The receiver has ordered the queue for * us! We do one quick check first though */ if (sk->sk_state != TCP_ESTABLISHED) goto out; if (flags & MSG_OOB) { rc = -EINVAL; if (sock_flag(sk, SOCK_URGINLINE) || !skb_peek(&x25->interrupt_in_queue)) goto out; skb = skb_dequeue(&x25->interrupt_in_queue); skb_pull(skb, X25_STD_MIN_LEN); /* * No Q bit information on Interrupt data. */ if (x25->qbitincl) { asmptr = skb_push(skb, 1); *asmptr = 0x00; } msg->msg_flags |= MSG_OOB; } else { /* Now we can treat all alike */ skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &rc); if (!skb) goto out; qbit = (skb->data[0] & X25_Q_BIT) == X25_Q_BIT; skb_pull(skb, x25->neighbour->extended ? X25_EXT_MIN_LEN : X25_STD_MIN_LEN); if (x25->qbitincl) { asmptr = skb_push(skb, 1); *asmptr = qbit; } } skb->h.raw = skb->data; copied = skb->len; if (copied > size) { copied = size; msg->msg_flags |= MSG_TRUNC; } /* Currently, each datagram always contains a complete record */ msg->msg_flags |= MSG_EOR; rc = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); if (rc) goto out_free_dgram; if (sx25) { sx25->sx25_family = AF_X25; sx25->sx25_addr = x25->dest_addr; } msg->msg_namelen = sizeof(struct sockaddr_x25); lock_sock(sk); x25_check_rbuf(sk); release_sock(sk); rc = copied;out_free_dgram: skb_free_datagram(sk, skb);out: return rc;}static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg){ struct sock *sk = sock->sk; struct x25_sock *x25 = x25_sk(sk); void __user *argp = (void __user *)arg; int rc; switch (cmd) { case TIOCOUTQ: { int amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc); if (amount < 0) amount = 0; rc = put_user(amount, (unsigned int __user *)argp); break; } case TIOCINQ: { struct sk_buff *skb; int amount = 0; /* * These two are safe on a single CPU system as * only user tasks fiddle here */ if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL) amount = skb->len; rc = put_user(amount, (unsigned int __user *)argp); break; } case SIOCGSTAMP: rc = -EINVAL; if (sk) rc = sock_get_timestamp(sk, (struct timeval __user *)argp); break; case SIOCGIFADDR: case SIOCSIFADDR: case SIOCGIFDSTADDR: case SIOCSIFDSTADDR: case SIOCGIFBRDADDR: case SIOCSIFBRDADDR: case SIOCGIFNETMASK: case SIOCSIFNETMASK: case SIOCGIFMETRIC: case SIOCSIFMETRIC: rc = -EINVAL; break; case SIOCADDRT: case SIOCDELRT: rc = -EPERM; if (!capable(CAP_NET_ADMIN)) break; rc = x25_route_ioctl(cmd, argp); break; case SIOCX25GSUBSCRIP: rc = x25_subscr_ioctl(cmd, argp); break; case SIOCX25SSUBSCRIP: rc = -EPERM; if (!capable(CAP_NET_ADMIN)) break; rc = x25_subscr_ioctl(cmd, argp); break; case SIOCX25GFACILITIES: { struct x25_facilities fac = x25->facilities; rc = copy_to_user(argp, &fac, sizeof(fac)) ? -EFAULT : 0; break; } case SIOCX25SFACILITIES: { struct x25_facilities facilities; rc = -EFAULT; if (copy_from_user(&facilities, argp, sizeof(facilities))) break; rc = -EINVAL; if (sk->sk_state != TCP_LISTEN && sk->sk_state != TCP_CLOSE) break; if (facilities.pacsize_in < X25_PS16 || facilities.pacsize_in > X25_PS4096) break; if (facilities.pacsize_out < X25_PS16 || facilities.pacsize_out > X25_PS4096) break; if (facilities.winsize_in < 1 || facilities.winsize_in > 127) break; if (facilities.throughput < 0x03 || facilities.throughput > 0xDD) break; if (facilities.reverse && (facilities.reverse | 0x81)!= 0x81) break; x25->facilities = facilities; rc = 0; break; } case SIOCX25GDTEFACILITIES: { rc = copy_to_user(argp, &x25->dte_facilities, sizeof(x25->dte_facilities)); if (rc) rc = -EFAULT; break; } case SIOCX25SDTEFACILITIES: { struct x25_dte_facilities dtefacs; rc = -EFAULT; if (copy_from_user(&dtefacs, argp, sizeof(dtefacs))) break; rc = -EINVAL; if (sk->sk_state != TCP_LISTEN && sk->sk_state != TCP_CLOSE) break; if (dtefacs.calling_len > X25_MAX_AE_LEN) break; if (dtefacs.calling_ae == NULL) break; if (dtefacs.called_len > X25_MAX_AE_LEN) break; if (dtefacs.called_ae == NULL) break; x25->dte_facilities = dtefacs; rc = 0; break; } case SIOCX25GCALLUSERDATA: { struct x25_calluserdata cud = x25->calluserdata; rc = copy_to_user(argp, &cud, sizeof(cud)) ? -EFAULT : 0; break; } case SIOCX25SCALLUSERDATA: { struct x25_calluserdata calluserdata; rc = -EFAULT; if (copy_from_user(&calluserdata, argp, sizeof(calluserdata))) break; rc = -EINVAL; if (calluserdata.cudlength > X25_MAX_CUD_LEN) break; x25->calluserdata = calluserdata; rc = 0; break; } case SIOCX25GCAUSEDIAG: { struct x25_causediag causediag; causediag = x25->causediag; rc = copy_to_user(argp, &causediag, sizeof(causediag)) ? -EFAULT : 0; break; } case SIOCX25SCUDMATCHLEN: { struct x25_subaddr sub_addr; rc = -EINVAL; if(sk->sk_state != TCP_CLOSE) break; rc = -EFAULT; if (copy_from_user(&sub_addr, argp, sizeof(sub_addr))) break; rc = -EINVAL; if(sub_addr.cudmatchlength > X25_MAX_CUD_LEN) break; x25->cudmatchlength = sub_addr.cudmatchlength; rc = 0; break; } case SIOCX25CALLACCPTAPPRV: { rc = -EINVAL; if (sk->sk_state != TCP_CLOSE) break; x25->accptapprv = X25_ALLOW_ACCPT_APPRV; rc = 0; break; } case SIOCX25SENDCALLACCPT: { rc = -EINVAL; if (sk->sk_state != TCP_ESTABLISHED) break; if (x25->accptapprv) /* must call accptapprv above */ break; x25_write_internal(sk, X25_CALL_ACCEPTED); x25->state = X25_STATE_3; rc = 0; break; } default: rc = -ENOIOCTLCMD; break; } return rc;}static struct net_proto_family x25_family_ops = { .family = AF_X25, .create = x25_create, .owner = THIS_MODULE,};#ifdef CONFIG_COMPATstatic int compat_x25_subscr_ioctl(unsigned int cmd, struct compat_x25_subscrip_struct __user *x25_subscr32){ struct compat_x25_subscrip_struct x25_subscr; struct x25_neigh *nb; struct net_device *dev; int rc = -EINVAL; rc = -EFAULT; if (copy_from_user(&x25_subscr, x25_subscr32, sizeof(*x25_subscr32))) goto out; rc = -EINVAL; dev = x25_dev_get(x25_subscr.device); if (dev == NULL) goto out; nb = x25_get_neigh(dev); if (nb == NULL) goto out_dev_put; dev_put(dev); if (cmd == SIOCX25GSUBSCRIP) { x25_subscr.extended = nb->extended; x25_subscr.global_facil_mask = nb->global_facil_mask; rc = copy_to_user(x25_subscr32, &x25_subscr, sizeof(*x25_subscr32)) ? -EFAULT : 0; } else { rc = -EINVAL; if (x25_subscr.extended == 0 || x25_subscr.extended == 1) { rc = 0; nb->extended = x25_subscr.extended; nb->global_facil_mask = x25_subscr.global_facil_mask; } } x25_neigh_put(nb);out: return rc;out_dev_put: dev_put(dev); goto out;}static int compat_x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg){ void __user *argp = compat_ptr(arg); struct sock *sk = sock->sk; int rc = -ENOIOCTLCMD; switch(cmd) { case TIOCOUTQ: case TIOCINQ: rc = x25_ioctl(sock, cmd, (unsigned long)argp); break; case SIOCGSTAMP: rc = -EINVAL; if (sk) rc = compat_sock_get_timestamp(sk, (struct timeval __user*)argp); break; case SIOCGIFADDR: case SIOCSIFADDR: case SIOCGIFDSTADDR: case SIOCSIFDSTADDR: case SIOCGIFBRDADDR: case SIOCSIFBRDADDR: case SIOCGIFNETMASK: case SIOCSIFNETMASK: case SIOCGIFMETRIC: case SIOCSIFMETRIC: rc = -EINVAL; break; case SIOCADDRT: case SIOCDELRT: rc = -EPERM; if (!capable(CAP_NET_ADMIN)) break; rc = x25_route_ioctl(cmd, argp); break; case SIOCX25GSUBSCRIP: rc = compat_x25_subscr_ioctl(cmd, argp); break; case SIOCX25SSUBSCRIP: rc = -EPERM; if (!capable(CAP_NET_ADMIN)) break; rc = compat_x25_subscr_ioctl(cmd, argp); break; case SIOCX25GFACILITIES: case SIOCX25SFACILITIES: case SIOCX25GDTEFACILITIES: case SIOCX25SDTEFACILITIES: case SIOCX25GCALLUSERDATA: case SIOCX25SCALLUSERDATA: case SIOCX25GCAUSEDIAG: case SIOCX25SCUDMATCHLEN: case SIOCX25CALLACCPTAPPRV: case SIOCX25SENDCALLACCPT: rc = x25_ioctl(sock, cmd, (unsigned long)argp); break; default: rc = -ENOIOCTLCMD; break; } return rc;}#endifstatic const struct proto_ops SOCKOPS_WRAPPED(x25_proto_ops) = { .family = AF_X25, .owner = THIS_MODULE, .release = x25_release, .bind = x25_bind, .connect = x25_connect, .socketpair = sock_no_socketpair, .accept = x25_accept, .getname = x25_getname, .poll = datagram_poll, .ioctl = x25_ioctl,#ifdef CONFIG_COMPAT .compat_ioctl = compat_x25_ioctl,#endif .listen = x25_listen, .shutdown = sock_no_shutdown, .setsockopt = x25_setsockopt, .getsockopt = x25_getsockopt, .sendmsg = x25_sendmsg, .recvmsg = x25_recvmsg, .mmap = sock_no_mmap, .sendpage = sock_no_sendpage,};#include <linux/smp_lock.h>SOCKOPS_WRAP(x25_proto, AF_X25);static struct packet_type x25_packet_type = { .type = __constant_htons(ETH_P_X25), .func = x25_lapb_receive_frame,};static struct notifier_block x25_dev_notifier = { .notifier_call = x25_device_event,};void x25_kill_by_neigh(struct x25_neigh *nb){ struct sock *s; struct hlist_node *node; write_lock_bh(&x25_list_lock); sk_for_each(s, node, &x25_list) if (x25_sk(s)->neighbour == nb) x25_disconnect(s, ENETUNREACH, 0, 0); write_unlock_bh(&x25_list_lock);}static int __init x25_init(void){ int rc = proto_register(&x25_proto, 0); if (rc != 0) goto out; sock_register(&x25_family_ops); dev_add_pack(&x25_packet_type); register_netdevice_notifier(&x25_dev_notifier); printk(KERN_INFO "X.25 for Linux. Version 0.2 for Linux 2.1.15\n");#ifdef CONFIG_SYSCTL x25_register_sysctl();#endif x25_proc_init();out: return rc;}module_init(x25_init);static void __exit x25_exit(void){ x25_proc_exit(); x25_link_free(); x25_route_free();#ifdef CONFIG_SYSCTL x25_unregister_sysctl();#endif unregister_netdevice_notifier(&x25_dev_notifier); dev_remove_pack(&x25_packet_type); sock_unregister(AF_X25); proto_unregister(&x25_proto);}module_exit(x25_exit);MODULE_AUTHOR("Jonathan Naylor <g4klx@g4klx.demon.co.uk>");MODULE_DESCRIPTION("The X.25 Packet Layer network layer protocol");MODULE_LICENSE("GPL");MODULE_ALIAS_NETPROTO(PF_X25);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -