* Destroy a clone network interface. */
| 301 | * Destroy a clone network interface. |
| 302 | */ |
| 303 | int |
| 304 | if_clone_destroyif(struct if_clone *ifc, struct ifnet *ifp) |
| 305 | { |
| 306 | int err; |
| 307 | struct ifnet *ifcifp; |
| 308 | |
| 309 | if (ifc->ifc_type == ADVANCED && ifc->ifc_destroy == NULL) |
| 310 | return(EOPNOTSUPP); |
| 311 | |
| 312 | /* |
| 313 | * Given that the cloned ifnet might be attached to a different |
| 314 | * vnet from where its cloner was registered, we have to |
| 315 | * switch to the vnet context of the target vnet. |
| 316 | */ |
| 317 | CURVNET_SET_QUIET(ifp->if_vnet); |
| 318 | |
| 319 | IF_CLONE_LOCK(ifc); |
| 320 | LIST_FOREACH(ifcifp, &ifc->ifc_iflist, if_clones) { |
| 321 | if (ifcifp == ifp) { |
| 322 | IFC_IFLIST_REMOVE(ifc, ifp); |
| 323 | break; |
| 324 | } |
| 325 | } |
| 326 | IF_CLONE_UNLOCK(ifc); |
| 327 | if (ifcifp == NULL) { |
| 328 | CURVNET_RESTORE(); |
| 329 | return (ENXIO); /* ifp is not on the list. */ |
| 330 | } |
| 331 | if ((ifc->ifc_flags & IFC_NOGROUP) == 0) |
| 332 | if_delgroup(ifp, ifc->ifc_name); |
| 333 | |
| 334 | if (ifc->ifc_type == SIMPLE) |
| 335 | err = ifc_simple_destroy(ifc, ifp); |
| 336 | else |
| 337 | err = (*ifc->ifc_destroy)(ifc, ifp); |
| 338 | |
| 339 | if (err != 0) { |
| 340 | if ((ifc->ifc_flags & IFC_NOGROUP) == 0) |
| 341 | if_addgroup(ifp, ifc->ifc_name); |
| 342 | |
| 343 | IF_CLONE_LOCK(ifc); |
| 344 | IFC_IFLIST_INSERT(ifc, ifp); |
| 345 | IF_CLONE_UNLOCK(ifc); |
| 346 | } |
| 347 | CURVNET_RESTORE(); |
| 348 | return (err); |
| 349 | } |
| 350 | |
| 351 | static struct if_clone * |
| 352 | if_clone_alloc(const char *name, int maxunit) |
no test coverage detected