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; }
/* * 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; }
/* * 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; }
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); }
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; }
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); }
/* * 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; }
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); }
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; }
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; }
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; }
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); }
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; }
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; }
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; }
/* * 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; }