Index: sys/netgraph/ng_ether.c =================================================================== --- sys/netgraph/ng_ether.c +++ sys/netgraph/ng_ether.c @@ -119,6 +119,7 @@ static int ng_ether_mod_event(module_t mod, int event, void *data); static eventhandler_tag ng_ether_ifnet_arrival_cookie; +static eventhandler_tag ng_ether_iflladdr_cookie; /* List of commands and how to convert arguments to/from ASCII */ static const struct ng_cmdlist ng_ether_cmdlist[] = { @@ -431,6 +432,51 @@ log(LOG_WARNING, "%s: can't re-name node %s\n", __func__, name); } +/* + * A handler for underlying interface link layer address changes. + * If the underlying interface link layer address is changed we + * should notify lower and orphan nodes as they may need it + * (for example, ng_pppoe etc.) + */ +static void +ng_ether_iflladdr_event(void *arg __unused, struct ifnet *ifp) +{ + node_p node; + priv_p priv; + hook_p hook; + struct ng_mesg *msg; + int dummy_error, i; + + /* Only ethernet interfaces are of interest. */ + if (ifp->if_type != IFT_ETHER && ifp->if_type != IFT_L2VLAN) + return; + + if ((node = IFP2NG(ifp)) == NULL) + return; + + if ((priv = NG_NODE_PRIVATE(node)) == NULL) + return; + + /* + * Notify peers but avoid double notifications to the same peer: + * first pass notifies peer connected to "lower" hook, if it exists; + * second pass notifies peer connected to "orphan" if it exists + * and is not same as previous one. + */ + for (i = 2, hook = priv->lower; i > 0; --i && (hook = priv->orphan)) + if (hook != NULL && NG_HOOK_IS_VALID(hook) && (i == 2 || + (priv->lower != NULL && NG_NODE_ID(NG_PEER_NODE(hook)) != + NG_NODE_ID(NG_PEER_NODE(priv->lower))))) { + NG_MKMESSAGE(msg, NGM_ETHER_COOKIE, NGM_ETHER_SET_ENADDR, + ETHER_ADDR_LEN, M_NOWAIT); + if (msg == NULL) + return; + + bcopy(IF_LLADDR(ifp), msg->data, ETHER_ADDR_LEN); + NG_SEND_MSG_HOOK(dummy_error, node, msg, hook, 0); + } +} + /****************************************************************** NETGRAPH NODE METHODS ******************************************************************/ @@ -826,6 +872,9 @@ ng_ether_ifnet_arrival_cookie = EVENTHANDLER_REGISTER(ifnet_arrival_event, ng_ether_ifnet_arrival_event, NULL, EVENTHANDLER_PRI_ANY); + ng_ether_iflladdr_cookie = + EVENTHANDLER_REGISTER(iflladdr_event, + ng_ether_iflladdr_event, NULL, EVENTHANDLER_PRI_ANY); break; case MOD_UNLOAD: @@ -840,6 +889,8 @@ EVENTHANDLER_DEREGISTER(ifnet_arrival_event, ng_ether_ifnet_arrival_cookie); + EVENTHANDLER_DEREGISTER(iflladdr_event, + ng_ether_iflladdr_cookie); /* Unregister function hooks */ ng_ether_attach_p = NULL; Index: sys/netgraph/ng_pppoe.c =================================================================== --- sys/netgraph/ng_pppoe.c +++ sys/netgraph/ng_pppoe.c @@ -1024,10 +1024,12 @@ } break; case NGM_ETHER_COOKIE: - if (!(msg->header.flags & NGF_RESP)) - LEAVE(EINVAL); switch (msg->header.cmd) { case NGM_ETHER_GET_ENADDR: + if (!(msg->header.flags & NGF_RESP)) + LEAVE(EINVAL); + /* FALLTHROUGH */ + case NGM_ETHER_SET_ENADDR: if (msg->header.arglen != ETHER_ADDR_LEN) LEAVE(EINVAL); bcopy(msg->data, &privp->eh.ether_shost,