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

📄 ddp.c

📁 嵌入式系统设计与实例开发源码
💻 C
📖 第 1 页 / 共 4 页
字号:
			       iface->dev->name, ntohs(iface->address.s_net),			       iface->address.s_node,			       ntohs(iface->nets.nr_firstnet),			       ntohs(iface->nets.nr_lastnet), iface->status);		pos = begin + len;		if (pos < offset) {			len   = 0;			begin = pos;		}		if (pos > offset + length)			break;	}	spin_unlock_bh(&atalk_iface_lock);	*start = buffer + (offset - begin);	len -= (offset - begin);	if (len > length)		len = length;	return len;}/* Called from proc fs - just make it print the routes neatly */static int atalk_rt_get_info(char *buffer, char **start, off_t offset,			     int length){	off_t pos = 0;	off_t begin = 0;	int len = sprintf(buffer, "Target        Router  Flags Dev\n");	struct atalk_route *rt;	if (atrtr_default.dev) {		rt = &atrtr_default;		len += sprintf(buffer + len,"Default     %04X:%02X  %-4d  %s\n",			       ntohs(rt->gateway.s_net), rt->gateway.s_node,			       rt->flags, rt->dev->name);	}	read_lock_bh(&atalk_router_lock);	for (rt = atalk_router_list; rt; rt = rt->next) {		len += sprintf(buffer + len,				"%04X:%02X     %04X:%02X  %-4d  %s\n",			       ntohs(rt->target.s_net), rt->target.s_node,			       ntohs(rt->gateway.s_net), rt->gateway.s_node,			       rt->flags, rt->dev->name);		pos = begin + len;		if (pos < offset) {			len = 0;			begin = pos;		}		if (pos > offset + length)			break;	}	read_unlock_bh(&atalk_router_lock);	*start = buffer + (offset - begin);	len -= (offset - begin);	if (len > length)		len = length;	return len;}/**************************************************************************\*                                                                          ** Handling for system calls applied via the various interfaces to an       ** AppleTalk socket object.                                                 **                                                                          *\**************************************************************************//* * Checksum: This is 'optional'. It's quite likely also a good * candidate for assembler hackery 8) */unsigned short atalk_checksum(struct ddpehdr *ddp, int len){	unsigned long sum = 0;	/* Assume unsigned long is >16 bits */	unsigned char *data = (unsigned char *) ddp;	len  -= 4;		/* skip header 4 bytes */	data += 4;	/* This ought to be unwrapped neatly. I'll trust gcc for now */	while (len--) {		sum += *data;		sum <<= 1;		if (sum & 0x10000) {			sum++;			sum &= 0xFFFF;		}		data++;	}	/* Use 0xFFFF for 0. 0 itself means none */	return sum ? htons((unsigned short) sum) : 0xFFFF;}/* * Create a socket. Initialise the socket, blank the addresses * set the state. */static int atalk_create(struct socket *sock, int protocol){	struct sock *sk = sk_alloc(PF_APPLETALK, GFP_KERNEL, 1);	if (!sk)		return -ENOMEM;	switch (sock->type) {		/*		 * We permit SOCK_DGRAM and RAW is an extension. It is		 * trivial to do and gives you the full ELAP frame.		 * Should be handy for CAP 8) 		 */		case SOCK_RAW:		case SOCK_DGRAM:			sock->ops = &atalk_dgram_ops;			break;					case SOCK_STREAM:			/*			 * TODO: if you want to implement ADSP, here's the			 * place to start			 */			/*			sock->ops = &atalk_stream_ops;			break;			*/		default:			sk_free(sk);			return -ESOCKTNOSUPPORT;	}	MOD_INC_USE_COUNT;	sock_init_data(sock, sk);	sk->destruct = NULL;	/* Checksums on by default */	sk->zapped = 1;	return 0;}/* Free a socket. No work needed */static int atalk_release(struct socket *sock){	struct sock *sk = sock->sk;	if (!sk)		return 0;	if (!sk->dead)		sk->state_change(sk);	sk->dead = 1;	sock->sk = NULL;	atalk_destroy_socket(sk);	return 0;}/* * Pick a source port when one is not given. If we can * find a suitable free one, we insert the socket into * the tables using it. * * This whole operation must be atomic. */static int atalk_pick_and_bind_port(struct sock *sk, struct sockaddr_at *sat){	struct sock *s;	int retval;	spin_lock_bh(&atalk_sockets_lock);	for (sat->sat_port = ATPORT_RESERVED;	     sat->sat_port < ATPORT_LAST;	     sat->sat_port++) {		for (s = atalk_sockets; s; s = s->next) {			if (s->protinfo.af_at.src_net == sat->sat_addr.s_net &&			    s->protinfo.af_at.src_node ==			    	sat->sat_addr.s_node &&			    s->protinfo.af_at.src_port == sat->sat_port)				goto try_next_port;		}		/* Wheee, it's free, assign and insert. */		sk->next = atalk_sockets;		if (sk->next)			atalk_sockets->pprev = &sk->next;		atalk_sockets = sk;		sk->pprev = &atalk_sockets;		sk->protinfo.af_at.src_port = sat->sat_port;		retval = 0;		goto out;	try_next_port:		;	}	retval = -EBUSY;out:	spin_unlock_bh(&atalk_sockets_lock);	return retval;}static int atalk_autobind(struct sock *sk){	struct sockaddr_at sat;	int n;	struct at_addr *ap = atalk_find_primary();	if (!ap || ap->s_net == htons(ATADDR_ANYNET))		return -EADDRNOTAVAIL;	sk->protinfo.af_at.src_net  = sat.sat_addr.s_net  = ap->s_net;	sk->protinfo.af_at.src_node = sat.sat_addr.s_node = ap->s_node;	n = atalk_pick_and_bind_port(sk, &sat);	if (n < 0)		return n;	sk->zapped = 0;	return 0;}/* Set the address 'our end' of the connection */static int atalk_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len){	struct sockaddr_at *addr = (struct sockaddr_at *)uaddr;	struct sock *sk = sock->sk;	if (!sk->zapped || addr_len != sizeof(struct sockaddr_at))		return -EINVAL;	if (addr->sat_family != AF_APPLETALK)		return -EAFNOSUPPORT;	if (addr->sat_addr.s_net == htons(ATADDR_ANYNET)) {		struct at_addr *ap = atalk_find_primary();		if (!ap)			return -EADDRNOTAVAIL;		sk->protinfo.af_at.src_net  = addr->sat_addr.s_net = ap->s_net;		sk->protinfo.af_at.src_node = addr->sat_addr.s_node= ap->s_node;	} else {		if (!atalk_find_interface(addr->sat_addr.s_net,					  addr->sat_addr.s_node))			return -EADDRNOTAVAIL;		sk->protinfo.af_at.src_net  = addr->sat_addr.s_net;		sk->protinfo.af_at.src_node = addr->sat_addr.s_node;	}	if (addr->sat_port == ATADDR_ANYPORT) {		int n = atalk_pick_and_bind_port(sk, addr);		if (n < 0)			return n;	} else {		sk->protinfo.af_at.src_port = addr->sat_port;		if (atalk_find_or_insert_socket(sk, addr))			return -EADDRINUSE;	}	sk->zapped = 0;	return 0;}/* Set the address we talk to */static int atalk_connect(struct socket *sock, struct sockaddr *uaddr,			 int addr_len, int flags){	struct sock *sk = sock->sk;	struct sockaddr_at *addr;	sk->state   = TCP_CLOSE;	sock->state = SS_UNCONNECTED;	if (addr_len != sizeof(*addr))		return -EINVAL;	addr = (struct sockaddr_at *)uaddr;	if (addr->sat_family != AF_APPLETALK)		return -EAFNOSUPPORT;	if (addr->sat_addr.s_node == ATADDR_BCAST && !sk->broadcast) {#if 1			printk(KERN_WARNING "%s is broken and did not set "				    "SO_BROADCAST. It will break when 2.2 is "				    "released.\n",			current->comm);#else		return -EACCES;#endif				}	if (sk->zapped)		if (atalk_autobind(sk) < 0)			return -EBUSY;	if (!atrtr_get_dev(&addr->sat_addr))		return -ENETUNREACH;	sk->protinfo.af_at.dest_port = addr->sat_port;	sk->protinfo.af_at.dest_net  = addr->sat_addr.s_net;	sk->protinfo.af_at.dest_node = addr->sat_addr.s_node;	sock->state = SS_CONNECTED;	sk->state   = TCP_ESTABLISHED;	return 0;}/* * Find the name of an AppleTalk socket. Just copy the right * fields into the sockaddr. */static int atalk_getname(struct socket *sock, struct sockaddr *uaddr,			 int *uaddr_len, int peer){	struct sockaddr_at sat;	struct sock *sk = sock->sk;	if (sk->zapped)		if (atalk_autobind(sk) < 0)			return -ENOBUFS;	*uaddr_len = sizeof(struct sockaddr_at);	if (peer) {		if (sk->state != TCP_ESTABLISHED)			return -ENOTCONN;		sat.sat_addr.s_net  = sk->protinfo.af_at.dest_net;		sat.sat_addr.s_node = sk->protinfo.af_at.dest_node;		sat.sat_port = sk->protinfo.af_at.dest_port;	} else {		sat.sat_addr.s_net  = sk->protinfo.af_at.src_net;		sat.sat_addr.s_node = sk->protinfo.af_at.src_node;		sat.sat_port = sk->protinfo.af_at.src_port;	}	sat.sat_family = AF_APPLETALK;	memcpy(uaddr, &sat, sizeof(sat));	return 0;}/* * Receive a packet (in skb) from device dev. This has come from the SNAP * decoder, and on entry skb->h.raw is the DDP header, skb->len is the DDP * header, skb->len is the DDP length. The physical headers have been * extracted. PPP should probably pass frames marked as for this layer. * [ie ARPHRD_ETHERTALK] */static int atalk_rcv(struct sk_buff *skb, struct net_device *dev,			struct packet_type *pt){	struct ddpehdr *ddp = (void *) skb->h.raw;	struct sock *sock;	struct atalk_iface *atif;	struct sockaddr_at tosat;        int origlen;        struct ddpebits ddphv;	/* Size check */	if (skb->len < sizeof(*ddp))		goto freeit;	/*	 *	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..]	 *	 *	FIXME: This is a write to a shared object. Granted it	 *	happens to be safe BUT.. (Its safe as user space will not	 *	run until we put it back)	 */	*((__u16 *)&ddphv) = ntohs(*((__u16 *)ddp));	/* Trim buffer in case of stray trailing data */	origlen = skb->len;	skb_trim(skb, min_t(unsigned int, skb->len, ddphv.deh_len));	/*	 * Size check to see if ddp->deh_len was crap	 * (Otherwise we'll detonate most spectacularly	 * in the middle of recvmsg()).	 */	if (skb->len < sizeof(*ddp))		goto freeit;	/*	 * Any checksums. Note we don't do htons() on this == is assumed to be	 * valid for net byte orders all over the networking code...	 */	if (ddp->deh_sum &&	    atalk_checksum(ddp, ddphv.deh_len) != ddp->deh_sum)		/* Not a valid AppleTalk frame - dustbin time */		goto freeit;	/* Check the packet is aimed at us */	if (!ddp->deh_dnet)	/* Net 0 is 'this network' */		atif = atalk_find_anynet(ddp->deh_dnode, dev);	else		atif = atalk_find_interface(ddp->deh_dnet, ddp->deh_dnode);	/* Not ours, so we route the packet via the correct AppleTalk iface */	if (!atif) {		struct atalk_route *rt;		struct at_addr ta;		/*		 * Don't route multicast, etc., packets, or packets		 * sent to "this network" 		 */		if (skb->pkt_type != PACKET_HOST || !ddp->deh_dnet) {			/* FIXME:			 * Can it ever happen that a packet is from a PPP			 * iface and needs to be broadcast onto the default			 * network? */			if (dev->type == ARPHRD_PPP)				printk(KERN_DEBUG "AppleTalk: didn't forward "						  "broadcast packet received "						  "from PPP iface\n");			goto freeit;		}		ta.s_net  = ddp->deh_dnet;		ta.s_node = ddp->deh_dnode;		/* Route the packet */		rt = atrtr_find(&ta);		if (!rt || ddphv.deh_hops == DDP_MAXHOPS)			goto freeit;		ddphv.deh_hops++;		/*		 * Route goes through another gateway, so		 * set the target to the gateway instead.		 */		if (rt->flags & RTF_GATEWAY) {			ta.s_net  = rt->gateway.s_net;			ta.s_node = rt->gateway.s_node;		}                /* Fix up skb->len field */                skb_trim(skb, min_t(unsigned int, origlen, rt->dev->hard_header_len +			ddp_dl->header_length + ddphv.deh_len));		/* Mend the byte order */		*((__u16 *)ddp) = ntohs(*((__u16 *)&ddphv));		/*		 * Send the buffer onwards		 *		 * Now we must always be careful. If it's come from 		 * LocalTalk to EtherTalk it might not fit		 *		 * Order matters here: If a packet has to be copied		 * to make a new headroom (rare hopefully) then it		 * won't need unsharing.		 *		 * Note. ddp-> becomes invalid at the realloc.		 */		if (skb_headroom(skb) < 22) {			/* 22 bytes - 12 ether, 2 len, 3 802.2 5 snap */			struct sk_buff *nskb = skb_realloc_headroom(skb, 32);			kfree_skb(skb);			if (!nskb) 				goto out;			skb = nskb;		} else			skb = skb_unshare(skb, GFP_ATOMIC);				/*		 * If the buffer didn't vanish into the lack of		 * space bitbucket we can send it.		 */		if (skb && aarp_send_ddp(rt->dev, skb, &ta, NULL) == -1)			goto freeit;		goto out;	}#if defined(CONFIG_IPDDP) || defined(CONFIG_IPDDP_MODULE)        /* Check if IP-over-DDP */        if (skb->data[12] == 22) {                struct net_device *dev = __dev_get_by_name("ipddp0");		struct net_device_stats *stats;		/* This needs to be able to handle ipddp"N" devices */                if (!dev)                        return -ENODEV;                skb->protocol = htons(ETH_P_IP);                skb_pull(skb, 13);                skb->dev = dev;                skb->h.raw = skb->data;		stats = dev->priv;                stats->rx_packets++;                stats->rx_bytes += skb->len + 13;                netif_rx(skb);  /* Send the SKB up to a higher place. */		goto out;        }#endif	/*	 * Which socket - atalk_search_socket() looks for a *full match*	 * of the <net,node,port> tuple.	 */	tosat.sat_addr.s_net  = ddp->deh_dnet;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -