📄 ddp.c
字号:
tosat.sat_addr.s_node = ddp->deh_dnode; tosat.sat_port = ddp->deh_dport; sock = atalk_search_socket(&tosat, atif); if (!sock) /* But not one of our sockets */ goto freeit; /* Queue packet (standard) */ skb->sk = sock; if (sock_queue_rcv_skb(sock, skb) < 0) goto freeit; goto out;freeit: kfree_skb(skb);out: return 0;}/* * Receive a LocalTalk frame. We make some demands on the caller here. * Caller must provide enough headroom on the packet to pull the short * header and append a long one. */static int ltalk_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt){ struct ddpehdr *ddp; struct at_addr *ap; /* Expand any short form frames */ if (skb->mac.raw[2] == 1) { /* Find our address */ ap = atalk_find_dev_addr(dev); if (!ap || skb->len < sizeof(struct ddpshdr)) { kfree_skb(skb); return 0; } /* * The push leaves us with a ddephdr not an shdr, and * handily the port bytes in the right place preset. */ skb_push(skb, sizeof(*ddp) - 4); ddp = (struct ddpehdr *)skb->data; /* Now fill in the long header */ /* * These two first. The mac overlays the new source/dest * network information so we MUST copy these before * we write the network numbers ! */ ddp->deh_dnode = skb->mac.raw[0]; /* From physical header */ ddp->deh_snode = skb->mac.raw[1]; /* From physical header */ ddp->deh_dnet = ap->s_net; /* Network number */ ddp->deh_snet = ap->s_net; ddp->deh_sum = 0; /* No checksum */ /* * Not sure about this bit... */ ddp->deh_len = skb->len; ddp->deh_hops = DDP_MAXHOPS; /* Non routable, so force a drop if we slip up later */ /* Mend the byte order */ *((__u16 *)ddp) = htons(*((__u16 *)ddp)); } skb->h.raw = skb->data; return atalk_rcv(skb, dev, pt);}static int atalk_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm){ struct sock *sk = sock->sk; struct sockaddr_at *usat = (struct sockaddr_at *)msg->msg_name; int flags = msg->msg_flags; int loopback = 0; struct sockaddr_at local_satalk, gsat; struct sk_buff *skb; struct net_device *dev; struct ddpehdr *ddp; int size; struct atalk_route *rt; int err; if (flags & ~MSG_DONTWAIT) return -EINVAL; if (len > DDP_MAXSZ) return -EMSGSIZE; if (usat) { if (sk->zapped) if (atalk_autobind(sk) < 0) return -EBUSY; if (msg->msg_namelen < sizeof(*usat) || usat->sat_family != AF_APPLETALK) return -EINVAL; /* netatalk doesn't implement this check */ if (usat->sat_addr.s_node == ATADDR_BCAST && !sk->broadcast) { printk(KERN_INFO "SO_BROADCAST: Fix your netatalk as " "it will break before 2.2\n");#if 0 return -EPERM;#endif } } else { if (sk->state != TCP_ESTABLISHED) return -ENOTCONN; usat = &local_satalk; usat->sat_family = AF_APPLETALK; usat->sat_port = sk->protinfo.af_at.dest_port; usat->sat_addr.s_node = sk->protinfo.af_at.dest_node; usat->sat_addr.s_net = sk->protinfo.af_at.dest_net; } /* Build a packet */ SOCK_DEBUG(sk, "SK %p: Got address.\n", sk); /* For headers */ size = sizeof(struct ddpehdr) + len + ddp_dl->header_length; if (usat->sat_addr.s_net || usat->sat_addr.s_node == ATADDR_ANYNODE) { rt = atrtr_find(&usat->sat_addr); if (!rt) return -ENETUNREACH; dev = rt->dev; } else { struct at_addr at_hint; at_hint.s_node = 0; at_hint.s_net = sk->protinfo.af_at.src_net; rt = atrtr_find(&at_hint); if (!rt) return -ENETUNREACH; dev = rt->dev; } SOCK_DEBUG(sk, "SK %p: Size needed %d, device %s\n", sk, size, dev->name); size += dev->hard_header_len; skb = sock_alloc_send_skb(sk, size, (flags & MSG_DONTWAIT), &err); if (!skb) return err; skb->sk = sk; skb_reserve(skb, ddp_dl->header_length); skb_reserve(skb, dev->hard_header_len); skb->dev = dev; SOCK_DEBUG(sk, "SK %p: Begin build.\n", sk); ddp = (struct ddpehdr *)skb_put(skb, sizeof(struct ddpehdr)); ddp->deh_pad = 0; ddp->deh_hops = 0; ddp->deh_len = len + sizeof(*ddp); /* * Fix up the length field [Ok this is horrible but otherwise * I end up with unions of bit fields and messy bit field order * compiler/endian dependencies.. */ *((__u16 *)ddp) = ntohs(*((__u16 *)ddp)); ddp->deh_dnet = usat->sat_addr.s_net; ddp->deh_snet = sk->protinfo.af_at.src_net; ddp->deh_dnode = usat->sat_addr.s_node; ddp->deh_snode = sk->protinfo.af_at.src_node; ddp->deh_dport = usat->sat_port; ddp->deh_sport = sk->protinfo.af_at.src_port; SOCK_DEBUG(sk, "SK %p: Copy user data (%d bytes).\n", sk, len); err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len); if (err) { kfree_skb(skb); return -EFAULT; } if (sk->no_check == 1) ddp->deh_sum = 0; else ddp->deh_sum = atalk_checksum(ddp, len + sizeof(*ddp)); /* * Loopback broadcast packets to non gateway targets (ie routes * to group we are in) */ if (ddp->deh_dnode == ATADDR_BCAST && !(rt->flags & RTF_GATEWAY) && !(dev->flags & IFF_LOOPBACK)) { struct sk_buff *skb2 = skb_copy(skb, GFP_KERNEL); if (skb2) { loopback = 1; SOCK_DEBUG(sk, "SK %p: send out(copy).\n", sk); if (aarp_send_ddp(dev, skb2, &usat->sat_addr, NULL) == -1) kfree_skb(skb2); /* else queued/sent above in the aarp queue */ } } if (dev->flags & IFF_LOOPBACK || loopback) { SOCK_DEBUG(sk, "SK %p: Loop back.\n", sk); /* loop back */ skb_orphan(skb); ddp_dl->datalink_header(ddp_dl, skb, dev->dev_addr); skb->mac.raw = skb->data; skb->h.raw = skb->data + ddp_dl->header_length + dev->hard_header_len; skb_pull(skb, dev->hard_header_len); skb_pull(skb, ddp_dl->header_length); atalk_rcv(skb, dev, NULL); } else { SOCK_DEBUG(sk, "SK %p: send out.\n", sk); if (rt->flags & RTF_GATEWAY) { gsat.sat_addr = rt->gateway; usat = &gsat; } if (aarp_send_ddp(dev, skb, &usat->sat_addr, NULL) == -1) kfree_skb(skb); /* else queued/sent above in the aarp queue */ } SOCK_DEBUG(sk, "SK %p: Done write (%d).\n", sk, len); return len;}static int atalk_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags, struct scm_cookie *scm){ struct sock *sk = sock->sk; struct sockaddr_at *sat = (struct sockaddr_at *)msg->msg_name; struct ddpehdr *ddp = NULL; int copied = 0; int err = 0; struct ddpebits ddphv; struct sk_buff *skb; skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &err); if (!skb) return err; ddp = (struct ddpehdr *)(skb->h.raw); *((__u16 *)&ddphv) = ntohs(*((__u16 *)ddp)); if (sk->type == SOCK_RAW) { copied = ddphv.deh_len; if (copied > size) { copied = size; msg->msg_flags |= MSG_TRUNC; } err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); } else { copied = ddphv.deh_len - sizeof(*ddp); if (copied > size) { copied = size; msg->msg_flags |= MSG_TRUNC; } err = skb_copy_datagram_iovec(skb, sizeof(*ddp), msg->msg_iov, copied); } if (!err) { if (sat) { sat->sat_family = AF_APPLETALK; sat->sat_port = ddp->deh_sport; sat->sat_addr.s_node = ddp->deh_snode; sat->sat_addr.s_net = ddp->deh_snet; } msg->msg_namelen = sizeof(*sat); } skb_free_datagram(sk, skb); /* Free the datagram. */ return err ? err : copied;}/* * AppleTalk ioctl calls. */static int atalk_ioctl(struct socket *sock,unsigned int cmd, unsigned long arg){ long amount = 0; struct sock *sk = sock->sk; switch (cmd) { /* Protocol layer */ case TIOCOUTQ: amount = sk->sndbuf - atomic_read(&sk->wmem_alloc); if (amount < 0) amount = 0; break; case TIOCINQ: { /* These two are safe on a single CPU system as only * user tasks fiddle here */ struct sk_buff *skb = skb_peek(&sk->receive_queue); if (skb) amount = skb->len-sizeof(struct ddpehdr); break; } case SIOCGSTAMP: if (!sk) return -EINVAL; if (!sk->stamp.tv_sec) return -ENOENT; return copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)) ? -EFAULT : 0; /* Routing */ case SIOCADDRT: case SIOCDELRT: if (!capable(CAP_NET_ADMIN)) return -EPERM; return atrtr_ioctl(cmd, (void *)arg); /* Interface */ case SIOCGIFADDR: case SIOCSIFADDR: case SIOCGIFBRDADDR: case SIOCATALKDIFADDR: case SIOCDIFADDR: case SIOCSARP: /* proxy AARP */ case SIOCDARP: /* proxy AARP */ { int ret; rtnl_lock(); ret = atif_ioctl(cmd, (void *)arg); rtnl_unlock(); return ret; } /* Physical layer ioctl calls */ case SIOCSIFLINK: case SIOCGIFHWADDR: case SIOCSIFHWADDR: case SIOCGIFFLAGS: case SIOCSIFFLAGS: case SIOCGIFMTU: case SIOCGIFCONF: case SIOCADDMULTI: case SIOCDELMULTI: case SIOCGIFCOUNT: case SIOCGIFINDEX: case SIOCGIFNAME: return dev_ioctl(cmd,(void *) arg); case SIOCSIFMETRIC: case SIOCSIFBRDADDR: case SIOCGIFNETMASK: case SIOCSIFNETMASK: case SIOCGIFMEM: case SIOCSIFMEM: case SIOCGIFDSTADDR: case SIOCSIFDSTADDR: return -EINVAL; default: return -EINVAL; } return put_user(amount, (int *)arg);}static struct net_proto_family atalk_family_ops ={ PF_APPLETALK, atalk_create};static struct proto_ops SOCKOPS_WRAPPED(atalk_dgram_ops)={ family: PF_APPLETALK, release: atalk_release, bind: atalk_bind, connect: atalk_connect, socketpair: sock_no_socketpair, accept: sock_no_accept, getname: atalk_getname, poll: datagram_poll, ioctl: atalk_ioctl, listen: sock_no_listen, shutdown: sock_no_shutdown, setsockopt: sock_no_setsockopt, getsockopt: sock_no_getsockopt, sendmsg: atalk_sendmsg, recvmsg: atalk_recvmsg, mmap: sock_no_mmap, sendpage: sock_no_sendpage,};#include <linux/smp_lock.h>SOCKOPS_WRAP(atalk_dgram, PF_APPLETALK);static struct notifier_block ddp_notifier={ ddp_device_event, NULL, 0};struct packet_type ltalk_packet_type={ 0, NULL, ltalk_rcv, NULL, NULL};struct packet_type ppptalk_packet_type={ 0, NULL, atalk_rcv, NULL, NULL};static char ddp_snap_id[] = {0x08, 0x00, 0x07, 0x80, 0x9B};/* Export symbols for use by drivers when AppleTalk is a module */EXPORT_SYMBOL(aarp_send_ddp);EXPORT_SYMBOL(atrtr_get_dev);EXPORT_SYMBOL(atalk_find_dev_addr);/* Called by proto.c on kernel start up */static int __init atalk_init(void){ (void) sock_register(&atalk_family_ops); ddp_dl = register_snap_client(ddp_snap_id, atalk_rcv); if (!ddp_dl) printk(KERN_CRIT "Unable to register DDP with SNAP.\n"); ltalk_packet_type.type = htons(ETH_P_LOCALTALK); dev_add_pack(<alk_packet_type); ppptalk_packet_type.type = htons(ETH_P_PPPTALK); dev_add_pack(&ppptalk_packet_type); register_netdevice_notifier(&ddp_notifier); aarp_proto_init(); proc_net_create("appletalk", 0, atalk_get_info); proc_net_create("atalk_route", 0, atalk_rt_get_info); proc_net_create("atalk_iface", 0, atalk_if_get_info);#ifdef CONFIG_PROC_FS aarp_register_proc_fs();#endif /* CONFIG_PROC_FS */#ifdef CONFIG_SYSCTL atalk_register_sysctl();#endif /* CONFIG_SYSCTL */ printk(KERN_INFO "NET4: AppleTalk 0.18a for Linux NET4.0\n"); return 0;}module_init(atalk_init);#ifdef MODULE/* * Note on MOD_{INC,DEC}_USE_COUNT: * * Use counts are incremented/decremented when * sockets are created/deleted. * * AppleTalk interfaces are not incremented until atalkd is run * and are only decremented when they are downed. * * Ergo, before the AppleTalk module can be removed, all AppleTalk * sockets be closed from user space. */static void __exit atalk_exit(void){#ifdef CONFIG_SYSCTL atalk_unregister_sysctl();#endif /* CONFIG_SYSCTL */ proc_net_remove("appletalk"); proc_net_remove("atalk_route"); proc_net_remove("atalk_iface");#ifdef CONFIG_PROC_FS aarp_unregister_proc_fs();#endif /* CONFIG_PROC_FS */ aarp_cleanup_module(); /* General aarp clean-up. */ unregister_netdevice_notifier(&ddp_notifier); dev_remove_pack(<alk_packet_type); dev_remove_pack(&ppptalk_packet_type); unregister_snap_client(ddp_snap_id); sock_unregister(PF_APPLETALK);}module_exit(atalk_exit);#endif /* MODULE */#endif /* CONFIG_ATALK || CONFIG_ATALK_MODULE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -