int rt6_get_dfltrt(char *buffer, char **start, off_t offset, int length, int dummy)
{
/*
 *      for /proc/net/rt6_default
 */
	int len = 0;
	char buf1[128];
	struct rt6_info *rt;

	if (rt6_dflt_pointer) {
		in6_ntop(&rt6_dflt_pointer->rt6i_gateway, buf1);
		goto out;
	}

	read_lock_bh(&rt6_lock);
	for (rt = ip6_routing_table.leaf; rt; rt = rt->u.next) {
		if (rt->rt6i_flags & RTF_DEFAULT) {
			in6_ntop(&rt->rt6i_gateway, buf1);
			break;
		}
		if (rt->u.next == NULL) {
			strcpy(buf1, "no default router");
			break;
		}
	}
	read_unlock_bh(&rt6_lock);

out:
	len += sprintf(buffer+len, "%s\n", buf1);
	*start = buffer + offset;
	len -= offset;
	if (len > length)
		len = length;
	return len;
}
Example #2
0
/*
 *	check if the interface/address pair is valid
 */
int ipv6_chk_mcast_addr(struct net_device *dev, struct in6_addr *addr)
{
	struct inet6_dev *idev;
	struct ifmcaddr6 *mc;
#ifdef CONFIG_IPV6_MLD6_DEBUG
	char abuf[128];
	in6_ntop(addr, abuf);

	MDBG3((KERN_DEBUG
		"ipv6_chk_mcast_addr(dev=%p(%s), addr=%s)\n",
		dev, dev->name ? dev->name : "<null>", abuf));
#endif

	idev = in6_dev_get(dev);
	if (idev) {
		read_lock_bh(&idev->lock);
		for (mc = idev->mc_list; mc; mc=mc->next) {
			if (ipv6_addr_cmp(&mc->mca_addr, addr) == 0) {
				read_unlock_bh(&idev->lock);
				in6_dev_put(idev);
				return 1;
			}
		}
		read_unlock_bh(&idev->lock);
		in6_dev_put(idev);
	}
	return 0;
}
Example #3
0
/*
 *	socket leave on multicast group
 */
int ipv6_sock_mc_drop(struct sock *sk, int ifindex, struct in6_addr *addr)
{
	struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
	struct ipv6_mc_socklist *mc_lst, **lnk;
#ifdef CONFIG_IPV6_MLD6_DEBUG
	char abuf[128];
	in6_ntop(addr, abuf);

	MDBG3((KERN_DEBUG
		"ipv6_sock_mc_drop(sk=%p, ifindex=%d, addr=%s)\n",
		sk, ifindex, abuf));
#endif

	write_lock_bh(&ipv6_sk_mc_lock);
	for (lnk = &np->ipv6_mc_list; (mc_lst = *lnk) !=NULL ; lnk = &mc_lst->next) {
		if ((ifindex == 0 || mc_lst->ifindex == ifindex) &&
		    ipv6_addr_cmp(&mc_lst->addr, addr) == 0) {
			struct net_device *dev;

			*lnk = mc_lst->next;
			write_unlock_bh(&ipv6_sk_mc_lock);

			/* Note: mc_lst->ifindex != 0 */
			if ((dev = dev_get_by_index(mc_lst->ifindex)) != NULL) {
				ipv6_dev_mc_dec(dev, &mc_lst->addr);
				dev_put(dev);
			}
			sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
			return 0;
		}
	}
	write_unlock_bh(&ipv6_sk_mc_lock);

	return -ENOENT;
}
Example #4
0
static void igmp6_join_group(struct ifmcaddr6 *ma)
{
	unsigned long delay;
#ifdef CONFIG_IPV6_MLD6_DEBUG
	char abuf[128];
	in6_ntop(&ma->mca_addr, abuf);

	MDBG3((KERN_DEBUG
		"igmp6_join_group(ma=%p): mca_addr=%s\n",
		ma, abuf));
#endif

	if (IPV6_ADDR_MC_SCOPE(&ma->mca_addr) < IPV6_ADDR_SCOPE_LINKLOCAL ||
	    ipv6_addr_is_ll_all_nodes(&ma->mca_addr))
		return;

	igmp6_send(&ma->mca_addr, ma->idev->dev, ICMPV6_MGM_REPORT);

	get_random_bytes(&delay, sizeof(delay));
	delay %= IGMP6_UNSOLICITED_IVAL;

	spin_lock_bh(&ma->mca_lock);
	if (del_timer(&ma->mca_timer)) {
		atomic_dec(&ma->mca_refcnt);
		delay = ma->mca_timer.expires - jiffies;
	}

	if (!mod_timer(&ma->mca_timer, jiffies + delay))
		atomic_inc(&ma->mca_refcnt);
	ma->mca_flags |= MAF_TIMER_RUNNING | MAF_LAST_REPORTER;
	spin_unlock_bh(&ma->mca_lock);
}
Example #5
0
static int igmp6_group_dropped(struct ifmcaddr6 *mc)
{
	struct net_device *dev = mc->idev->dev;
	char buf[MAX_ADDR_LEN];
#ifdef CONFIG_IPV6_MLD6_DEBUG
	char abuf[128];
#endif

	spin_lock_bh(&mc->mca_lock);
#ifdef CONFIG_IPV6_MLD6_DEBUG
	in6_ntop(&mc->mca_addr, abuf);
	MDBG3((KERN_DEBUG
		"igmp6_group_dropped(mc=%p): mca_addr=%s, flag=%08x\n", 
		mc, abuf, mc->mca_flags));
#endif
	if (mc->mca_flags&MAF_LOADED) {
		mc->mca_flags &= ~MAF_LOADED;
		if (ndisc_mc_map(&mc->mca_addr, buf, dev, 0) == 0)
			dev_mc_delete(dev, buf, dev->addr_len, 0);
	}
	spin_unlock_bh(&mc->mca_lock);

	if (dev->flags&IFF_UP)
		igmp6_leave_group(mc);
	return 0;
}
Example #6
0
void igmp6_timer_handler(unsigned long data)
{
	struct ifmcaddr6 *ma = (struct ifmcaddr6 *) data;
#ifdef CONFIG_IPV6_MLD6_DEBUG
	char abuf[128];
	in6_ntop(&ma->mca_addr, abuf);

	MDBG3((KERN_DEBUG
		"igmp6_timer_handler(ma=%p): mca_addr=%s\n", 
		ma, abuf));
#endif

	igmp6_send(&ma->mca_addr, ma->idev->dev, ICMPV6_MGM_REPORT);

	spin_lock(&ma->mca_lock);
	ma->mca_flags |=  MAF_LAST_REPORTER;
	ma->mca_flags &= ~MAF_TIMER_RUNNING;
	spin_unlock(&ma->mca_lock);
	ma_put(ma);
}
Example #7
0
/*
 *	device multicast group del
 */
int ipv6_dev_mc_dec(struct net_device *dev, struct in6_addr *addr)
{
	struct inet6_dev *idev;
	struct ifmcaddr6 *ma, **map;

#ifdef CONFIG_IPV6_MLD6_DEBUG
	char abuf[128];
	in6_ntop(addr, abuf);

	MDBG3((KERN_DEBUG
		"ipv6_dev_mc_dec(dev=%p(%s), addr=%s)\n",
		dev, dev->name ? dev->name : "<null>", abuf));
#endif

	idev = in6_dev_get(dev);
	if (idev == NULL)
		return -ENODEV;

	write_lock_bh(&idev->lock);
	for (map = &idev->mc_list; (ma=*map) != NULL; map = &ma->next) {
		if (ipv6_addr_cmp(&ma->mca_addr, addr) == 0) {
			if (--ma->mca_users == 0) {
				*map = ma->next;
				write_unlock_bh(&idev->lock);

				igmp6_group_dropped(ma);

				ma_put(ma);
				in6_dev_put(idev);
				return 0;
			}
			write_unlock_bh(&idev->lock);
			in6_dev_put(idev);
			return 0;
		}
	}
	write_unlock_bh(&idev->lock);
	in6_dev_put(idev);

	return -ENOENT;
}
Example #8
0
static void igmp6_leave_group(struct ifmcaddr6 *ma)
{
#ifdef CONFIG_IPV6_MLD6_DEBUG
	char abuf[128];
	in6_ntop(&ma->mca_addr, abuf);

	MDBG3((KERN_DEBUG
		"igmp6_leave_group(ma=%p): mca_addr=%s\n",
		ma, abuf));
#endif

	if (IPV6_ADDR_MC_SCOPE(&ma->mca_addr) < IPV6_ADDR_SCOPE_LINKLOCAL ||
	    ipv6_addr_is_ll_all_nodes(&ma->mca_addr))
		return;

	if (ma->mca_flags & MAF_LAST_REPORTER)
		igmp6_send(&ma->mca_addr, ma->idev->dev, ICMPV6_MGM_REDUCTION);

	spin_lock_bh(&ma->mca_lock);
	if (del_timer(&ma->mca_timer))
		atomic_dec(&ma->mca_refcnt);
	spin_unlock_bh(&ma->mca_lock);
}
Example #9
0
int inet6_mc_check(struct sock *sk, struct in6_addr *addr)
{
	struct ipv6_mc_socklist *mc;
#ifdef CONFIG_IPV6_MLD6_DEBUG
	char abuf[128];
	in6_ntop(addr, abuf);

	MDBG3((KERN_DEBUG
		"ipv6_sock_mc_check(sk=%p, addr=%s)\n",
		sk, abuf));
#endif

	read_lock(&ipv6_sk_mc_lock);
	for (mc = sk->net_pinfo.af_inet6.ipv6_mc_list; mc; mc=mc->next) {
		if (ipv6_addr_cmp(&mc->addr, addr) == 0) {
			read_unlock(&ipv6_sk_mc_lock);
			return 1;
		}
	}
	read_unlock(&ipv6_sk_mc_lock);

	return 0;
}
Example #10
0
void print_ip6packet(struct ip6_packet_refs refs)
{
	char srcadr[50], dstadr[50], buf[1024], *s;
	int length;

	length = ntohs(refs.ipv6hdr->payload_len) + sizeof(struct ipv6hdr);

	in6_ntop(&refs.ipv6hdr->saddr, srcadr);
	in6_ntop(&refs.ipv6hdr->daddr, dstadr);
	sprintf(buf,"src: %s dest: %s total_length: %u",
		srcadr,dstadr,length);
	IPSEC6_DEBUG("IPv6 header (%s)\n",buf);
	if (refs.rthdr) {
		IPSEC6_DEBUG(" Routing header\n");
	}
	if (refs.destopthdr) {
		IPSEC6_DEBUG(" Destination options header\n");
	}
	if (refs.hopopthdr) {
		IPSEC6_DEBUG(" Hop-by-hop options header\n");
	}
	if (refs.authhdr) {
		sprintf(buf,"nexthdr: %u len: %u, spi: 0x%x seq: 0x%x",
			refs.authhdr->nexthdr,refs.authhdr->hdrlen,
			ntohl(refs.authhdr->spi),ntohl(refs.authhdr->seq_no));
		IPSEC6_DEBUG(" Authentication header (%s)\n",buf);
	}
	switch (refs.resttype) {
		case NEXTHDR_FRAGMENT:
			IPSEC6_DEBUG(" Fragment header\n");
			break;
		case NEXTHDR_ICMP:
			switch (((struct icmp6hdr*)refs.rest)->icmp6_type) {
				case ICMPV6_DEST_UNREACH:
					s = "DEST_UNREACH"; break;
				case ICMPV6_PKT_TOOBIG:
					s = "PKT_TOOBIG"; break;
				case ICMPV6_TIME_EXCEED:
					s = "TIME_EXCEED"; break;
				case ICMPV6_PARAMPROB:
					s = "PARAMPROB"; break;
				case ICMPV6_ECHO_REQUEST:
					s = "ECHO_REQUEST"; break;
				case ICMPV6_ECHO_REPLY:
					s = "ECHO_REPLY"; break;
				case ICMPV6_MGM_QUERY:
					s = "MGM_QUERY"; break;
				case ICMPV6_MGM_REPORT:
					s = "MGM_REPORT"; break;
				case ICMPV6_MGM_REDUCTION:
					s = "MGM_REDUCTION"; break;
				default:
					s = "unknown";
			}
			sprintf(buf,"type: %u (0x%x) - %s",
				((struct icmp6hdr*)refs.rest)->icmp6_type,
				((struct icmp6hdr*)refs.rest)->icmp6_type,s);
			IPSEC6_DEBUG(" ICMP header (%s)\n",buf);
			break;
		case NEXTHDR_UDP/*17*/:
			IPSEC6_DEBUG(" UDP packet\n");
			break;
		case NEXTHDR_TCP/*6*/:
			IPSEC6_DEBUG(" TCP packet\n");
			break;
		case NEXTHDR_ESP:
			sprintf(buf,"spi: %u seq: %u",
				ntohl(((struct ipv6_esp_hdr*)refs.rest)->spi),
				ntohl(((struct ipv6_esp_hdr*)refs.rest)->seq_no));
			IPSEC6_DEBUG(" Encrypted security payload (%s)\n",buf);
			break;
		default:
			IPSEC6_DEBUG(" Unknown header type %u (0x%x)\n",refs.resttype,
				refs.resttype);
	}
}
int ipsec6_input_check(struct sk_buff **skb, __u8 *nexthdr)
{
	int rtn = 0;
	struct inet6_skb_parm *opt = NULL;
	int result = IPSEC_ACTION_BYPASS;
	struct sa_index auth_sa_idx;
	struct sa_index esp_sa_idx;
	struct selector selector;
	struct ipsec_sp *policy = NULL;
	int addr_type = 0;
	struct ipv6hdr *hdr = (*skb)->nh.ipv6h;

	IPSEC6_DEBUG("called\n");
#ifdef CONFIG_IPSEC_DEBUG
	{
		char buf[64];
		IPSEC6_DEBUG("dst addr: %s\n", 
				in6_ntop( &hdr->daddr, buf));
		IPSEC6_DEBUG("src addr: %s\n", 
				in6_ntop( &hdr->saddr, buf));
		IPSEC6_DEBUG("hdr->payload_len is %d\n", ntohs(hdr->payload_len)); 
	}
#endif /* CONFIG_IPSEC_DEBUG */
	/* XXX */
	addr_type = ipv6_addr_type(&hdr->daddr);
	if (addr_type & IPV6_ADDR_MULTICAST) {
		IPSEC6_DEBUG("address type multicast skip!\n");
		goto finish;
	}
	
	if ( *nexthdr == NEXTHDR_UDP ) { /* IKE */
		if (pskb_may_pull(*skb, (*skb)->h.raw - (*skb)->data + sizeof(struct udphdr))) {
			if ((*skb)->h.uh->source == __constant_htons(500)
				 && (*skb)->h.uh->dest == __constant_htons(500)) {
					IPSEC6_DEBUG("received IKE packet. skip!\n");
					goto finish;
			}
		}
	}

	opt = (struct inet6_skb_parm*)((*skb)->cb);

	if (opt->auth) {
		sa_index_init(&auth_sa_idx);
		ipv6_addr_copy(&((struct sockaddr_in6 *)&auth_sa_idx.dst)->sin6_addr,
		       &(*skb)->nh.ipv6h->daddr);
		((struct sockaddr_in6 *)&auth_sa_idx.dst)->sin6_family = AF_INET6;
		auth_sa_idx.prefixlen_d = 128;
		auth_sa_idx.ipsec_proto = SADB_SATYPE_AH;
		auth_sa_idx.spi = ((struct ipv6_auth_hdr*)((*skb)->nh.raw + opt->auth))->spi;
		result |= IPSEC_ACTION_AUTH;
		opt->auth=0;
	}

	if (opt->espspi) {
		sa_index_init(&esp_sa_idx);
		ipv6_addr_copy(&((struct sockaddr_in6 *)&esp_sa_idx.dst)->sin6_addr,
		       &(*skb)->nh.ipv6h->daddr);
		((struct sockaddr_in6 *)&esp_sa_idx.dst)->sin6_family = AF_INET6;
		esp_sa_idx.prefixlen_d = 128;
		esp_sa_idx.ipsec_proto = SADB_SATYPE_ESP;
		esp_sa_idx.spi = opt->espspi;
		result |= IPSEC_ACTION_ESP;
		opt->espspi=0;
	}

	if (result&IPSEC_ACTION_DROP) {
		IPSEC6_DEBUG("result is drop.\n");
		rtn = -EINVAL;
		goto finish;
	}

	/* copy selector XXX port */
	memset(&selector, 0, sizeof(struct selector));
	
	switch(*nexthdr) {

#ifdef CONFIG_IPV6_IPSEC_TUNNEL
	case NEXTHDR_IPV6:
		IPSEC6_DEBUG("nexthdr: ipv6.\n");
		selector.mode = IPSEC_MODE_TUNNEL;
		break;
#endif
	case NEXTHDR_ICMP:
		IPSEC6_DEBUG("nexthdr: icmp.\n");
		selector.proto = IPPROTO_ICMPV6;
		break;

	case NEXTHDR_TCP:
		IPSEC6_DEBUG("nexthdr: tcp.\n");
		selector.proto = IPPROTO_TCP;
		break;

	case NEXTHDR_UDP:
		IPSEC6_DEBUG("nexthdr: udp.\n");
		selector.proto = IPPROTO_UDP;
		break;
	default:
		break;
	}

	IPSEC6_DEBUG("nexthdr = %u\n", *nexthdr);

#ifdef CONFIG_IPV6_IPSEC_TUNNEL
	if (selector.mode == IPSEC_MODE_TUNNEL) {
		struct ipv6hdr *h = NULL;
		if (pskb_may_pull(*skb, (*skb)->h.raw - (*skb)->data + sizeof(struct ipv6hdr))) {
			h = (struct ipv6hdr*) (*skb)->h.raw;

			((struct sockaddr_in6 *)&selector.src)->sin6_family = AF_INET6;
			ipv6_addr_copy(&((struct sockaddr_in6 *)&selector.src)->sin6_addr,
				       &h->saddr);
			((struct sockaddr_in6 *)&selector.dst)->sin6_family = AF_INET6;
			ipv6_addr_copy(&((struct sockaddr_in6 *)&selector.dst)->sin6_addr,
				       &h->daddr);
		} else {
			rtn = -EINVAL;
			goto finish;
		}
	} else {
#endif
		((struct sockaddr_in6 *)&selector.src)->sin6_family = AF_INET6;
		ipv6_addr_copy(&((struct sockaddr_in6 *)&selector.src)->sin6_addr,
			       &(*skb)->nh.ipv6h->saddr);
		((struct sockaddr_in6 *)&selector.dst)->sin6_family = AF_INET6;
		ipv6_addr_copy(&((struct sockaddr_in6 *)&selector.dst)->sin6_addr,
			       &(*skb)->nh.ipv6h->daddr);
#ifdef CONFIG_IPV6_IPSEC_TUNNEL
	}
#endif
	selector.prefixlen_d = 128;
	selector.prefixlen_s = 128;

	/* beggining of matching check selector and policy */
	IPSEC6_DEBUG("start match check SA and policy.\n");

#ifdef CONFIG_IPSEC_DEBUG
	{
		char buf[64];
		IPSEC6_DEBUG("selector dst addr: %s\n", 
			  in6_ntop( &((struct sockaddr_in6 *)&selector.dst)->sin6_addr, buf));
		IPSEC6_DEBUG("selector src addr: %s\n", 
			  in6_ntop( &((struct sockaddr_in6 *)&selector.src)->sin6_addr, buf));
	}
#endif /* CONFIG_IPSEC_DEBUG */
	policy = spd_get(&selector);
		
	if (policy) {

		read_lock_bh(&policy->lock);

		/* non-ipsec packet processing: If this packet doesn't
		 * have any IPSEC headers, then consult policy to see
		 * what to do with packet. If policy says to apply IPSEC,
		 * and there is an SA, then pass packet to netxt layer,
		 * if ther isn't an SA, then drop the packet.
		 */
		if (policy->policy_action == IPSEC_POLICY_DROP) {
			rtn = -EINVAL;
			read_unlock_bh(&policy->lock);
			goto finish;
		}

		if (policy->policy_action == IPSEC_POLICY_BYPASS) {
			rtn = 0;
			read_unlock_bh(&policy->lock);
			goto finish;
		}

		if (policy->policy_action == IPSEC_POLICY_APPLY) {
			if (result&IPSEC_ACTION_AUTH) {
				if (policy->auth_sa_idx) {
					if (sa_index_compare(&auth_sa_idx, policy->auth_sa_idx)) {
						rtn = -EINVAL;
					}
				} else {
					rtn = -EINVAL;
				}
			} else {
				if (policy->auth_sa_idx) rtn = -EINVAL;
			}

			if (result&IPSEC_ACTION_ESP) {
				if (policy->esp_sa_idx) {
					if (sa_index_compare(&esp_sa_idx, policy->esp_sa_idx)) {
						rtn = -EINVAL;
					}
				} else {
					rtn = -EINVAL;
				}
			} else {
				if (policy->esp_sa_idx) rtn = -EINVAL;
			}
		}

		read_unlock_bh(&policy->lock);
		ipsec_sp_put(policy);
	} else {
		if (!result) {
			rtn = 0;
		} else {
			IPSEC6_DEBUG("matching pair of SA and policy not found, through!\n"); 
			rtn = -EINVAL;
			goto finish;		
		}
	}


	IPSEC6_DEBUG("end match check SA and policy.\n");
	/* end of matching check selector and policy */
		

finish:

	return rtn;
}
Example #12
0
int ipv6_sock_mc_join(struct sock *sk, int ifindex, struct in6_addr *addr)
{
	struct net_device *dev = NULL;
	struct ipv6_mc_socklist *mc_lst;
	struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
	int err;
#ifdef CONFIG_IPV6_MLD6_DEBUG
	char abuf[128];
	in6_ntop(addr, abuf);

	MDBG3((KERN_DEBUG
		"ipv6_sock_mc_join(sk=%p, ifindex=%d, addr=%s)\n",
		sk, ifindex, abuf));
#endif

	if (!(ipv6_addr_type(addr) & IPV6_ADDR_MULTICAST))
		return -EINVAL;

	mc_lst = sock_kmalloc(sk, sizeof(struct ipv6_mc_socklist), GFP_KERNEL);

	if (mc_lst == NULL)
		return -ENOMEM;

	mc_lst->next = NULL;
	ipv6_addr_copy(&mc_lst->addr, addr);

	if (ifindex == 0) {
		struct rt6_info *rt;
		rt = rt6_lookup(addr, NULL, 0, 0);
		if (rt) {
			dev = rt->rt6i_dev;
			dev_hold(dev);
			dst_release(&rt->u.dst);
		}
	} else
		dev = dev_get_by_index(ifindex);

	if (dev == NULL) {
		sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
		return -ENODEV;
	}

	mc_lst->ifindex = dev->ifindex;

	/*
	 *	now add/increase the group membership on the device
	 */

	err = ipv6_dev_mc_inc(dev, addr);

	if (err) {
		sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
		dev_put(dev);
		return err;
	}

	write_lock_bh(&ipv6_sk_mc_lock);
	mc_lst->next = np->ipv6_mc_list;
	np->ipv6_mc_list = mc_lst;
	write_unlock_bh(&ipv6_sk_mc_lock);

	dev_put(dev);

	return 0;
}
Example #13
0
void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
{
	struct sock *sk = igmp6_socket->sk;
        struct sk_buff *skb;
	struct inet6_dev *idev;
        struct icmp6hdr *hdr;
	struct in6_addr *snd_addr;
	struct in6_addr *addrp;
	struct in6_addr addr_buf;
	struct in6_addr all_routers;
	int err, len, payload_len, full_len;
	u8 ra[8] = { IPPROTO_ICMPV6, 0,
		     IPV6_TLV_ROUTERALERT, 2, 0, 0,
		     IPV6_TLV_PADN, 0 };
#ifdef CONFIG_IPV6_MLD6_DEBUG
	char abuf[128];
	in6_ntop(addr, abuf);

	MDBG3((KERN_DEBUG
		"igmp6_send(addr=%s, dev=%p(%s), type=%d)\n",
		abuf, dev, dev->name ? dev->name :"<null>", type));
#endif

	snd_addr = addr;
	if (type == ICMPV6_MGM_REDUCTION) {
		snd_addr = &all_routers;
		ipv6_addr_all_routers(&all_routers);
	}

	len = sizeof(struct icmp6hdr) + sizeof(struct in6_addr);
	payload_len = len + sizeof(ra);
	full_len = sizeof(struct ipv6hdr) + payload_len;

	skb = sock_alloc_send_skb(sk, dev->hard_header_len + full_len + 15, 0, &err);

	if (skb == NULL)
		return;

	skb_reserve(skb, (dev->hard_header_len + 15) & ~15);
	if (dev->hard_header) {
		unsigned char ha[MAX_ADDR_LEN];
		ndisc_mc_map(snd_addr, ha, dev, 1);
		if (dev->hard_header(skb, dev, ETH_P_IPV6, ha, NULL, full_len) < 0)
			goto out;
	}

	if (ipv6_get_lladdr(dev, &addr_buf)) {
		MDBG1((KERN_WARNING "igmp6: %s no linklocal address\n",
		       dev->name));
		goto out;
	}

	ip6_nd_hdr(sk, skb, dev, &addr_buf, snd_addr, NEXTHDR_HOP, payload_len);

	memcpy(skb_put(skb, sizeof(ra)), ra, sizeof(ra));

	hdr = (struct icmp6hdr *) skb_put(skb, sizeof(struct icmp6hdr));
	memset(hdr, 0, sizeof(struct icmp6hdr));
	hdr->icmp6_type = type;

	addrp = (struct in6_addr *) skb_put(skb, sizeof(struct in6_addr));
	ipv6_addr_copy(addrp, addr);

	hdr->icmp6_cksum = csum_ipv6_magic(&addr_buf, snd_addr, len,
					   IPPROTO_ICMPV6,
					   csum_partial((__u8 *) hdr, len, 0));

	dev_queue_xmit(skb);
	idev = in6_dev_get(dev);
	if (type == ICMPV6_MGM_REDUCTION)
		ICMP6_INC_STATS(idev,Icmp6OutGroupMembReductions);
	else
		ICMP6_INC_STATS(idev,Icmp6OutGroupMembResponses);
	ICMP6_INC_STATS(idev,Icmp6OutMsgs);
	if (idev)
		in6_dev_put(idev);
	return;

out:
	kfree_skb(skb);
}
Example #14
0
int igmp6_event_report(struct sk_buff *skb)
{
	struct ifmcaddr6 *ma;
	struct in6_addr *addrp;
	struct inet6_dev *idev;
	struct icmp6hdr *hdr;
#ifdef CONFIG_IPV6_MLD6_DEBUG
	char abuf1[128], abuf2[128];
	unsigned long resptime;

	in6_ntop(&skb->nh.ipv6h->saddr, abuf1);
	in6_ntop(&skb->nh.ipv6h->daddr, abuf2);
	MDBG((KERN_DEBUG
		"igmp6_event_report(skb=%p): saddr=%s, daddr=%s\n",
		skb, abuf1, abuf2));
#endif

	/* Our own report looped back. Ignore it. */
	if (skb->pkt_type == PACKET_LOOPBACK)
		return 0;

	if (!pskb_may_pull(skb, sizeof(struct in6_addr)))
		return -EINVAL;

	hdr = (struct icmp6hdr*) skb->h.raw;

	/* Drop reports with not link local source */
	if (!(ipv6_addr_type(&skb->nh.ipv6h->saddr)&IPV6_ADDR_LINKLOCAL))
		return -EINVAL;

#ifdef CONFIG_IPV6_MLD6_DEBUG
	resptime = ntohs(hdr->icmp6_maxdelay);
#endif
	addrp = (struct in6_addr *) (hdr + 1);

#ifdef CONFIG_IPV6_MLD6_DEBUG
	in6_ntop(addrp, abuf1);
	MDBG3((KERN_DEBUG
		"igmp6_event_report(): maxdelay=%lu, addr=%s\n",
		resptime, abuf1));
#endif

	if (!ipv6_addr_is_multicast(addrp))
		goto drop;

	idev = in6_dev_get(skb->dev);
	if (idev == NULL)
		return -ENODEV;

	/*
	 *	Cancel the timer for this group
	 */

	read_lock(&idev->lock);
	for (ma = idev->mc_list; ma; ma=ma->next) {
		if (ipv6_addr_cmp(&ma->mca_addr, addrp) == 0) {
			spin_lock(&ma->mca_lock);
			if (del_timer(&ma->mca_timer))
				atomic_dec(&ma->mca_refcnt);
#ifndef CONFIG_IPV6_MLD6_ALL_DONE
			ma->mca_flags &= ~(MAF_LAST_REPORTER|MAF_TIMER_RUNNING);
#else
			ma->mca_flags &= ~MAF_TIMER_RUNNING;
#endif
			spin_unlock(&ma->mca_lock);
			break;
		}
	}
	read_unlock(&idev->lock);
	in6_dev_put(idev);
  drop:
	return 0;
}
Example #15
0
int igmp6_event_query(struct sk_buff *skb)
{
	struct ifmcaddr6 *ma;
	struct in6_addr *addrp;
	unsigned long resptime;
	struct inet6_dev *idev;
	struct icmp6hdr *hdr;
	int addr_type;
#ifdef CONFIG_IPV6_MLD6_DEBUG
	char abuf1[128], abuf2[128];

	in6_ntop(&skb->nh.ipv6h->saddr, abuf1);
	in6_ntop(&skb->nh.ipv6h->daddr, abuf2);
	MDBG3((KERN_DEBUG
		"igmp6_event_query(skb=%p): saddr=%s, daddr=%s\n",
		skb, abuf1, abuf2));
#endif

	if (!pskb_may_pull(skb, sizeof(struct in6_addr)))
		return -EINVAL;

	hdr = (struct icmp6hdr*) skb->h.raw;

	/* Drop queries with not link local source */
	if (!(ipv6_addr_type(&skb->nh.ipv6h->saddr)&IPV6_ADDR_LINKLOCAL))
 		return -EINVAL;

	resptime = ntohs(hdr->icmp6_maxdelay);
	addrp = (struct in6_addr *) (hdr + 1);

#ifdef CONFIG_IPV6_MLD6_DEBUG
	in6_ntop(addrp, abuf1);
	MDBG3((KERN_DEBUG
		"igmp6_event_query(): maxdelay=%lu, addr=%s\n",
		resptime, abuf1));
#endif

	/* Translate milliseconds to jiffies */
	resptime = (resptime<<10)/(1024000/HZ);

	addr_type = ipv6_addr_type(addrp);

	if (addr_type == IPV6_ADDR_ANY ||
	    (addr_type & IPV6_ADDR_MULTICAST) == 0)
		goto drop;

	idev = in6_dev_get(skb->dev);

	if (idev == NULL)
		return 0;

	read_lock(&idev->lock);
	if (addr_type == IPV6_ADDR_ANY) {
		for (ma = idev->mc_list; ma; ma=ma->next)
			igmp6_group_queried(ma, resptime);
	} else {
		for (ma = idev->mc_list; ma; ma=ma->next) {
			if (ipv6_addr_cmp(addrp, &ma->mca_addr) == 0) {
				igmp6_group_queried(ma, resptime);
				break;
			}
		}
	}
	read_unlock(&idev->lock);
	in6_dev_put(idev);
  drop:
	return 0;
}
Example #16
0
int ipsec6_output_check(struct sock *sk, struct flowi *fl, struct ipsec_sp **policy_ptr)
{
	struct in6_addr *saddr,*daddr;
	u16 sport,dport;
	unsigned char proto;
	struct selector selector;
	int result = IPSEC_ACTION_BYPASS; 	/* default */

	IPSEC6_DEBUG("called\n");
	if (!sk && !fl) {
		printk(KERN_ERR "flowi and sock are NULL\n");
		result = -EINVAL;
		goto err;
	}
	
	if (fl && fl->fl6_src) {
		saddr = fl->fl6_src; 
	} else {
		if (sk) {
			saddr = &sk->net_pinfo.af_inet6.saddr; 
		} else {
			result = -EINVAL;
			printk(KERN_ERR "sock is null\n");
			goto err;
		}
	}

	if (fl && fl->fl6_dst) {
		daddr = fl->fl6_dst; 
	} else {
		if (sk) {
			daddr = &sk->net_pinfo.af_inet6.daddr; 
		} else { 
			result = -EINVAL;
			printk(KERN_ERR "flowi and sock are NULL\n");
			goto err;
		}
	}

	if (fl) { 
		sport=fl->uli_u.ports.sport;
		dport=fl->uli_u.ports.dport;
		proto=fl->proto;
	} else if (sk) {
		sport=sk->sport;
		dport=sk->dport;
		proto=sk->protocol;
	} else {
		result = -EINVAL;
		printk(KERN_ERR "flowi and sock are NULL\n");
		goto err;
	}

	/* for ISKAMP see RFC2408 */
	if (proto == IPPROTO_UDP && 
	    sport == __constant_htons(500) && dport == __constant_htons(500)) {
		result = IPSEC_ACTION_BYPASS; 	/* default */
		goto err;
	}

	/* XXX have to decide to the policy of ICMP messages -mk*/
	if (proto == IPPROTO_ICMPV6) {
#ifdef CONFIG_APPLY_ICMPV6_IPSEC /* XXX currently we can't handle NS-NA -mk */
		sport = 0;
		dport = 0;
#else
		IPSEC6_DEBUG("skip ICMP packet!\n");
		goto err; 
#endif /* CONFIG_APPLY_ICMPV6_IPSEC */
	}

	/* XXX config  port policy */
	memset(&selector, 0, sizeof(struct selector));

	((struct sockaddr_in6 *)&selector.src)->sin6_family = AF_INET6;
	ipv6_addr_copy(&((struct sockaddr_in6 *)&selector.src)->sin6_addr,
		       saddr);
	((struct sockaddr_in6 *)&selector.dst)->sin6_family = AF_INET6;
	ipv6_addr_copy(&((struct sockaddr_in6 *)&selector.dst)->sin6_addr,
		       daddr);
	selector.proto = proto;
	selector.prefixlen_d = 128;
	selector.prefixlen_s = 128;

	((struct sockaddr_in6 *)&selector.src)->sin6_port = sport;	
	((struct sockaddr_in6 *)&selector.dst)->sin6_port = dport;	

#ifdef CONFIG_IPSEC_DEBUG
	{
		char buf[64];
		IPSEC6_DEBUG("original dst addr: %s\n", in6_ntop(daddr, buf));
		IPSEC6_DEBUG("original dst port: %u\n", ntohs(dport));
		IPSEC6_DEBUG("original src addr: %s\n", in6_ntop(saddr, buf));
		IPSEC6_DEBUG("original src port: %u\n", ntohs(sport));

		IPSEC6_DEBUG("selector dst addr: %s\n", 
				in6_ntop( &((struct sockaddr_in6 *)&selector.dst)->sin6_addr, buf));
		IPSEC6_DEBUG("selector dst port: %u\n", 
				ntohs(((struct sockaddr_in6 *)&selector.dst)->sin6_port));
		IPSEC6_DEBUG("selector src addr: %s\n", 
				in6_ntop( &((struct sockaddr_in6 *)&selector.src)->sin6_addr, buf));
		IPSEC6_DEBUG("selector src port: %u\n", 
				ntohs(((struct sockaddr_in6 *)&selector.src)->sin6_port));
		IPSEC6_DEBUG("selector proto: %u\n", selector.proto);
	}
#endif /* CONFIG_IPSEC_DEBUG */

	result = ipsec6_output_check_core(&selector, policy_ptr);

 err:
		return result;
}
Example #17
0
/*
 *	device multicast group inc (add if not found)
 */
