static int ndisc_build_ll_hdr(struct sk_buff *skb, struct device *dev, struct in6_addr *daddr, struct neighbour *neigh, int len) { unsigned char ha[MAX_ADDR_LEN]; unsigned char *h_dest = NULL; skb_reserve(skb, (dev->hard_header_len + 15) & ~15); if (dev->hard_header) { if (ipv6_addr_type(daddr) & IPV6_ADDR_MULTICAST) { ndisc_mc_map(daddr, ha, dev, 1); h_dest = ha; } else if (neigh) { h_dest = neigh->ha; } else { neigh = neigh_lookup(&nd_tbl, daddr, dev); if (neigh) { if (neigh->nud_state&NUD_VALID) { memcpy(ha, neigh->ha, dev->addr_len); h_dest = ha; } neigh_release(neigh); } } if (dev->hard_header(skb, dev, ETH_P_IPV6, h_dest, NULL, len) < 0) return 0; } return 1; }
static int arp_req_delete(struct net *net, struct arpreq *r, struct net_device * dev) { int err; __be32 ip; struct neighbour *neigh; if (r->arp_flags & ATF_PUBL) return arp_req_delete_public(net, r, dev); ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr; if (dev == NULL) { struct flowi fl = { .nl_u = { .ip4_u = { .daddr = ip, .tos = RTO_ONLINK } } }; struct rtable * rt; if ((err = ip_route_output_key(net, &rt, &fl)) != 0) return err; dev = rt->u.dst.dev; ip_rt_put(rt); if (!dev) return -EINVAL; } err = -ENXIO; neigh = neigh_lookup(&arp_tbl, &ip, dev); if (neigh) { if (neigh->nud_state&~NUD_NOARP) err = neigh_update(neigh, NULL, NUD_FAILED, NEIGH_UPDATE_F_OVERRIDE| NEIGH_UPDATE_F_ADMIN); neigh_release(neigh); } return err; }
static void br_do_proxy_arp(struct sk_buff *skb, struct net_bridge *br, u16 vid, struct net_bridge_port *p) { struct net_device *dev = br->dev; struct neighbour *n; struct arphdr *parp; u8 *arpptr, *sha; __be32 sip, tip; BR_INPUT_SKB_CB(skb)->proxyarp_replied = false; if (dev->flags & IFF_NOARP) return; if (!pskb_may_pull(skb, arp_hdr_len(dev))) { dev->stats.tx_dropped++; return; } parp = arp_hdr(skb); if (parp->ar_pro != htons(ETH_P_IP) || parp->ar_op != htons(ARPOP_REQUEST) || parp->ar_hln != dev->addr_len || parp->ar_pln != 4) return; arpptr = (u8 *)parp + sizeof(struct arphdr); sha = arpptr; arpptr += dev->addr_len; /* sha */ memcpy(&sip, arpptr, sizeof(sip)); arpptr += sizeof(sip); arpptr += dev->addr_len; /* tha */ memcpy(&tip, arpptr, sizeof(tip)); if (ipv4_is_loopback(tip) || ipv4_is_multicast(tip)) return; n = neigh_lookup(&arp_tbl, &tip, dev); if (n) { struct net_bridge_fdb_entry *f; if (!(n->nud_state & NUD_VALID)) { neigh_release(n); return; } f = __br_fdb_get(br, n->ha, vid); if (f && ((p->flags & BR_PROXYARP) || (f->dst && (f->dst->flags & BR_PROXYARP_WIFI)))) { arp_send(ARPOP_REPLY, ETH_P_ARP, sip, skb->dev, tip, sha, n->ha, sha); BR_INPUT_SKB_CB(skb)->proxyarp_replied = true; } neigh_release(n); } }
static int arp_req_delete(struct arpreq *r, struct net_device * dev) { int err; u32 ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr; struct neighbour *neigh; if (r->arp_flags & ATF_PUBL) { u32 mask = ((struct sockaddr_in *)&r->arp_netmask)->sin_addr.s_addr; if (mask == 0xFFFFFFFF) return pneigh_delete(&arp_tbl, &ip, dev); if (mask == 0) { if (dev == NULL) { ipv4_devconf.proxy_arp = 0; return 0; } if (__in_dev_get_rtnl(dev)) { __in_dev_get_rtnl(dev)->cnf.proxy_arp = 0; return 0; } return -ENXIO; } return -EINVAL; } if (dev == NULL) { #ifndef __TCS__ struct flowi fl = { .nl_u = { .ip4_u = { .daddr = ip, .tos = RTO_ONLINK } } }; struct rtable * rt; #else struct rtable * rt; struct flowi fl; memset(&fl,0,sizeof(fl)); fl.nl_u.ip4_u.daddr=ip; fl.nl_u.ip4_u.tos=RTO_ONLINK; #endif if ((err = ip_route_output_key(&rt, &fl)) != 0) return err; dev = rt->u.dst.dev; ip_rt_put(rt); if (!dev) return -EINVAL; } err = -ENXIO; neigh = neigh_lookup(&arp_tbl, &ip, dev); if (neigh) { if (neigh->nud_state&~NUD_NOARP) err = neigh_update(neigh, NULL, NUD_FAILED, NEIGH_UPDATE_F_OVERRIDE| NEIGH_UPDATE_F_ADMIN); neigh_release(neigh); } return err; }
/* Get eth_addr for a dst_ip by looking up into the ARP table */ int get_dst_haddr(unsigned char* daddr, u32 dst_ip, struct net_device *dev){ struct neighbour *neigh = neigh_lookup(&arp_tbl, &dst_ip, dev); int err = -ENXIO; if(neigh){ memcpy(daddr, neigh->ha, dev->addr_len); neigh_release(neigh); err = 0; } else{ pr_debug("neigh_lookup failed!\n"); } return err; }
int arp_invalidate(struct net_device *dev, __be32 ip) { struct neighbour *neigh = neigh_lookup(&arp_tbl, &ip, dev); int err = -ENXIO; if (neigh) { if (neigh->nud_state & ~NUD_NOARP) err = neigh_update(neigh, NULL, NUD_FAILED, NEIGH_UPDATE_F_OVERRIDE| NEIGH_UPDATE_F_ADMIN); neigh_release(neigh); } return err; }
static int arp_req_delete(struct arpreq *r, struct net_device * dev) { int err; __be32 ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr; struct neighbour *neigh; if (r->arp_flags & ATF_PUBL) { __be32 mask = ((struct sockaddr_in *)&r->arp_netmask)->sin_addr.s_addr; if (mask == htonl(0xFFFFFFFF)) return pneigh_delete(&arp_tbl, &ip, dev); if (mask == 0) { if (dev == NULL) { IPV4_DEVCONF_ALL(PROXY_ARP) = 0; return 0; } if (__in_dev_get_rtnl(dev)) { IN_DEV_CONF_SET(__in_dev_get_rtnl(dev), PROXY_ARP, 0); return 0; } return -ENXIO; } return -EINVAL; } if (dev == NULL) { struct flowi fl = { .nl_u = { .ip4_u = { .daddr = ip, .tos = RTO_ONLINK } } }; struct rtable * rt; if ((err = ip_route_output_key(&rt, &fl)) != 0) return err; dev = rt->u.dst.dev; ip_rt_put(rt); if (!dev) return -EINVAL; } err = -ENXIO; neigh = neigh_lookup(&arp_tbl, &ip, dev); if (neigh) { if (neigh->nud_state&~NUD_NOARP) err = neigh_update(neigh, NULL, NUD_FAILED, NEIGH_UPDATE_F_OVERRIDE| NEIGH_UPDATE_F_ADMIN); neigh_release(neigh); } return err; }
int arp_req_delete(struct arpreq *r, struct net_device * dev) { int err; u32 ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr; struct neighbour *neigh; if (r->arp_flags & ATF_PUBL) { u32 mask = ((struct sockaddr_in *)&r->arp_netmask)->sin_addr.s_addr; if (mask == 0xFFFFFFFF) return pneigh_delete(&arp_tbl, &ip, dev); if (mask == 0) { if (dev == NULL) { ipv4_devconf.proxy_arp = 0; return 0; } if (__in_dev_get(dev)) { __in_dev_get(dev)->cnf.proxy_arp = 0; return 0; } return -ENXIO; } return -EINVAL; } if (dev == NULL) { struct flowi fl = { .nl_u = { .ip4_u = { .daddr = ip, .tos = RTO_ONLINK } } }; struct rtable * rt; if ((err = ip_route_output_key(&rt, &fl)) != 0) return err; dev = rt->u.dst.dev; ip_rt_put(rt); if (!dev) return -EINVAL; } err = -ENXIO; neigh = neigh_lookup(&arp_tbl, &ip, dev); if (neigh) { if (neigh->nud_state&~NUD_NOARP) err = neigh_update(neigh, NULL, NUD_FAILED, 1, 0); neigh_release(neigh); } return err; }
static int arp_req_get(struct arpreq *r, struct net_device *dev) { __be32 ip = ((struct sockaddr_in *) &r->arp_pa)->sin_addr.s_addr; struct neighbour *neigh; int err = -ENXIO; neigh = neigh_lookup(&arp_tbl, &ip, dev); if (neigh) { read_lock_bh(&neigh->lock); memcpy(r->arp_ha.sa_data, neigh->ha, dev->addr_len); r->arp_flags = arp_state_to_flags(neigh); read_unlock_bh(&neigh->lock); r->arp_ha.sa_family = dev->type; strlcpy(r->arp_dev, dev->name, sizeof(r->arp_dev)); neigh_release(neigh); err = 0; } return err; }
static int arp_invalidate(struct net_device *dev, __be32 ip) { struct neighbour *neigh = neigh_lookup(&arp_tbl, &ip, dev); int err = -ENXIO; struct neigh_table *tbl = &arp_tbl; if (neigh) { if (neigh->nud_state & ~NUD_NOARP) err = neigh_update(neigh, NULL, NUD_FAILED, NEIGH_UPDATE_F_OVERRIDE| NEIGH_UPDATE_F_ADMIN, 0); write_lock_bh(&tbl->lock); neigh_release(neigh); neigh_remove_one(neigh, tbl); write_unlock_bh(&tbl->lock); } return err; }
static void cicp_kernel_resolve(ci_netif* ni, struct cp_fwd_key* key, struct cp_fwd_data* data) { int rc; struct rtable *rt = NULL; cicp_hwport_mask_t rx_hwports = 0; #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,38) /* rhel6 case */ struct flowi fl; memset(&fl, 0, sizeof(fl)); fl.fl4_dst = key->dst; fl.fl4_src = key->src; fl.fl4_tos = key->tos; fl.oif = key->ifindex; rc = ip_route_output_key(ni->cplane->cp_netns, &rt, &fl); if( rc < 0 ) { data->ifindex = CI_IFID_BAD; return; } data->src = fl.fl4_src; #define DST_DEV(rt) rt->u.dst.dev #else /* linux-2.6.39 and newer */ struct flowi4 fl4; memset(&fl4, 0, sizeof(fl4)); fl4.daddr = key->dst; fl4.saddr = key->src; fl4.flowi4_tos = key->tos; fl4.flowi4_oif = key->ifindex; #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0) fl4.flowi4_uid = make_kuid(current_user_ns(), ni->state->uuid); #endif rt = ip_route_output_key(ni->cplane->cp_netns, &fl4); if( IS_ERR(rt) ) { data->ifindex = CI_IFID_BAD; return; } data->src = fl4.saddr; #define DST_DEV(rt) rt->dst.dev #endif /* 2.6.39 */ data->ifindex = DST_DEV(rt)->ifindex; data->next_hop = rt->rt_gateway; if( data->next_hop == 0 ) data->next_hop = key->dst; #if LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0) data->mtu = 0; /* We'll use interface MTU and ignore the route MTU even if it has one * for the older kernels. This code is mostly used for SYN-ACK replies, * so MTU value is not too important. */ #else data->mtu = rt->rt_pmtu; #endif data->arp_valid = 0; if( data->ifindex != 1 ) { /* In theory the rt->dst structure has a reference to the neigh, * but in practice it is not easy to dig the neigh out. */ struct neighbour *neigh = neigh_lookup(&arp_tbl, &rt->rt_gateway, DST_DEV(rt)); if( neigh != NULL && (neigh->nud_state & NUD_VALID) ) { data->arp_valid = 1; memcpy(data->dst_mac, neigh->ha, ETH_ALEN); } if( neigh != NULL ) neigh_release(neigh); } ip_rt_put(rt); if( data->ifindex == CI_IFID_LOOP ) return; /* We've got the route. Let's look into llap table to find out the * network interface details. */ rc = oo_cp_find_llap(ni->cplane, data->ifindex, data->mtu == 0 ? &data->mtu : NULL, &data->hwports, &rx_hwports, &data->src_mac, &data->encap); if( rc < 0 || rx_hwports == 0 ) data->ifindex = CI_IFID_BAD; }