Index: sys/net/if_llatbl.h =================================================================== --- sys/net/if_llatbl.h +++ sys/net/if_llatbl.h @@ -202,6 +202,8 @@ #define LLE_PUB 0x0020 /* publish entry ??? */ #define LLE_LINKED 0x0040 /* linked to lookup structure */ #define LLE_CHILD 0x0080 /* Child LLE storing different AF encap */ +#define LLE_REJECT 0x0100 /* Reject traffic towards the entry */ +#define LLE_DISCARD 0x0200 /* Discard traffic towards the entry */ /* LLE request flags */ #define LLE_EXCLUSIVE 0x2000 /* return lle xlocked */ #define LLE_UNLOCKED 0x4000 /* return lle unlocked */ Index: sys/net/if_llatbl.c =================================================================== --- sys/net/if_llatbl.c +++ sys/net/if_llatbl.c @@ -794,6 +794,23 @@ return (llt->llt_af); } +static bool +fill_lladdr(struct ifnet *ifp, int family, struct llentry *lle, char *lladdr) +{ + uint8_t linkhdr[LLE_MAX_LINKHDR]; + size_t linkhdrsize; + int lladdr_off; + + linkhdrsize = sizeof(linkhdr); + if (lltable_calc_llheader(ifp, family, lladdr, linkhdr, &linkhdrsize, + &lladdr_off) != 0) + return (false); + + lltable_set_entry_addr(ifp, lle, linkhdr, linkhdrsize, lladdr_off); + + return (true); +} + /* * Called in route_output when rtm_flags contains RTF_LLDATA. */ @@ -806,10 +823,8 @@ struct ifnet *ifp; struct lltable *llt; struct llentry *lle, *lle_tmp; - uint8_t linkhdr[LLE_MAX_LINKHDR]; - size_t linkhdrsize; - int lladdr_off; u_int laflags = 0; + bool discard; int error; if (dl == NULL || dl->sdl_family != AF_LINK) @@ -840,18 +855,25 @@ case RTM_ADD: /* Add static LLE */ laflags = 0; - if (rtm->rtm_rmx.rmx_expire == 0) + discard = rtm->rtm_flags & (RTF_BLACKHOLE|RTF_REJECT); + if ((rtm->rtm_rmx.rmx_expire == 0) && !discard) laflags = LLE_STATIC; lle = lltable_alloc_entry(llt, laflags, dst); if (lle == NULL) return (ENOMEM); - linkhdrsize = sizeof(linkhdr); - if (lltable_calc_llheader(ifp, dst->sa_family, LLADDR(dl), - linkhdr, &linkhdrsize, &lladdr_off) != 0) - return (EINVAL); - lltable_set_entry_addr(ifp, lle, linkhdr, linkhdrsize, - lladdr_off); + if (!discard) { + if (!fill_lladdr(ifp, dst->sa_family, lle, LLADDR(dl))) + return (EINVAL); + } else { + if (rtm->rtm_flags & RTF_REJECT) + lle->la_flags |= LLE_REJECT; + else + lle->la_flags |= LLE_DISCARD; + if (rtm->rtm_rmx.rmx_expire == 0) + lle->la_flags |= LLE_STATIC; + } + if ((rtm->rtm_flags & RTF_ANNOUNCE)) lle->la_flags |= LLE_PUB; lle->la_expire = rtm->rtm_rmx.rmx_expire; Index: sys/netinet/if_ether.c =================================================================== --- sys/netinet/if_ether.c +++ sys/netinet/if_ether.c @@ -533,6 +533,12 @@ return (0); } + if (la->la_flags & (LLE_REJECT|LLE_DISCARD)) { + LLE_WUNLOCK(la); + m_freem(m); + return ((la->la_flags & LLE_REJECT) ? EHOSTUNREACH : EWOULDBLOCK); + } + renew = (la->la_asked == 0 || la->la_expire != time_uptime); /* * There is an arptab entry, but no ethernet address Index: sys/netinet/in.c =================================================================== --- sys/netinet/in.c +++ sys/netinet/in.c @@ -1637,6 +1637,10 @@ /* publish */ if (lle->la_flags & LLE_PUB) arpc.rtm.rtm_flags |= RTF_ANNOUNCE; + if (lle->la_flags & LLE_REJECT) + arpc.rtm.rtm_flags |= RTF_REJECT; + if (lle->la_flags & LLE_DISCARD) + arpc.rtm.rtm_flags |= RTF_BLACKHOLE; sdl = &arpc.sdl; sdl->sdl_family = AF_LINK; Index: usr.sbin/arp/arp.c =================================================================== --- usr.sbin/arp/arp.c +++ usr.sbin/arp/arp.c @@ -650,6 +650,10 @@ if (rtm->rtm_flags & RTF_ANNOUNCE) xo_emit("{d:/ published}{en:published/true}"); + if (rtm->rtm_flags & RTF_REJECT) + xo_emit("{d:/ rejected}{en:rejected/true}"); + if (rtm->rtm_flags & RTF_BLACKHOLE) + xo_emit("{d:/ discarded}{en:discarded/true}"); switch(sdl->sdl_type) { case IFT_ETHER: