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

📄 ddp.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
			sum = atalk_sum_partial(vaddr + frag->page_offset +						  offset - start, copy, sum);			kunmap_skb_frag(vaddr);			if (!(len -= copy))				return sum;			offset += copy;		}		start = end;	}	if (skb_shinfo(skb)->frag_list) {		struct sk_buff *list = skb_shinfo(skb)->frag_list;		for (; list; list = list->next) {			int end;			BUG_TRAP(start <= offset + len);			end = start + list->len;			if ((copy = end - offset) > 0) {				if (copy > len)					copy = len;				sum = atalk_sum_skb(list, offset - start,						    copy, sum);				if ((len -= copy) == 0)					return sum;				offset += copy;			}			start = end;		}	}	BUG_ON(len > 0);	return sum;}static __be16 atalk_checksum(const struct sk_buff *skb, int len){	unsigned long sum;	/* skip header 4 bytes */	sum = atalk_sum_skb(skb, 4, len-4, 0);	/* Use 0xFFFF for 0. 0 itself means none */	return sum ? htons((unsigned short)sum) : htons(0xFFFF);}static struct proto ddp_proto = {	.name	  = "DDP",	.owner	  = THIS_MODULE,	.obj_size = sizeof(struct atalk_sock),};/* * Create a socket. Initialise the socket, blank the addresses * set the state. */static int atalk_create(struct net *net, struct socket *sock, int protocol){	struct sock *sk;	int rc = -ESOCKTNOSUPPORT;	if (net != &init_net)		return -EAFNOSUPPORT;	/*	 * 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)	 */	if (sock->type != SOCK_RAW && sock->type != SOCK_DGRAM)		goto out;	rc = -ENOMEM;	sk = sk_alloc(net, PF_APPLETALK, GFP_KERNEL, &ddp_proto);	if (!sk)		goto out;	rc = 0;	sock->ops = &atalk_dgram_ops;	sock_init_data(sock, sk);	/* Checksums on by default */	sock_set_flag(sk, SOCK_ZAPPED);out:	return rc;}/* Free a socket. No work needed */static int atalk_release(struct socket *sock){	struct sock *sk = sock->sk;	if (sk) {		sock_orphan(sk);		sock->sk = NULL;		atalk_destroy_socket(sk);	}	return 0;}/** * atalk_pick_and_bind_port - Pick a source port when one is not given * @sk - socket to insert into the tables * @sat - address to search for * * 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){	int retval;	write_lock_bh(&atalk_sockets_lock);	for (sat->sat_port = ATPORT_RESERVED;	     sat->sat_port < ATPORT_LAST;	     sat->sat_port++) {		struct sock *s;		struct hlist_node *node;		sk_for_each(s, node, &atalk_sockets) {			struct atalk_sock *at = at_sk(s);			if (at->src_net == sat->sat_addr.s_net &&			    at->src_node == sat->sat_addr.s_node &&			    at->src_port == sat->sat_port)				goto try_next_port;		}		/* Wheee, it's free, assign and insert. */		__atalk_insert_socket(sk);		at_sk(sk)->src_port = sat->sat_port;		retval = 0;		goto out;try_next_port:;	}	retval = -EBUSY;out:	write_unlock_bh(&atalk_sockets_lock);	return retval;}static int atalk_autobind(struct sock *sk){	struct atalk_sock *at = at_sk(sk);	struct sockaddr_at sat;	struct atalk_addr *ap = atalk_find_primary();	int n = -EADDRNOTAVAIL;	if (!ap || ap->s_net == htons(ATADDR_ANYNET))		goto out;	at->src_net  = sat.sat_addr.s_net  = ap->s_net;	at->src_node = sat.sat_addr.s_node = ap->s_node;	n = atalk_pick_and_bind_port(sk, &sat);	if (!n)		sock_reset_flag(sk, SOCK_ZAPPED);out:	return n;}/* 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;	struct atalk_sock *at = at_sk(sk);	if (!sock_flag(sk, SOCK_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 atalk_addr *ap = atalk_find_primary();		if (!ap)			return -EADDRNOTAVAIL;		at->src_net  = addr->sat_addr.s_net = ap->s_net;		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;		at->src_net  = addr->sat_addr.s_net;		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 {		at->src_port = addr->sat_port;		if (atalk_find_or_insert_socket(sk, addr))			return -EADDRINUSE;	}	sock_reset_flag(sk, SOCK_ZAPPED);	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 atalk_sock *at = at_sk(sk);	struct sockaddr_at *addr;	sk->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 &&	    !sock_flag(sk, SOCK_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 (sock_flag(sk, SOCK_ZAPPED))		if (atalk_autobind(sk) < 0)			return -EBUSY;	if (!atrtr_get_dev(&addr->sat_addr))		return -ENETUNREACH;	at->dest_port = addr->sat_port;	at->dest_net  = addr->sat_addr.s_net;	at->dest_node = addr->sat_addr.s_node;	sock->state  = SS_CONNECTED;	sk->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;	struct atalk_sock *at = at_sk(sk);	if (sock_flag(sk, SOCK_ZAPPED))		if (atalk_autobind(sk) < 0)			return -ENOBUFS;	*uaddr_len = sizeof(struct sockaddr_at);	if (peer) {		if (sk->sk_state != TCP_ESTABLISHED)			return -ENOTCONN;		sat.sat_addr.s_net  = at->dest_net;		sat.sat_addr.s_node = at->dest_node;		sat.sat_port	    = at->dest_port;	} else {		sat.sat_addr.s_net  = at->src_net;		sat.sat_addr.s_node = at->src_node;		sat.sat_port	    = at->src_port;	}	sat.sat_family = AF_APPLETALK;	memcpy(uaddr, &sat, sizeof(sat));	return 0;}#if defined(CONFIG_IPDDP) || defined(CONFIG_IPDDP_MODULE)static __inline__ int is_ip_over_ddp(struct sk_buff *skb){	return skb->data[12] == 22;}static int handle_ip_over_ddp(struct sk_buff *skb){	struct net_device *dev = __dev_get_by_name(&init_net, "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_reset_transport_header(skb);	stats = dev->priv;	stats->rx_packets++;	stats->rx_bytes += skb->len + 13;	netif_rx(skb);  /* Send the SKB up to a higher place. */	return 0;}#else/* make it easy for gcc to optimize this test out, i.e. kill the code */#define is_ip_over_ddp(skb) 0#define handle_ip_over_ddp(skb) 0#endifstatic void atalk_route_packet(struct sk_buff *skb, struct net_device *dev,			       struct ddpehdr *ddp, __u16 len_hops,			       int origlen){	struct atalk_route *rt;	struct atalk_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 free_it;	}	ta.s_net  = ddp->deh_dnet;	ta.s_node = ddp->deh_dnode;	/* Route the packet */	rt = atrtr_find(&ta);	/* increment hops count */	len_hops += 1 << 10;	if (!rt || !(len_hops & (15 << 10)))		goto free_it;	/* FIXME: use skb->cb to be able to use shared skbs */	/*	 * 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 + (len_hops & 1023))));	/* FIXME: use skb->cb to be able to use shared skbs */	ddp->deh_len_hops = htons(len_hops);	/*	 * 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 free_it;out:	return;free_it:	kfree_skb(skb);}/** *	atalk_rcv - Receive a packet (in skb) from device dev *	@skb - packet received *	@dev - network device where the packet comes from *	@pt - packet type * *	Receive a packet (in skb) from device dev. This has come from the SNAP *	decoder, and on entry skb->transport_header 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 net_device *orig_dev){	struct ddpehdr *ddp;	struct sock *sock;	struct atalk_iface *atif;	struct sockaddr_at tosat;	int origlen;	__u16 len_hops;	if (dev->nd_net != &init_net)		goto freeit;	/* Don't mangle buffer if shared */	if (!(skb = skb_share_check(skb, GFP_ATOMIC)))		goto out;	/* Size check and make sure header is contiguous */	if (!pskb_may_pull(skb, sizeof(*ddp)))		goto freeit;	ddp = ddp_hdr(skb);	len_hops = ntohs(ddp->deh_len_hops);	/* Trim buffer in case of stray trailing data */	origlen = skb->len;	skb_trim(skb, min_t(unsigned int, skb->len, len_hops & 1023));	/*	 * Size check to see if ddp->deh_len was crap	 * (Otherwise we'll detonate most spectacularly	 * in the middle of atalk_checksum() or recvmsg()).	 */	if (skb->len < sizeof(*ddp) || skb->len < (len_hops & 1023)) {		pr_debug("AppleTalk: dropping corrupted frame (deh_len=%u, "			 "skb->len=%u)\n", len_hops & 1023, skb->len);		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(skb, len_hops & 1023) != 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);	if (!atif) {		/* Not ours, so we route the packet via the correct		 * AppleTalk iface		 */		atalk_route_packet(skb, dev, ddp, len_hops, origlen);

⌨️ 快捷键说明

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