int ipv6_dev_mc_inc(struct net_device *dev, struct in6_addr *addr)
{
	struct ifmcaddr6 *mc;
	struct inet6_dev *idev;

#ifdef CONFIG_IPV6_MLD6_DEBUG
	char abuf[128];
	in6_ntop(addr, abuf);

	MDBG3((KERN_DEBUG
		"ipv6_dev_mc_inc(dev=%p(%s), addr=%s)\n",
		dev, dev->name ? dev->name :"<null>", abuf));
#endif

	idev = in6_dev_get(dev);

	if (idev == NULL)
		return -EINVAL;

	write_lock_bh(&idev->lock);
	if (idev->dead) {
		write_unlock_bh(&idev->lock);
		in6_dev_put(idev);
		return -ENODEV;
	}

	for (mc = idev->mc_list; mc; mc = mc->next) {
		if (ipv6_addr_cmp(&mc->mca_addr, addr) == 0) {
			mc->mca_users++;
			write_unlock_bh(&idev->lock);
			in6_dev_put(idev);
			return 0;
		}
	}

	/*
	 *	not found: create a new one.
	 */

	mc = kmalloc(sizeof(struct ifmcaddr6), GFP_ATOMIC);

	if (mc == NULL) {
		write_unlock_bh(&idev->lock);
		in6_dev_put(idev);
		return -ENOMEM;
	}

	memset(mc, 0, sizeof(struct ifmcaddr6));
	mc->mca_timer.function = igmp6_timer_handler;
	mc->mca_timer.data = (unsigned long) mc;

	ipv6_addr_copy(&mc->mca_addr, addr);
	mc->idev = idev;
	mc->mca_users = 1;
	atomic_set(&mc->mca_refcnt, 2);
	mc->mca_lock = SPIN_LOCK_UNLOCKED;

	mc->next = idev->mc_list;
	idev->mc_list = mc;
	write_unlock_bh(&idev->lock);

	igmp6_group_added(mc);
	ma_put(mc);
	return 0;
}