📄 af_netrom.c
字号:
nr_start_idletimer(make); return 1;}static int nr_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len){ struct sock *sk = sock->sk; struct nr_sock *nr = nr_sk(sk); struct sockaddr_ax25 *usax = (struct sockaddr_ax25 *)msg->msg_name; int err; struct sockaddr_ax25 sax; struct sk_buff *skb; unsigned char *asmptr; int size; if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR|MSG_CMSG_COMPAT)) return -EINVAL; lock_sock(sk); if (sock_flag(sk, SOCK_ZAPPED)) { err = -EADDRNOTAVAIL; goto out; } if (sk->sk_shutdown & SEND_SHUTDOWN) { send_sig(SIGPIPE, current, 0); err = -EPIPE; goto out; } if (nr->device == NULL) { err = -ENETUNREACH; goto out; } if (usax) { if (msg->msg_namelen < sizeof(sax)) { err = -EINVAL; goto out; } sax = *usax; if (ax25cmp(&nr->dest_addr, &sax.sax25_call) != 0) { err = -EISCONN; goto out; } if (sax.sax25_family != AF_NETROM) { err = -EINVAL; goto out; } } else { if (sk->sk_state != TCP_ESTABLISHED) { err = -ENOTCONN; goto out; } sax.sax25_family = AF_NETROM; sax.sax25_call = nr->dest_addr; } SOCK_DEBUG(sk, "NET/ROM: sendto: Addresses built.\n"); /* Build a packet */ SOCK_DEBUG(sk, "NET/ROM: sendto: building packet.\n"); size = len + NR_NETWORK_LEN + NR_TRANSPORT_LEN; if ((skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL) goto out; skb_reserve(skb, size - len); skb_reset_transport_header(skb); /* * Push down the NET/ROM header */ asmptr = skb_push(skb, NR_TRANSPORT_LEN); SOCK_DEBUG(sk, "Building NET/ROM Header.\n"); /* Build a NET/ROM Transport header */ *asmptr++ = nr->your_index; *asmptr++ = nr->your_id; *asmptr++ = 0; /* To be filled in later */ *asmptr++ = 0; /* Ditto */ *asmptr++ = NR_INFO; SOCK_DEBUG(sk, "Built header.\n"); /* * Put the data on the end */ skb_put(skb, len); SOCK_DEBUG(sk, "NET/ROM: Appending user data\n"); /* User data follows immediately after the NET/ROM transport header */ if (memcpy_fromiovec(skb_transport_header(skb), msg->msg_iov, len)) { kfree_skb(skb); err = -EFAULT; goto out; } SOCK_DEBUG(sk, "NET/ROM: Transmitting buffer\n"); if (sk->sk_state != TCP_ESTABLISHED) { kfree_skb(skb); err = -ENOTCONN; goto out; } nr_output(sk, skb); /* Shove it onto the queue */ err = len;out: release_sock(sk); return err;}static int nr_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t size, int flags){ struct sock *sk = sock->sk; struct sockaddr_ax25 *sax = (struct sockaddr_ax25 *)msg->msg_name; size_t copied; struct sk_buff *skb; int er; /* * This works for seqpacket too. The receiver has ordered the queue for * us! We do one quick check first though */ lock_sock(sk); if (sk->sk_state != TCP_ESTABLISHED) { release_sock(sk); return -ENOTCONN; } /* Now we can treat all alike */ if ((skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &er)) == NULL) { release_sock(sk); return er; } skb_reset_transport_header(skb); copied = skb->len; if (copied > size) { copied = size; msg->msg_flags |= MSG_TRUNC; } skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); if (sax != NULL) { sax->sax25_family = AF_NETROM; skb_copy_from_linear_data_offset(skb, 7, sax->sax25_call.ax25_call, AX25_ADDR_LEN); } msg->msg_namelen = sizeof(*sax); skb_free_datagram(sk, skb); release_sock(sk); return copied;}static int nr_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg){ struct sock *sk = sock->sk; void __user *argp = (void __user *)arg; int ret; switch (cmd) { case TIOCOUTQ: { long amount; lock_sock(sk); amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc); if (amount < 0) amount = 0; release_sock(sk); return put_user(amount, (int __user *)argp); } case TIOCINQ: { struct sk_buff *skb; long amount = 0L; lock_sock(sk); /* 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; release_sock(sk); return put_user(amount, (int __user *)argp); } case SIOCGSTAMP: lock_sock(sk); ret = sock_get_timestamp(sk, argp); release_sock(sk); return ret; case SIOCGSTAMPNS: lock_sock(sk); ret = sock_get_timestampns(sk, argp); release_sock(sk); return ret; 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: case SIOCNRDECOBS: if (!capable(CAP_NET_ADMIN)) return -EPERM; return nr_rt_ioctl(cmd, argp); default: return -ENOIOCTLCMD; } return 0;}#ifdef CONFIG_PROC_FSstatic void *nr_info_start(struct seq_file *seq, loff_t *pos){ struct sock *s; struct hlist_node *node; int i = 1; spin_lock_bh(&nr_list_lock); if (*pos == 0) return SEQ_START_TOKEN; sk_for_each(s, node, &nr_list) { if (i == *pos) return s; ++i; } return NULL;}static void *nr_info_next(struct seq_file *seq, void *v, loff_t *pos){ ++*pos; return (v == SEQ_START_TOKEN) ? sk_head(&nr_list) : sk_next((struct sock *)v);}static void nr_info_stop(struct seq_file *seq, void *v){ spin_unlock_bh(&nr_list_lock);}static int nr_info_show(struct seq_file *seq, void *v){ struct sock *s = v; struct net_device *dev; struct nr_sock *nr; const char *devname; char buf[11]; if (v == SEQ_START_TOKEN) seq_puts(seq,"user_addr dest_node src_node dev my your st vs vr va t1 t2 t4 idle n2 wnd Snd-Q Rcv-Q inode\n"); else { bh_lock_sock(s); nr = nr_sk(s); if ((dev = nr->device) == NULL) devname = "???"; else devname = dev->name; seq_printf(seq, "%-9s ", ax2asc(buf, &nr->user_addr)); seq_printf(seq, "%-9s ", ax2asc(buf, &nr->dest_addr)); seq_printf(seq,"%-9s %-3s %02X/%02X %02X/%02X %2d %3d %3d %3d %3lu/%03lu %2lu/%02lu %3lu/%03lu %3lu/%03lu %2d/%02d %3d %5d %5d %ld\n", ax2asc(buf, &nr->source_addr), devname, nr->my_index, nr->my_id, nr->your_index, nr->your_id, nr->state, nr->vs, nr->vr, nr->va, ax25_display_timer(&nr->t1timer) / HZ, nr->t1 / HZ, ax25_display_timer(&nr->t2timer) / HZ, nr->t2 / HZ, ax25_display_timer(&nr->t4timer) / HZ, nr->t4 / HZ, ax25_display_timer(&nr->idletimer) / (60 * HZ), nr->idle / (60 * HZ), nr->n2count, nr->n2, nr->window, atomic_read(&s->sk_wmem_alloc), atomic_read(&s->sk_rmem_alloc), s->sk_socket ? SOCK_INODE(s->sk_socket)->i_ino : 0L); bh_unlock_sock(s); } return 0;}static const struct seq_operations nr_info_seqops = { .start = nr_info_start, .next = nr_info_next, .stop = nr_info_stop, .show = nr_info_show,};static int nr_info_open(struct inode *inode, struct file *file){ return seq_open(file, &nr_info_seqops);}static const struct file_operations nr_info_fops = { .owner = THIS_MODULE, .open = nr_info_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release,};#endif /* CONFIG_PROC_FS */static struct net_proto_family nr_family_ops = { .family = PF_NETROM, .create = nr_create, .owner = THIS_MODULE,};static const struct proto_ops nr_proto_ops = { .family = PF_NETROM, .owner = THIS_MODULE, .release = nr_release, .bind = nr_bind, .connect = nr_connect, .socketpair = sock_no_socketpair, .accept = nr_accept, .getname = nr_getname, .poll = datagram_poll, .ioctl = nr_ioctl, .listen = nr_listen, .shutdown = sock_no_shutdown, .setsockopt = nr_setsockopt, .getsockopt = nr_getsockopt, .sendmsg = nr_sendmsg, .recvmsg = nr_recvmsg, .mmap = sock_no_mmap, .sendpage = sock_no_sendpage,};static struct notifier_block nr_dev_notifier = { .notifier_call = nr_device_event,};static struct net_device **dev_nr;static struct ax25_protocol nr_pid = { .pid = AX25_P_NETROM, .func = nr_route_frame};static struct ax25_linkfail nr_linkfail_notifier = { .func = nr_link_failed,};static int __init nr_proto_init(void){ int i; int rc = proto_register(&nr_proto, 0); if (rc != 0) goto out; if (nr_ndevs > 0x7fffffff/sizeof(struct net_device *)) { printk(KERN_ERR "NET/ROM: nr_proto_init - nr_ndevs parameter to large\n"); return -1; } dev_nr = kzalloc(nr_ndevs * sizeof(struct net_device *), GFP_KERNEL); if (dev_nr == NULL) { printk(KERN_ERR "NET/ROM: nr_proto_init - unable to allocate device array\n"); return -1; } for (i = 0; i < nr_ndevs; i++) { char name[IFNAMSIZ]; struct net_device *dev; sprintf(name, "nr%d", i); dev = alloc_netdev(sizeof(struct nr_private), name, nr_setup); if (!dev) { printk(KERN_ERR "NET/ROM: nr_proto_init - unable to allocate device structure\n"); goto fail; } dev->base_addr = i; if (register_netdev(dev)) { printk(KERN_ERR "NET/ROM: nr_proto_init - unable to register network device\n"); free_netdev(dev); goto fail; } lockdep_set_class(&dev->_xmit_lock, &nr_netdev_xmit_lock_key); dev_nr[i] = dev; } if (sock_register(&nr_family_ops)) { printk(KERN_ERR "NET/ROM: nr_proto_init - unable to register socket family\n"); goto fail; } register_netdevice_notifier(&nr_dev_notifier); ax25_register_pid(&nr_pid); ax25_linkfail_register(&nr_linkfail_notifier);#ifdef CONFIG_SYSCTL nr_register_sysctl();#endif nr_loopback_init(); proc_net_fops_create(&init_net, "nr", S_IRUGO, &nr_info_fops); proc_net_fops_create(&init_net, "nr_neigh", S_IRUGO, &nr_neigh_fops); proc_net_fops_create(&init_net, "nr_nodes", S_IRUGO, &nr_nodes_fops);out: return rc;fail: while (--i >= 0) { unregister_netdev(dev_nr[i]); free_netdev(dev_nr[i]); } kfree(dev_nr); proto_unregister(&nr_proto); rc = -1; goto out;}module_init(nr_proto_init);module_param(nr_ndevs, int, 0);MODULE_PARM_DESC(nr_ndevs, "number of NET/ROM devices");MODULE_AUTHOR("Jonathan Naylor G4KLX <g4klx@g4klx.demon.co.uk>");MODULE_DESCRIPTION("The amateur radio NET/ROM network and transport layer protocol");MODULE_LICENSE("GPL");MODULE_ALIAS_NETPROTO(PF_NETROM);static void __exit nr_exit(void){ int i; proc_net_remove(&init_net, "nr"); proc_net_remove(&init_net, "nr_neigh"); proc_net_remove(&init_net, "nr_nodes"); nr_loopback_clear(); nr_rt_free();#ifdef CONFIG_SYSCTL nr_unregister_sysctl();#endif ax25_linkfail_release(&nr_linkfail_notifier); ax25_protocol_release(AX25_P_NETROM); unregister_netdevice_notifier(&nr_dev_notifier); sock_unregister(PF_NETROM); for (i = 0; i < nr_ndevs; i++) { struct net_device *dev = dev_nr[i]; if (dev) { unregister_netdev(dev); free_netdev(dev); } } kfree(dev_nr); proto_unregister(&nr_proto);}module_exit(nr_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -