* Process a state change from the upper layer for the given IPv6 group. * * Each socket holds a reference on the in_multi in its own ip_moptions. * The socket layer will have made the necessary updates to.the group * state, it is now up to MLD to issue a state change report if there * has been any change between T0 (when the last state-change was issued) * and T1 (now). * * We use the MLDv
| 1893 | * is called from the socket option handlers. |
| 1894 | */ |
| 1895 | int |
| 1896 | mld_change_state(struct in6_multi *inm, const int delay) |
| 1897 | { |
| 1898 | struct mld_ifsoftc *mli; |
| 1899 | struct ifnet *ifp; |
| 1900 | int error; |
| 1901 | |
| 1902 | IN6_MULTI_LIST_LOCK_ASSERT(); |
| 1903 | |
| 1904 | error = 0; |
| 1905 | |
| 1906 | /* |
| 1907 | * Check if the in6_multi has already been disconnected. |
| 1908 | */ |
| 1909 | if (inm->in6m_ifp == NULL) { |
| 1910 | CTR1(KTR_MLD, "%s: inm is disconnected", __func__); |
| 1911 | return (0); |
| 1912 | } |
| 1913 | |
| 1914 | /* |
| 1915 | * Try to detect if the upper layer just asked us to change state |
| 1916 | * for an interface which has now gone away. |
| 1917 | */ |
| 1918 | KASSERT(inm->in6m_ifma != NULL, ("%s: no ifma", __func__)); |
| 1919 | ifp = inm->in6m_ifma->ifma_ifp; |
| 1920 | if (ifp == NULL) |
| 1921 | return (0); |
| 1922 | /* |
| 1923 | * Sanity check that netinet6's notion of ifp is the |
| 1924 | * same as net's. |
| 1925 | */ |
| 1926 | KASSERT(inm->in6m_ifp == ifp, ("%s: bad ifp", __func__)); |
| 1927 | |
| 1928 | MLD_LOCK(); |
| 1929 | mli = MLD_IFINFO(ifp); |
| 1930 | KASSERT(mli != NULL, ("%s: no mld_ifsoftc for ifp %p", __func__, ifp)); |
| 1931 | |
| 1932 | /* |
| 1933 | * If we detect a state transition to or from MCAST_UNDEFINED |
| 1934 | * for this group, then we are starting or finishing an MLD |
| 1935 | * life cycle for this group. |
| 1936 | */ |
| 1937 | if (inm->in6m_st[1].iss_fmode != inm->in6m_st[0].iss_fmode) { |
| 1938 | CTR3(KTR_MLD, "%s: inm transition %d -> %d", __func__, |
| 1939 | inm->in6m_st[0].iss_fmode, inm->in6m_st[1].iss_fmode); |
| 1940 | if (inm->in6m_st[0].iss_fmode == MCAST_UNDEFINED) { |
| 1941 | CTR1(KTR_MLD, "%s: initial join", __func__); |
| 1942 | error = mld_initial_join(inm, mli, delay); |
| 1943 | goto out_locked; |
| 1944 | } else if (inm->in6m_st[1].iss_fmode == MCAST_UNDEFINED) { |
| 1945 | CTR1(KTR_MLD, "%s: final leave", __func__); |
| 1946 | mld_final_leave(inm, mli); |
| 1947 | goto out_locked; |
| 1948 | } |
| 1949 | } else { |
| 1950 | CTR1(KTR_MLD, "%s: filter set change", __func__); |
| 1951 | } |
| 1952 |
no test coverage detected