-/* $OpenBSD: if_media.c,v 1.35 2022/07/12 22:27:38 bluhm Exp $ */
+/* $OpenBSD: if_media.c,v 1.36 2022/07/14 13:46:25 bluhm Exp $ */
/* $NetBSD: if_media.c,v 1.10 2000/03/13 23:52:39 soren Exp $ */
/*-
struct mutex ifmedia_mtx = MUTEX_INITIALIZER(IPL_NET);
+struct ifmedia_entry *ifmedia_get(struct ifmedia *, uint64_t, uint64_t);
+
/*
* Initialize if_media struct for a specific interface instance.
*/
{
struct ifmedia_entry *match;
- match = ifmedia_match(ifm, target, ifm->ifm_mask);
+ mtx_enter(&ifmedia_mtx);
+ match = ifmedia_get(ifm, target, ifm->ifm_mask);
/*
* If we didn't find the requested media, then we try to fall
printf("%s: no match for 0x%llx/0x%llx\n", __func__,
target, ~ifm->ifm_mask);
target = (target & IFM_NMASK) | IFM_NONE;
- match = ifmedia_match(ifm, target, ifm->ifm_mask);
+ match = ifmedia_get(ifm, target, ifm->ifm_mask);
if (match == NULL) {
+ mtx_leave(&ifmedia_mtx);
ifmedia_add(ifm, target, 0, NULL);
- match = ifmedia_match(ifm, target, ifm->ifm_mask);
- if (match == NULL)
+ mtx_enter(&ifmedia_mtx);
+ match = ifmedia_get(ifm, target, ifm->ifm_mask);
+ if (match == NULL) {
+ mtx_leave(&ifmedia_mtx);
panic("ifmedia_set failed");
+ }
}
}
ifm->ifm_cur = match;
+ mtx_leave(&ifmedia_mtx);
#ifdef IFMEDIA_DEBUG
if (ifmedia_debug) {
uint64_t oldmedia;
uint64_t newmedia = ifr->ifr_media;
- match = ifmedia_match(ifm, newmedia, ifm->ifm_mask);
+ mtx_enter(&ifmedia_mtx);
+ match = ifmedia_get(ifm, newmedia, ifm->ifm_mask);
if (match == NULL) {
+ mtx_leave(&ifmedia_mtx);
#ifdef IFMEDIA_DEBUG
if (ifmedia_debug) {
printf("%s: no media found for 0x%llx\n",
*/
if ((IFM_SUBTYPE(newmedia) != IFM_AUTO) &&
(newmedia == ifm->ifm_media) &&
- (match == ifm->ifm_cur))
+ (match == ifm->ifm_cur)) {
+ mtx_leave(&ifmedia_mtx);
return (0);
+ }
/*
* We found a match, now make the driver switch to it.
oldmedia = ifm->ifm_media;
ifm->ifm_cur = match;
ifm->ifm_media = newmedia;
+ mtx_leave(&ifmedia_mtx);
+
error = (*ifm->ifm_change_cb)(ifp);
if (error && error != ENETRESET) {
- ifm->ifm_cur = oldentry;
- ifm->ifm_media = oldmedia;
+ mtx_enter(&ifmedia_mtx);
+ if (ifm->ifm_cur == match) {
+ ifm->ifm_cur = oldentry;
+ ifm->ifm_media = oldmedia;
+ }
+ mtx_leave(&ifmedia_mtx);
}
break;
}
if (ifmr->ifm_count < 0)
return (EINVAL);
+ mtx_enter(&ifmedia_mtx);
ifmr->ifm_active = ifmr->ifm_current = ifm->ifm_cur ?
ifm->ifm_cur->ifm_media : IFM_NONE;
ifmr->ifm_mask = ifm->ifm_mask;
ifmr->ifm_status = 0;
+ mtx_leave(&ifmedia_mtx);
+
(*ifm->ifm_status_cb)(ifp, ifmr);
mtx_enter(&ifmedia_mtx);
}
/*
- * Find media entry matching a given ifm word.
+ * Find media entry matching a given ifm word. Return 1 if found.
*/
-struct ifmedia_entry *
+int
ifmedia_match(struct ifmedia *ifm, uint64_t target, uint64_t mask)
+{
+ struct ifmedia_entry *match;
+
+ mtx_enter(&ifmedia_mtx);
+ match = ifmedia_get(ifm, target, mask);
+ mtx_leave(&ifmedia_mtx);
+
+ return (match != NULL);
+}
+
+struct ifmedia_entry *
+ifmedia_get(struct ifmedia *ifm, uint64_t target, uint64_t mask)
{
struct ifmedia_entry *match, *next;
+ MUTEX_ASSERT_LOCKED(&ifmedia_mtx);
+
match = NULL;
mask = ~mask;
- mtx_enter(&ifmedia_mtx);
TAILQ_FOREACH(next, &ifm->ifm_list, ifm_list) {
if ((next->ifm_media & mask) == (target & mask)) {
if (match) {
match = next;
}
}
- mtx_leave(&ifmedia_mtx);
return (match);
}
TAILQ_INSERT_TAIL(&ifmlist, ife, ifm_list);
}
}
+ ifm->ifm_cur = NULL;
mtx_leave(&ifmedia_mtx);
/* Do not hold mutex longer than necessary, call free() without. */
-/* $OpenBSD: if_media.h,v 1.44 2022/07/12 22:08:18 bluhm Exp $ */
+/* $OpenBSD: if_media.h,v 1.45 2022/07/14 13:46:25 bluhm Exp $ */
/* $NetBSD: if_media.h,v 1.22 2000/02/17 21:53:16 sommerfeld Exp $ */
/*-
struct ifmedia {
uint64_t ifm_mask; /* mask of changes we don't care about */
uint64_t ifm_media; /* current user-set media word */
- struct ifmedia_entry *ifm_cur; /* currently selected media */
+ struct ifmedia_entry *ifm_cur; /* [M] currently selected media */
struct ifmedia_list ifm_list; /* [M] list of all supported media */
size_t ifm_nwords; /* [M] number of ifm_list entries */
ifm_change_cb_t ifm_change_cb; /* media change driver callback */
u_long);
/* Locate a media entry */
-struct ifmedia_entry *ifmedia_match(struct ifmedia *, uint64_t, uint64_t);
+int ifmedia_match(struct ifmedia *, uint64_t, uint64_t);
/* Delete all media for a given media instance */
void ifmedia_delete_instance(struct ifmedia *, uint64_t);