Loading net/core/neighbour.c +51 −39 Original line number Diff line number Diff line Loading @@ -1506,76 +1506,88 @@ int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { struct ndmsg *ndm = NLMSG_DATA(nlh); struct rtattr **nda = arg; struct ndmsg *ndm; struct nlattr *tb[NDA_MAX+1]; struct neigh_table *tbl; struct net_device *dev = NULL; int err = -ENODEV; int err; if (ndm->ndm_ifindex && (dev = dev_get_by_index(ndm->ndm_ifindex)) == NULL) err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL); if (err < 0) goto out; err = -EINVAL; if (tb[NDA_DST] == NULL) goto out; ndm = nlmsg_data(nlh); if (ndm->ndm_ifindex) { dev = dev_get_by_index(ndm->ndm_ifindex); if (dev == NULL) { err = -ENODEV; goto out; } if (tb[NDA_LLADDR] && nla_len(tb[NDA_LLADDR]) < dev->addr_len) goto out_dev_put; } read_lock(&neigh_tbl_lock); for (tbl = neigh_tables; tbl; tbl = tbl->next) { struct rtattr *lladdr_attr = nda[NDA_LLADDR - 1]; struct rtattr *dst_attr = nda[NDA_DST - 1]; int override = 1; struct neighbour *n; int flags = NEIGH_UPDATE_F_ADMIN | NEIGH_UPDATE_F_OVERRIDE; struct neighbour *neigh; void *dst, *lladdr; if (tbl->family != ndm->ndm_family) continue; read_unlock(&neigh_tbl_lock); err = -EINVAL; if (!dst_attr || RTA_PAYLOAD(dst_attr) < tbl->key_len) if (nla_len(tb[NDA_DST]) < tbl->key_len) goto out_dev_put; dst = nla_data(tb[NDA_DST]); lladdr = tb[NDA_LLADDR] ? nla_data(tb[NDA_LLADDR]) : NULL; if (ndm->ndm_flags & NTF_PROXY) { err = -ENOBUFS; if (pneigh_lookup(tbl, RTA_DATA(dst_attr), dev, 1)) err = 0; if (pneigh_lookup(tbl, dst, dev, 1) == NULL) err = -ENOBUFS; goto out_dev_put; } err = -EINVAL; if (!dev) goto out; if (lladdr_attr && RTA_PAYLOAD(lladdr_attr) < dev->addr_len) if (dev == NULL) goto out_dev_put; n = neigh_lookup(tbl, RTA_DATA(dst_attr), dev); if (n) { if (nlh->nlmsg_flags & NLM_F_EXCL) { err = -EEXIST; neigh_release(n); neigh = neigh_lookup(tbl, dst, dev); if (neigh == NULL) { if (!(nlh->nlmsg_flags & NLM_F_CREATE)) { err = -ENOENT; goto out_dev_put; } override = nlh->nlmsg_flags & NLM_F_REPLACE; } else if (!(nlh->nlmsg_flags & NLM_F_CREATE)) { err = -ENOENT; neigh = __neigh_lookup_errno(tbl, dst, dev); if (IS_ERR(neigh)) { err = PTR_ERR(neigh); goto out_dev_put; } } else { n = __neigh_lookup_errno(tbl, RTA_DATA(dst_attr), dev); if (IS_ERR(n)) { err = PTR_ERR(n); if (nlh->nlmsg_flags & NLM_F_EXCL) { err = -EEXIST; neigh_release(neigh); goto out_dev_put; } } err = neigh_update(n, lladdr_attr ? RTA_DATA(lladdr_attr) : NULL, ndm->ndm_state, (override ? NEIGH_UPDATE_F_OVERRIDE : 0) | NEIGH_UPDATE_F_ADMIN); if (!(nlh->nlmsg_flags & NLM_F_REPLACE)) flags &= ~NEIGH_UPDATE_F_OVERRIDE; } neigh_release(n); err = neigh_update(neigh, lladdr, ndm->ndm_state, flags); neigh_release(neigh); goto out_dev_put; } read_unlock(&neigh_tbl_lock); err = -EADDRNOTAVAIL; err = -EAFNOSUPPORT; out_dev_put: if (dev) dev_put(dev); Loading Loading
net/core/neighbour.c +51 −39 Original line number Diff line number Diff line Loading @@ -1506,76 +1506,88 @@ int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { struct ndmsg *ndm = NLMSG_DATA(nlh); struct rtattr **nda = arg; struct ndmsg *ndm; struct nlattr *tb[NDA_MAX+1]; struct neigh_table *tbl; struct net_device *dev = NULL; int err = -ENODEV; int err; if (ndm->ndm_ifindex && (dev = dev_get_by_index(ndm->ndm_ifindex)) == NULL) err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL); if (err < 0) goto out; err = -EINVAL; if (tb[NDA_DST] == NULL) goto out; ndm = nlmsg_data(nlh); if (ndm->ndm_ifindex) { dev = dev_get_by_index(ndm->ndm_ifindex); if (dev == NULL) { err = -ENODEV; goto out; } if (tb[NDA_LLADDR] && nla_len(tb[NDA_LLADDR]) < dev->addr_len) goto out_dev_put; } read_lock(&neigh_tbl_lock); for (tbl = neigh_tables; tbl; tbl = tbl->next) { struct rtattr *lladdr_attr = nda[NDA_LLADDR - 1]; struct rtattr *dst_attr = nda[NDA_DST - 1]; int override = 1; struct neighbour *n; int flags = NEIGH_UPDATE_F_ADMIN | NEIGH_UPDATE_F_OVERRIDE; struct neighbour *neigh; void *dst, *lladdr; if (tbl->family != ndm->ndm_family) continue; read_unlock(&neigh_tbl_lock); err = -EINVAL; if (!dst_attr || RTA_PAYLOAD(dst_attr) < tbl->key_len) if (nla_len(tb[NDA_DST]) < tbl->key_len) goto out_dev_put; dst = nla_data(tb[NDA_DST]); lladdr = tb[NDA_LLADDR] ? nla_data(tb[NDA_LLADDR]) : NULL; if (ndm->ndm_flags & NTF_PROXY) { err = -ENOBUFS; if (pneigh_lookup(tbl, RTA_DATA(dst_attr), dev, 1)) err = 0; if (pneigh_lookup(tbl, dst, dev, 1) == NULL) err = -ENOBUFS; goto out_dev_put; } err = -EINVAL; if (!dev) goto out; if (lladdr_attr && RTA_PAYLOAD(lladdr_attr) < dev->addr_len) if (dev == NULL) goto out_dev_put; n = neigh_lookup(tbl, RTA_DATA(dst_attr), dev); if (n) { if (nlh->nlmsg_flags & NLM_F_EXCL) { err = -EEXIST; neigh_release(n); neigh = neigh_lookup(tbl, dst, dev); if (neigh == NULL) { if (!(nlh->nlmsg_flags & NLM_F_CREATE)) { err = -ENOENT; goto out_dev_put; } override = nlh->nlmsg_flags & NLM_F_REPLACE; } else if (!(nlh->nlmsg_flags & NLM_F_CREATE)) { err = -ENOENT; neigh = __neigh_lookup_errno(tbl, dst, dev); if (IS_ERR(neigh)) { err = PTR_ERR(neigh); goto out_dev_put; } } else { n = __neigh_lookup_errno(tbl, RTA_DATA(dst_attr), dev); if (IS_ERR(n)) { err = PTR_ERR(n); if (nlh->nlmsg_flags & NLM_F_EXCL) { err = -EEXIST; neigh_release(neigh); goto out_dev_put; } } err = neigh_update(n, lladdr_attr ? RTA_DATA(lladdr_attr) : NULL, ndm->ndm_state, (override ? NEIGH_UPDATE_F_OVERRIDE : 0) | NEIGH_UPDATE_F_ADMIN); if (!(nlh->nlmsg_flags & NLM_F_REPLACE)) flags &= ~NEIGH_UPDATE_F_OVERRIDE; } neigh_release(n); err = neigh_update(neigh, lladdr, ndm->ndm_state, flags); neigh_release(neigh); goto out_dev_put; } read_unlock(&neigh_tbl_lock); err = -EADDRNOTAVAIL; err = -EAFNOSUPPORT; out_dev_put: if (dev) dev_put(dev); Loading