| 1544 | } |
| 1545 | |
| 1546 | static void |
| 1547 | vlan_unconfig_locked(struct ifnet *ifp, int departing) |
| 1548 | { |
| 1549 | struct ifvlantrunk *trunk; |
| 1550 | struct vlan_mc_entry *mc; |
| 1551 | struct ifvlan *ifv; |
| 1552 | struct ifnet *parent; |
| 1553 | int error; |
| 1554 | |
| 1555 | VLAN_XLOCK_ASSERT(); |
| 1556 | |
| 1557 | ifv = ifp->if_softc; |
| 1558 | trunk = ifv->ifv_trunk; |
| 1559 | parent = NULL; |
| 1560 | |
| 1561 | if (trunk != NULL) { |
| 1562 | parent = trunk->parent; |
| 1563 | |
| 1564 | /* |
| 1565 | * Since the interface is being unconfigured, we need to |
| 1566 | * empty the list of multicast groups that we may have joined |
| 1567 | * while we were alive from the parent's list. |
| 1568 | */ |
| 1569 | while ((mc = CK_SLIST_FIRST(&ifv->vlan_mc_listhead)) != NULL) { |
| 1570 | /* |
| 1571 | * If the parent interface is being detached, |
| 1572 | * all its multicast addresses have already |
| 1573 | * been removed. Warn about errors if |
| 1574 | * if_delmulti() does fail, but don't abort as |
| 1575 | * all callers expect vlan destruction to |
| 1576 | * succeed. |
| 1577 | */ |
| 1578 | if (!departing) { |
| 1579 | error = if_delmulti(parent, |
| 1580 | (struct sockaddr *)&mc->mc_addr); |
| 1581 | if (error) |
| 1582 | if_printf(ifp, |
| 1583 | "Failed to delete multicast address from parent: %d\n", |
| 1584 | error); |
| 1585 | } |
| 1586 | CK_SLIST_REMOVE_HEAD(&ifv->vlan_mc_listhead, mc_entries); |
| 1587 | NET_EPOCH_CALL(vlan_mc_free, &mc->mc_epoch_ctx); |
| 1588 | } |
| 1589 | |
| 1590 | vlan_setflags(ifp, 0); /* clear special flags on parent */ |
| 1591 | |
| 1592 | vlan_remhash(trunk, ifv); |
| 1593 | ifv->ifv_trunk = NULL; |
| 1594 | |
| 1595 | /* |
| 1596 | * Check if we were the last. |
| 1597 | */ |
| 1598 | if (trunk->refcnt == 0) { |
| 1599 | parent->if_vlantrunk = NULL; |
| 1600 | NET_EPOCH_WAIT(); |
| 1601 | trunk_destroy(trunk); |
| 1602 | } |
| 1603 | } |
no test coverage detected