📄 af_x25.c
字号:
if (!x25->neighbour) goto out; if (usx25) { rc = -EINVAL; if (msg->msg_namelen < sizeof(sx25)) goto out; memcpy(&sx25, usx25, sizeof(sx25)); rc = -EISCONN; if (strcmp(x25->dest_addr.x25_addr, sx25.sx25_addr.x25_addr)) goto out; rc = -EINVAL; if (sx25.sx25_family != AF_X25) goto out; } else { /* * FIXME 1003.1g - if the socket is like this because * it has become closed (not started closed) we ought * to SIGPIPE, EPIPE; */ rc = -ENOTCONN; if (sk->sk_state != TCP_ESTABLISHED) goto out; sx25.sx25_family = AF_X25; sx25.sx25_addr = x25->dest_addr; } SOCK_DEBUG(sk, "x25_sendmsg: sendto: Addresses built.\n"); /* Build a packet */ SOCK_DEBUG(sk, "x25_sendmsg: sendto: building packet.\n"); if ((msg->msg_flags & MSG_OOB) && len > 32) len = 32; size = len + X25_MAX_L2_LEN + X25_EXT_MIN_LEN; skb = sock_alloc_send_skb(sk, size, noblock, &rc); if (!skb) goto out; X25_SKB_CB(skb)->flags = msg->msg_flags; skb_reserve(skb, X25_MAX_L2_LEN + X25_EXT_MIN_LEN); /* * Put the data on the end */ SOCK_DEBUG(sk, "x25_sendmsg: Copying user data\n"); asmptr = skb->h.raw = skb_put(skb, len); rc = memcpy_fromiovec(asmptr, msg->msg_iov, len); if (rc) goto out_kfree_skb; /* * If the Q BIT Include socket option is in force, the first * byte of the user data is the logical value of the Q Bit. */ if (x25->qbitincl) { qbit = skb->data[0]; skb_pull(skb, 1); } /* * Push down the X.25 header */ SOCK_DEBUG(sk, "x25_sendmsg: Building X.25 Header.\n"); if (msg->msg_flags & MSG_OOB) { if (x25->neighbour->extended) { asmptr = skb_push(skb, X25_STD_MIN_LEN); *asmptr++ = ((x25->lci >> 8) & 0x0F) | X25_GFI_EXTSEQ; *asmptr++ = (x25->lci >> 0) & 0xFF; *asmptr++ = X25_INTERRUPT; } else { asmptr = skb_push(skb, X25_STD_MIN_LEN); *asmptr++ = ((x25->lci >> 8) & 0x0F) | X25_GFI_STDSEQ; *asmptr++ = (x25->lci >> 0) & 0xFF; *asmptr++ = X25_INTERRUPT; } } else { if (x25->neighbour->extended) { /* Build an Extended X.25 header */ asmptr = skb_push(skb, X25_EXT_MIN_LEN); *asmptr++ = ((x25->lci >> 8) & 0x0F) | X25_GFI_EXTSEQ; *asmptr++ = (x25->lci >> 0) & 0xFF; *asmptr++ = X25_DATA; *asmptr++ = X25_DATA; } else { /* Build an Standard X.25 header */ asmptr = skb_push(skb, X25_STD_MIN_LEN); *asmptr++ = ((x25->lci >> 8) & 0x0F) | X25_GFI_STDSEQ; *asmptr++ = (x25->lci >> 0) & 0xFF; *asmptr++ = X25_DATA; } if (qbit) skb->data[0] |= X25_Q_BIT; } SOCK_DEBUG(sk, "x25_sendmsg: Built header.\n"); SOCK_DEBUG(sk, "x25_sendmsg: Transmitting buffer\n"); rc = -ENOTCONN; if (sk->sk_state != TCP_ESTABLISHED) goto out_kfree_skb; 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_opt *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_opt *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 != 1) break; x25->facilities = facilities; 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; } default: rc = dev_ioctl(cmd, argp); break; } return rc;}struct net_proto_family x25_family_ops = { .family = AF_X25, .create = x25_create, .owner = THIS_MODULE,};static 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, .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,};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){ 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(); return 0;}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);}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 + -