⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ddp.c

📁 《嵌入式系统设计与实例开发实验教材二源码》Linux内核移植与编译实验
💻 C
📖 第 1 页 / 共 4 页
字号:
	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(&ltalk_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(&ltalk_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 + -