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

📄 ddp.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	int len = 0;	off_t pos = 0;	off_t begin = 0;	len += sprintf(buffer,"Interface	  Address   Networks   Status\n");	spin_lock_bh(&atalk_iface_lock);	for (iface = atalk_iface_list; iface != NULL; iface = iface->next) {		len += sprintf(buffer+len,"%-16s %04X:%02X  %04X-%04X  %d\n",			       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){	struct atalk_route *rt;	int len = 0;	off_t pos = 0;	off_t begin = 0;	len += sprintf(buffer,"Target        Router  Flags Dev\n");	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 != NULL; 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++;	}	if (sum)		return htons((unsigned short) sum);	return 0xFFFF;		/* Use 0xFFFF for 0. 0 itself means none */}/* * 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 = sk_alloc(PF_APPLETALK, GFP_KERNEL, 1);	if (sk == NULL)		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:			/*			 * TO DO: if you want to implement ADSP, here's the place to start			 */			/*			sock->ops = &atalk_stream_ops;			break;			*/		default:			sk_free((void *) 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 == NULL)		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 != NULL; 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. */		if ((sk->next = atalk_sockets) != NULL)			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 at_addr *ap = atalk_find_primary();	struct sockaddr_at sat;	int n;	if (ap == NULL || 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;	if ((n = atalk_pick_and_bind_port(sk, &sat)) < 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 sock *sk;	struct sockaddr_at *addr = (struct sockaddr_at *)uaddr;	sk = sock->sk;	if(sk->zapped == 0)		return -EINVAL;	if(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 == NULL)			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) == NULL)			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) != NULL)			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) == NULL)		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;	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 sock *sock;	struct ddpehdr *ddp = (void *) skb->h.raw;	struct atalk_iface *atif;	struct sockaddr_at tosat;        int origlen;        struct ddpebits ddphv;	/* Size check */	if (skb->len < sizeof(*ddp)) {		kfree_skb(skb);		return 0;	}	/*	 *	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(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)) {		kfree_skb(skb);		return 0;	}	/*	 * 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 */		kfree_skb(skb);		return 0;	}	/* Check the packet is aimed at us */	if (ddp->deh_dnet == 0)	/* 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 interface.	 */	if (atif == NULL) {		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 == 0) {			/*			 * FIX ME:			 * 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");						kfree_skb(skb);			return 0;		}		ta.s_net  = ddp->deh_dnet;		ta.s_node = ddp->deh_dnode;		/* Route the packet */		rt = atrtr_find(&ta);		if (rt == NULL || ddphv.deh_hops == DDP_MAXHOPS) {			kfree_skb(skb);			return 0;		}		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(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)		{			struct sk_buff *newskb;			/* 22 bytes - 12 ether, 2 len, 3 802.2 5 snap */			newskb = skb_realloc_headroom(skb, 32);			kfree_skb(skb);			if (!newskb) 				return 0;			skb = newskb;		}		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) {			if (aarp_send_ddp(rt->dev, skb, &ta, NULL) == -1)				kfree_skb(skb);		}		return 0;	}#if defined(CONFIG_IPDDP) || defined(CONFIG_IPDDP_MODULE)        /*         *      Check if IP-over-DDP         */        if (skb->data[12] == 22) {                struct net_device *dev;		/* This needs to be able to handle ipddp"N" devices */                if ((dev = __dev_get_by_name("ipddp0")) == NULL)                        return -ENODEV;                skb->protocol = htons(ETH_P_IP);                skb_pull(skb, 13);                skb->dev = dev;                skb->h.raw = skb->data;                ((struct net_device_stats *)dev->priv)->rx_packets++;

⌨️ 快捷键说明

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