📄 af_x25.c
字号:
*/ SOCK_DEBUG(sk, "x25_sendmsg: Copying user data\n"); asmptr = skb->h.raw = skb_put(skb, len); memcpy_fromiovec(asmptr, msg->msg_iov, len); /* * 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 (sk->protinfo.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 (sk->protinfo.x25->neighbour->extended) { asmptr = skb_push(skb, X25_STD_MIN_LEN); *asmptr++ = ((sk->protinfo.x25->lci >> 8) & 0x0F) | X25_GFI_EXTSEQ; *asmptr++ = (sk->protinfo.x25->lci >> 0) & 0xFF; *asmptr++ = X25_INTERRUPT; } else { asmptr = skb_push(skb, X25_STD_MIN_LEN); *asmptr++ = ((sk->protinfo.x25->lci >> 8) & 0x0F) | X25_GFI_STDSEQ; *asmptr++ = (sk->protinfo.x25->lci >> 0) & 0xFF; *asmptr++ = X25_INTERRUPT; } } else { if (sk->protinfo.x25->neighbour->extended) { /* Build an Extended X.25 header */ asmptr = skb_push(skb, X25_EXT_MIN_LEN); *asmptr++ = ((sk->protinfo.x25->lci >> 8) & 0x0F) | X25_GFI_EXTSEQ; *asmptr++ = (sk->protinfo.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++ = ((sk->protinfo.x25->lci >> 8) & 0x0F) | X25_GFI_STDSEQ; *asmptr++ = (sk->protinfo.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"); if (sk->state != TCP_ESTABLISHED) { kfree_skb(skb); return -ENOTCONN; } if (msg->msg_flags & MSG_OOB) { skb_queue_tail(&sk->protinfo.x25->interrupt_out_queue, skb); } else { len = x25_output(sk, skb); if(len<0){ kfree_skb(skb); } else { if(sk->protinfo.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); return len;}static int x25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags, struct scm_cookie *scm){ struct sock *sk = sock->sk; struct sockaddr_x25 *sx25 = (struct sockaddr_x25 *)msg->msg_name; int copied, qbit; struct sk_buff *skb; unsigned char *asmptr; int er; /* * This works for seqpacket too. The receiver has ordered the queue for * us! We do one quick check first though */ if (sk->state != TCP_ESTABLISHED) return -ENOTCONN; if (flags & MSG_OOB) { if (sk->urginline || skb_peek(&sk->protinfo.x25->interrupt_in_queue) == NULL) return -EINVAL; skb = skb_dequeue(&sk->protinfo.x25->interrupt_in_queue); skb_pull(skb, X25_STD_MIN_LEN); /* * No Q bit information on Interrupt data. */ if (sk->protinfo.x25->qbitincl) { asmptr = skb_push(skb, 1); *asmptr = 0x00; } msg->msg_flags |= MSG_OOB; } else { /* Now we can treat all alike */ if ((skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &er)) == NULL) return er; qbit = (skb->data[0] & X25_Q_BIT) == X25_Q_BIT; skb_pull(skb, (sk->protinfo.x25->neighbour->extended) ? X25_EXT_MIN_LEN : X25_STD_MIN_LEN); if (sk->protinfo.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; skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); if (sx25 != NULL) { sx25->sx25_family = AF_X25; sx25->sx25_addr = sk->protinfo.x25->dest_addr; } msg->msg_namelen = sizeof(struct sockaddr_x25); skb_free_datagram(sk, skb); return copied;}static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg){ struct sock *sk = sock->sk; switch (cmd) { case TIOCOUTQ: { int amount; amount = sk->sndbuf - atomic_read(&sk->wmem_alloc); if (amount < 0) amount = 0; return put_user(amount, (unsigned int *)arg); } 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->receive_queue)) != NULL) amount = skb->len; return put_user(amount, (unsigned int *)arg); } case SIOCGSTAMP: if (sk != NULL) { if (sk->stamp.tv_sec == 0) return -ENOENT; return copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)) ? -EFAULT : 0; } return -EINVAL; case SIOCGIFADDR: case SIOCSIFADDR: case SIOCGIFDSTADDR: case SIOCSIFDSTADDR: case SIOCGIFBRDADDR: case SIOCSIFBRDADDR: case SIOCGIFNETMASK: case SIOCSIFNETMASK: case SIOCGIFMETRIC: case SIOCSIFMETRIC: return -EINVAL; case SIOCADDRT: case SIOCDELRT: if (!capable(CAP_NET_ADMIN)) return -EPERM; return x25_route_ioctl(cmd, (void *)arg); case SIOCX25GSUBSCRIP: return x25_subscr_ioctl(cmd, (void *)arg); case SIOCX25SSUBSCRIP: if (!capable(CAP_NET_ADMIN)) return -EPERM; return x25_subscr_ioctl(cmd, (void *)arg); case SIOCX25GFACILITIES: { struct x25_facilities facilities; facilities = sk->protinfo.x25->facilities; return copy_to_user((void *)arg, &facilities, sizeof(facilities)) ? -EFAULT : 0; } case SIOCX25SFACILITIES: { struct x25_facilities facilities; if (copy_from_user(&facilities, (void *)arg, sizeof(facilities))) return -EFAULT; if (sk->state != TCP_LISTEN && sk->state != TCP_CLOSE) return -EINVAL; if (facilities.pacsize_in < X25_PS16 || facilities.pacsize_in > X25_PS4096) return -EINVAL; if (facilities.pacsize_out < X25_PS16 || facilities.pacsize_out > X25_PS4096) return -EINVAL; if (facilities.winsize_in < 1 || facilities.winsize_in > 127) return -EINVAL; if (facilities.throughput < 0x03 || facilities.throughput > 0xDD) return -EINVAL; if (facilities.reverse != 0 && facilities.reverse != 1) return -EINVAL; sk->protinfo.x25->facilities = facilities; return 0; } case SIOCX25GCALLUSERDATA: { struct x25_calluserdata calluserdata; calluserdata = sk->protinfo.x25->calluserdata; return copy_to_user((void *)arg, &calluserdata, sizeof(calluserdata)) ? -EFAULT : 0; } case SIOCX25SCALLUSERDATA: { struct x25_calluserdata calluserdata; if (copy_from_user(&calluserdata, (void *)arg, sizeof(calluserdata))) return -EFAULT; if (calluserdata.cudlength > X25_MAX_CUD_LEN) return -EINVAL; sk->protinfo.x25->calluserdata = calluserdata; return 0; } case SIOCX25GCAUSEDIAG: { struct x25_causediag causediag; causediag = sk->protinfo.x25->causediag; return copy_to_user((void *)arg, &causediag, sizeof(causediag)) ? -EFAULT : 0; } default: return dev_ioctl(cmd, (void *)arg); } /*NOTREACHED*/ return 0;}static int x25_get_info(char *buffer, char **start, off_t offset, int length){ struct sock *s; struct net_device *dev; const char *devname; int len = 0; off_t pos = 0; off_t begin = 0; cli(); len += sprintf(buffer, "dest_addr src_addr dev lci st vs vr va t t2 t21 t22 t23 Snd-Q Rcv-Q inode\n"); for (s = x25_list; s != NULL; s = s->next) { if (s->protinfo.x25->neighbour == NULL || (dev = s->protinfo.x25->neighbour->dev) == NULL) devname = "???"; else devname = s->protinfo.x25->neighbour->dev->name; len += sprintf(buffer + len, "%-10s %-10s %-5s %3.3X %d %d %d %d %3lu %3lu %3lu %3lu %3lu %5d %5d %ld\n", (s->protinfo.x25->dest_addr.x25_addr[0] == '\0') ? "*" : s->protinfo.x25->dest_addr.x25_addr, (s->protinfo.x25->source_addr.x25_addr[0] == '\0') ? "*" : s->protinfo.x25->source_addr.x25_addr, devname, s->protinfo.x25->lci & 0x0FFF, s->protinfo.x25->state, s->protinfo.x25->vs, s->protinfo.x25->vr, s->protinfo.x25->va, x25_display_timer(s) / HZ, s->protinfo.x25->t2 / HZ, s->protinfo.x25->t21 / HZ, s->protinfo.x25->t22 / HZ, s->protinfo.x25->t23 / HZ, atomic_read(&s->wmem_alloc), atomic_read(&s->rmem_alloc), s->socket != NULL ? s->socket->inode->i_ino : 0L); pos = begin + len; if (pos < offset) { len = 0; begin = pos; } if (pos > offset + length) break; } sti(); *start = buffer + (offset - begin); len -= (offset - begin); if (len > length) len = length; return(len);} struct net_proto_family x25_family_ops = { AF_X25, x25_create};static struct proto_ops SOCKOPS_WRAPPED(x25_proto_ops) = { family: AF_X25, 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,};#include <linux/smp_lock.h>SOCKOPS_WRAP(x25_proto, AF_X25);static struct packet_type x25_packet_type ={ 0, /* MUTTER ntohs(ETH_P_X25),*/ 0, /* copy */ x25_lapb_receive_frame, NULL, NULL,};struct notifier_block x25_dev_notifier = { x25_device_event, 0};void x25_kill_by_neigh(struct x25_neigh *neigh){ struct sock *s; for( s=x25_list; s != NULL; s=s->next){ if( s->protinfo.x25->neighbour == neigh ) x25_disconnect(s, ENETUNREACH, 0, 0); } }static int __init x25_init(void){#ifdef MODULE struct net_device *dev;#endif /* MODULE */ sock_register(&x25_family_ops); x25_packet_type.type = htons(ETH_P_X25); 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 proc_net_create("x25", 0, x25_get_info); proc_net_create("x25_routes", 0, x25_routes_get_info);#ifdef MODULE /* * Register any pre existing devices. */ read_lock(&dev_base_lock); for (dev = dev_base; dev != NULL; dev = dev->next) { if ((dev->flags & IFF_UP) && (dev->type == ARPHRD_X25#if defined(CONFIG_LLC) || defined(CONFIG_LLC_MODULE) || dev->type == ARPHRD_ETHER#endif )) x25_link_device_up(dev); } read_unlock(&dev_base_lock);#endif /* MODULE */ return 0;}module_init(x25_init);EXPORT_NO_SYMBOLS;MODULE_AUTHOR("Jonathan Naylor <g4klx@g4klx.demon.co.uk>");MODULE_DESCRIPTION("The X.25 Packet Layer network layer protocol");static void __exit x25_exit(void){ proc_net_remove("x25"); proc_net_remove("x25_routes"); 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -