📄 af_rose.c
字号:
if (sk->zapped) return -EADDRNOTAVAIL; if (sk->shutdown & SEND_SHUTDOWN) { send_sig(SIGPIPE, current, 0); return -EPIPE; } if (sk->protinfo.rose->neighbour == NULL || sk->protinfo.rose->device == NULL) return -ENETUNREACH; if (usrose != NULL) { if (msg->msg_namelen != sizeof(struct sockaddr_rose) && msg->msg_namelen != sizeof(struct full_sockaddr_rose)) return -EINVAL; memset(&srose, 0, sizeof(struct full_sockaddr_rose)); memcpy(&srose, usrose, msg->msg_namelen); if (rosecmp(&sk->protinfo.rose->dest_addr, &srose.srose_addr) != 0 || ax25cmp(&sk->protinfo.rose->dest_call, &srose.srose_call) != 0) return -EISCONN; if (srose.srose_ndigis != sk->protinfo.rose->dest_ndigis) return -EISCONN; if (srose.srose_ndigis == sk->protinfo.rose->dest_ndigis) { for (n = 0 ; n < srose.srose_ndigis ; n++) if (ax25cmp(&sk->protinfo.rose->dest_digis[n], &srose.srose_digis[n]) != 0) return -EISCONN; } if (srose.srose_family != AF_ROSE) return -EINVAL; } else { if (sk->state != TCP_ESTABLISHED) return -ENOTCONN; srose.srose_family = AF_ROSE; srose.srose_addr = sk->protinfo.rose->dest_addr; srose.srose_call = sk->protinfo.rose->dest_call; srose.srose_ndigis = sk->protinfo.rose->dest_ndigis; for (n = 0 ; n < sk->protinfo.rose->dest_ndigis ; n++) srose.srose_digis[n] = sk->protinfo.rose->dest_digis[n]; } SOCK_DEBUG(sk, "ROSE: sendto: Addresses built.\n"); /* Build a packet */ SOCK_DEBUG(sk, "ROSE: sendto: building packet.\n"); size = len + AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN; if ((skb = sock_alloc_send_skb(sk, size, 0, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL) return err; skb_reserve(skb, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN); /* * Put the data on the end */ SOCK_DEBUG(sk, "ROSE: Appending 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.rose->qbitincl) { qbit = skb->data[0]; skb_pull(skb, 1); } /* * Push down the ROSE header */ asmptr = skb_push(skb, ROSE_MIN_LEN); SOCK_DEBUG(sk, "ROSE: Building Network Header.\n"); /* Build a ROSE Network header */ asmptr[0] = ((sk->protinfo.rose->lci >> 8) & 0x0F) | ROSE_GFI; asmptr[1] = (sk->protinfo.rose->lci >> 0) & 0xFF; asmptr[2] = ROSE_DATA; if (qbit) asmptr[0] |= ROSE_Q_BIT; SOCK_DEBUG(sk, "ROSE: Built header.\n"); SOCK_DEBUG(sk, "ROSE: Transmitting buffer\n"); if (sk->state != TCP_ESTABLISHED) { kfree_skb(skb); return -ENOTCONN; }#ifdef M_BIT#define ROSE_PACLEN (256-ROSE_MIN_LEN) if (skb->len - ROSE_MIN_LEN > ROSE_PACLEN) { unsigned char header[ROSE_MIN_LEN]; struct sk_buff *skbn; int frontlen; int lg; /* Save a copy of the Header */ memcpy(header, skb->data, ROSE_MIN_LEN); skb_pull(skb, ROSE_MIN_LEN); frontlen = skb_headroom(skb); while (skb->len > 0) { if ((skbn = sock_alloc_send_skb(sk, frontlen + ROSE_PACLEN, 0, 0, &err)) == NULL) return err; skbn->sk = sk; skbn->free = 1; skbn->arp = 1; skb_reserve(skbn, frontlen); lg = (ROSE_PACLEN > skb->len) ? skb->len : ROSE_PACLEN; /* Copy the user data */ memcpy(skb_put(skbn, lg), skb->data, lg); skb_pull(skb, lg); /* Duplicate the Header */ skb_push(skbn, ROSE_MIN_LEN); memcpy(skbn->data, header, ROSE_MIN_LEN); if (skb->len > 0) skbn->data[2] |= M_BIT; skb_queue_tail(&sk->write_queue, skbn); /* Throw it on the queue */ } skb->free = 1; kfree_skb(skb, FREE_WRITE); } else { skb_queue_tail(&sk->write_queue, skb); /* Throw it on the queue */ }#else skb_queue_tail(&sk->write_queue, skb); /* Shove it onto the queue */#endif rose_kick(sk); return len;}static int rose_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags, struct scm_cookie *scm){ struct sock *sk = sock->sk; struct sockaddr_rose *srose = (struct sockaddr_rose *)msg->msg_name; int copied, qbit; unsigned char *asmptr; struct sk_buff *skb; int n, 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; /* 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] & ROSE_Q_BIT) == ROSE_Q_BIT; skb_pull(skb, ROSE_MIN_LEN); if (sk->protinfo.rose->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; } skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); if (srose != NULL) { srose->srose_family = AF_ROSE; srose->srose_addr = sk->protinfo.rose->dest_addr; srose->srose_call = sk->protinfo.rose->dest_call; srose->srose_ndigis = sk->protinfo.rose->dest_ndigis; if (msg->msg_namelen >= sizeof(struct full_sockaddr_rose)) { struct full_sockaddr_rose *full_srose = (struct full_sockaddr_rose *)msg->msg_name; for (n = 0 ; n < sk->protinfo.rose->dest_ndigis ; n++) full_srose->srose_digis[n] = sk->protinfo.rose->dest_digis[n]; msg->msg_namelen = sizeof(struct full_sockaddr_rose); } else { if (sk->protinfo.rose->dest_ndigis >= 1) { srose->srose_ndigis = 1; srose->srose_digi = sk->protinfo.rose->dest_digis[0]; } msg->msg_namelen = sizeof(struct sockaddr_rose); } } skb_free_datagram(sk, skb); return copied;}static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg){ struct sock *sk = sock->sk; switch (cmd) { case TIOCOUTQ: { long 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; long amount = 0L; /* 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: case SIOCRSCLRRT: if (!capable(CAP_NET_ADMIN)) return -EPERM; return rose_rt_ioctl(cmd, (void *)arg); case SIOCRSGCAUSE: { struct rose_cause_struct rose_cause; rose_cause.cause = sk->protinfo.rose->cause; rose_cause.diagnostic = sk->protinfo.rose->diagnostic; return copy_to_user((void *)arg, &rose_cause, sizeof(struct rose_cause_struct)) ? -EFAULT : 0; } case SIOCRSSCAUSE: { struct rose_cause_struct rose_cause; if (copy_from_user(&rose_cause, (void *)arg, sizeof(struct rose_cause_struct))) return -EFAULT; sk->protinfo.rose->cause = rose_cause.cause; sk->protinfo.rose->diagnostic = rose_cause.diagnostic; return 0; } case SIOCRSSL2CALL: if (!capable(CAP_NET_ADMIN)) return -EPERM; if (ax25cmp(&rose_callsign, &null_ax25_address) != 0) ax25_listen_release(&rose_callsign, NULL); if (copy_from_user(&rose_callsign, (void *)arg, sizeof(ax25_address))) return -EFAULT; if (ax25cmp(&rose_callsign, &null_ax25_address) != 0) ax25_listen_register(&rose_callsign, NULL); return 0; case SIOCRSGL2CALL: return copy_to_user((void *)arg, &rose_callsign, sizeof(ax25_address)) ? -EFAULT : 0; case SIOCRSACCEPT: if (sk->protinfo.rose->state == ROSE_STATE_5) { rose_write_internal(sk, ROSE_CALL_ACCEPTED); rose_start_idletimer(sk); sk->protinfo.rose->condition = 0x00; sk->protinfo.rose->vs = 0; sk->protinfo.rose->va = 0; sk->protinfo.rose->vr = 0; sk->protinfo.rose->vl = 0; sk->protinfo.rose->state = ROSE_STATE_3; } return 0; default: return dev_ioctl(cmd, (void *)arg); } /*NOTREACHED*/ return 0;}static int rose_get_info(char *buffer, char **start, off_t offset, int length){ struct sock *s; struct net_device *dev; const char *devname, *callsign; int len = 0; off_t pos = 0; off_t begin = 0; cli(); len += sprintf(buffer, "dest_addr dest_call src_addr src_call dev lci neigh st vs vr va t t1 t2 t3 hb idle Snd-Q Rcv-Q inode\n"); for (s = rose_list; s != NULL; s = s->next) { if ((dev = s->protinfo.rose->device) == NULL) devname = "???"; else devname = dev->name; len += sprintf(buffer + len, "%-10s %-9s ", rose2asc(&s->protinfo.rose->dest_addr), ax2asc(&s->protinfo.rose->dest_call)); if (ax25cmp(&s->protinfo.rose->source_call, &null_ax25_address) == 0) callsign = "??????-?"; else callsign = ax2asc(&s->protinfo.rose->source_call); len += sprintf(buffer + len, "%-10s %-9s %-5s %3.3X %05d %d %d %d %d %3lu %3lu %3lu %3lu %3lu %3lu/%03lu %5d %5d %ld\n", rose2asc(&s->protinfo.rose->source_addr), callsign, devname, s->protinfo.rose->lci & 0x0FFF, (s->protinfo.rose->neighbour) ? s->protinfo.rose->neighbour->number : 0, s->protinfo.rose->state, s->protinfo.rose->vs, s->protinfo.rose->vr, s->protinfo.rose->va, ax25_display_timer(&s->protinfo.rose->timer) / HZ, s->protinfo.rose->t1 / HZ, s->protinfo.rose->t2 / HZ, s->protinfo.rose->t3 / HZ, s->protinfo.rose->hb / HZ, ax25_display_timer(&s->protinfo.rose->idletimer) / (60 * HZ), s->protinfo.rose->idle / (60 * 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);} static struct net_proto_family rose_family_ops = { PF_ROSE, rose_create};static struct proto_ops SOCKOPS_WRAPPED(rose_proto_ops) = { family: PF_ROSE, release: rose_release, bind: rose_bind, connect: rose_connect, socketpair: sock_no_socketpair, accept: rose_accept, getname: rose_getname, poll: datagram_poll, ioctl: rose_ioctl, listen: rose_listen, shutdown: sock_no_shutdown, setsockopt: rose_setsockopt, getsockopt: rose_getsockopt, sendmsg: rose_sendmsg, recvmsg: rose_recvmsg, mmap: sock_no_mmap,};#include <linux/smp_lock.h>SOCKOPS_WRAP(rose_proto, PF_ROSE);static struct notifier_block rose_dev_notifier = { rose_device_event, 0};static struct net_device *dev_rose;static int __init rose_proto_init(void){ int i; rose_callsign = null_ax25_address; if ((dev_rose = kmalloc(rose_ndevs * sizeof(struct net_device), GFP_KERNEL)) == NULL) { printk(KERN_ERR "ROSE: rose_proto_init - unable to allocate device structure\n"); return -1; } memset(dev_rose, 0x00, rose_ndevs * sizeof(struct net_device)); for (i = 0; i < rose_ndevs; i++) { sprintf(dev_rose[i].name, "rose%d", i); dev_rose[i].init = rose_init; register_netdev(&dev_rose[i]); } sock_register(&rose_family_ops); register_netdevice_notifier(&rose_dev_notifier); printk(KERN_INFO "F6FBB/G4KLX ROSE for Linux. Version 0.62 for AX25.037 Linux 2.4\n"); ax25_protocol_register(AX25_P_ROSE, rose_route_frame); ax25_linkfail_register(rose_link_failed);#ifdef CONFIG_SYSCTL rose_register_sysctl();#endif rose_loopback_init(); rose_add_loopback_neigh(); proc_net_create("rose", 0, rose_get_info); proc_net_create("rose_neigh", 0, rose_neigh_get_info); proc_net_create("rose_nodes", 0, rose_nodes_get_info); proc_net_create("rose_routes", 0, rose_routes_get_info); return 0;}module_init(rose_proto_init);EXPORT_NO_SYMBOLS;MODULE_PARM(rose_ndevs, "i");MODULE_PARM_DESC(rose_ndevs, "number of ROSE devices");MODULE_AUTHOR("Jonathan Naylor G4KLX <g4klx@g4klx.demon.co.uk>");MODULE_DESCRIPTION("The amateur radio ROSE network layer protocol");static void __exit rose_exit(void){ int i; proc_net_remove("rose"); proc_net_remove("rose_neigh"); proc_net_remove("rose_nodes"); proc_net_remove("rose_routes"); rose_loopback_clear(); rose_rt_free(); ax25_protocol_release(AX25_P_ROSE); ax25_linkfail_release(rose_link_failed); if (ax25cmp(&rose_callsign, &null_ax25_address) != 0) ax25_listen_release(&rose_callsign, NULL);#ifdef CONFIG_SYSCTL rose_unregister_sysctl();#endif unregister_netdevice_notifier(&rose_dev_notifier); sock_unregister(PF_ROSE); for (i = 0; i < rose_ndevs; i++) { if (dev_rose[i].priv != NULL) { kfree(dev_rose[i].priv); dev_rose[i].priv = NULL; unregister_netdev(&dev_rose[i]); } kfree(dev_rose[i].name); } kfree(dev_rose);}module_exit(rose_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -