📄 in6.c
字号:
ifra.ifra_flags = ia->ia6_flags;#if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3) return in6_control(so, SIOCDIFADDR_IN6, (caddr_t)&ifra, ifp, p);#else return in6_control(so, SIOCDIFADDR_IN6, (caddr_t)&ifra, ifp);#endif } } } return EOPNOTSUPP; /* just for safety */}/* * Initialize an interface's intetnet6 address * and routing table entry. */static intin6_ifinit(ifp, ia, sin6, newhost) struct ifnet *ifp; struct in6_ifaddr *ia; struct sockaddr_in6 *sin6; int newhost;{ int error = 0, plen, ifacount = 0; int s = splimp(); struct ifaddr *ifa; /* * Give the interface a chance to initialize * if this is its first address, * and to validate the address if necessary. */#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3) for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)#elif defined(__FreeBSD__) && __FreeBSD__ >= 4 TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)#else for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next)#endif { if (ifa->ifa_addr == NULL) continue; /* just for safety */ if (ifa->ifa_addr->sa_family != AF_INET6) continue; ifacount++; } ia->ia_addr = *sin6; if (ifacount <= 1 && ifp->if_ioctl && (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia))) { splx(s); return(error); } splx(s); ia->ia_ifa.ifa_metric = ifp->if_metric; /* we could do in(6)_socktrim here, but just omit it at this moment. */ /* * Special case: * If the destination address is specified for a point-to-point * interface, install a route to the destination as an interface * direct route. */ plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */ if (plen == 128 && ia->ia_dstaddr.sin6_family == AF_INET6) { if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_UP | RTF_HOST)) != 0) return(error); ia->ia_flags |= IFA_ROUTE; } if (plen < 128) { /* * The RTF_CLONING flag is necessary for in6_is_ifloop_auto(). */ ia->ia_ifa.ifa_flags |= RTF_CLONING; } /* Add ownaddr as loopback rtentry, if necessary (ex. on p2p link). */ if (newhost) { /* set the rtrequest function to create llinfo */ ia->ia_ifa.ifa_rtrequest = nd6_rtrequest; in6_ifaddloop(&(ia->ia_ifa)); }#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) if (ifp->if_flags & IFF_MULTICAST) in6_restoremkludge(ia, ifp);#endif return(error);}#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)/* * Multicast address kludge: * If there were any multicast addresses attached to this interface address, * either move them to another address on this interface, or save them until * such time as this interface is reconfigured for IPv6. */voidin6_savemkludge(oia) struct in6_ifaddr *oia;{ struct in6_ifaddr *ia; struct in6_multi *in6m, *next; IFP_TO_IA6(oia->ia_ifp, ia); if (ia) { /* there is another address */ for (in6m = oia->ia6_multiaddrs.lh_first; in6m; in6m = next){ next = in6m->in6m_entry.le_next; IFAFREE(&in6m->in6m_ia->ia_ifa); IFAREF(&ia->ia_ifa); in6m->in6m_ia = ia; LIST_INSERT_HEAD(&ia->ia6_multiaddrs, in6m, in6m_entry); } } else { /* last address on this if deleted, save */ struct multi6_kludge *mk; for (mk = in6_mk.lh_first; mk; mk = mk->mk_entry.le_next) { if (mk->mk_ifp == oia->ia_ifp) break; } if (mk == NULL) /* this should not happen! */ panic("in6_savemkludge: no kludge space"); for (in6m = oia->ia6_multiaddrs.lh_first; in6m; in6m = next){ next = in6m->in6m_entry.le_next; IFAFREE(&in6m->in6m_ia->ia_ifa); /* release reference */ in6m->in6m_ia = NULL; LIST_INSERT_HEAD(&mk->mk_head, in6m, in6m_entry); } }}/* * Continuation of multicast address hack: * If there was a multicast group list previously saved for this interface, * then we re-attach it to the first address configured on the i/f. */voidin6_restoremkludge(ia, ifp) struct in6_ifaddr *ia; struct ifnet *ifp;{ struct multi6_kludge *mk; for (mk = in6_mk.lh_first; mk; mk = mk->mk_entry.le_next) { if (mk->mk_ifp == ifp) { struct in6_multi *in6m, *next; for (in6m = mk->mk_head.lh_first; in6m; in6m = next) { next = in6m->in6m_entry.le_next; in6m->in6m_ia = ia; IFAREF(&ia->ia_ifa); LIST_INSERT_HEAD(&ia->ia6_multiaddrs, in6m, in6m_entry); } LIST_INIT(&mk->mk_head); break; } }}/* * Allocate space for the kludge at interface initialization time. * Formerly, we dynamically allocated the space in in6_savemkludge() with * malloc(M_WAITOK). However, it was wrong since the function could be called * under an interrupt context (software timer on address lifetime expiration). * Also, we cannot just give up allocating the strucutre, since the group * membership structure is very complex and we need to keep it anyway. * Of course, this function MUST NOT be called under an interrupt context. * Specifically, it is expected to be called only from in6_ifattach(), though * it is a global function. */voidin6_createmkludge(ifp) struct ifnet *ifp;{ struct multi6_kludge *mk; for (mk = in6_mk.lh_first; mk; mk = mk->mk_entry.le_next) { /* If we've already had one, do not allocate. */ if (mk->mk_ifp == ifp) return; } mk = malloc(sizeof(*mk), M_IPMADDR, M_WAITOK); bzero(mk, sizeof(*mk)); LIST_INIT(&mk->mk_head); mk->mk_ifp = ifp; LIST_INSERT_HEAD(&in6_mk, mk, mk_entry);}voidin6_purgemkludge(ifp) struct ifnet *ifp;{ struct multi6_kludge *mk; struct in6_multi *in6m; for (mk = in6_mk.lh_first; mk; mk = mk->mk_entry.le_next) { if (mk->mk_ifp != ifp) continue; /* leave from all multicast groups joined */ while ((in6m = LIST_FIRST(&mk->mk_head)) != NULL) in6_delmulti(in6m); LIST_REMOVE(mk, mk_entry); free(mk, M_IPMADDR); break; }}/* * Add an address to the list of IP6 multicast addresses for a * given interface. */struct in6_multi *in6_addmulti(maddr6, ifp, errorp) struct in6_addr *maddr6; struct ifnet *ifp; int *errorp;{ struct in6_ifaddr *ia; struct in6_ifreq ifr; struct in6_multi *in6m;#ifdef __NetBSD__ int s = splsoftnet();#else int s = splnet();#endif *errorp = 0; /* * See if address already in list. */ IN6_LOOKUP_MULTI(*maddr6, ifp, in6m); if (in6m != NULL) { /* * Found it; just increment the refrence count. */ in6m->in6m_refcount++; } else { /* * New address; allocate a new multicast record * and link it into the interface's multicast list. */ in6m = (struct in6_multi *) malloc(sizeof(*in6m), M_IPMADDR, M_NOWAIT); if (in6m == NULL) { splx(s); *errorp = ENOBUFS; return(NULL); } in6m->in6m_addr = *maddr6; in6m->in6m_ifp = ifp; in6m->in6m_refcount = 1; IFP_TO_IA6(ifp, ia); if (ia == NULL) { free(in6m, M_IPMADDR); splx(s); *errorp = EADDRNOTAVAIL; /* appropriate? */ return(NULL); } in6m->in6m_ia = ia; IFAREF(&ia->ia_ifa); /* gain a reference */ LIST_INSERT_HEAD(&ia->ia6_multiaddrs, in6m, in6m_entry); /* * Ask the network driver to update its multicast reception * filter appropriately for the new address. */ bzero(&ifr.ifr_addr, sizeof(struct sockaddr_in6)); ifr.ifr_addr.sin6_len = sizeof(struct sockaddr_in6); ifr.ifr_addr.sin6_family = AF_INET6; ifr.ifr_addr.sin6_addr = *maddr6; if (ifp->if_ioctl == NULL) *errorp = ENXIO; /* XXX: appropriate? */ else *errorp = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, (caddr_t)&ifr); if (*errorp) { LIST_REMOVE(in6m, in6m_entry); free(in6m, M_IPMADDR); IFAFREE(&ia->ia_ifa); splx(s); return(NULL); } /* * Let MLD6 know that we have joined a new IP6 multicast * group. */ mld6_start_listening(in6m); } splx(s); return(in6m);}/* * Delete a multicast address record. */voidin6_delmulti(in6m) struct in6_multi *in6m;{ struct in6_ifreq ifr;#ifdef __NetBSD__ int s = splsoftnet();#else int s = splnet();#endif if (--in6m->in6m_refcount == 0) { /* * No remaining claims to this record; let MLD6 know * that we are leaving the multicast group. */ mld6_stop_listening(in6m); /* * Unlink from list. */ LIST_REMOVE(in6m, in6m_entry); if (in6m->in6m_ia) { IFAFREE(&in6m->in6m_ia->ia_ifa); /* release reference */ } /* * Notify the network driver to update its multicast * reception filter. */ bzero(&ifr.ifr_addr, sizeof(struct sockaddr_in6)); ifr.ifr_addr.sin6_len = sizeof(struct sockaddr_in6); ifr.ifr_addr.sin6_family = AF_INET6; ifr.ifr_addr.sin6_addr = in6m->in6m_addr; (*in6m->in6m_ifp->if_ioctl)(in6m->in6m_ifp, SIOCDELMULTI, (caddr_t)&ifr); free(in6m, M_IPMADDR); } splx(s);}#else /* not FreeBSD3 *//* * Add an address to the list of IP6 multicast addresses for a * given interface. */struct in6_multi *in6_addmulti(maddr6, ifp, errorp) struct in6_addr *maddr6; struct ifnet *ifp; int *errorp;{ struct in6_multi *in6m; struct sockaddr_in6 sin6; struct ifmultiaddr *ifma; int s = splnet(); *errorp = 0; /* * Call generic routine to add membership or increment * refcount. It wants addresses in the form of a sockaddr, * so we build one here (being careful to zero the unused bytes). */ bzero(&sin6, sizeof sin6); sin6.sin6_family = AF_INET6; sin6.sin6_len = sizeof sin6; sin6.sin6_addr = *maddr6; *errorp = if_addmulti(ifp, (struct sockaddr *)&sin6, &ifma); if (*errorp) { splx(s); return 0; } /* * If ifma->ifma_protospec is null, then if_addmulti() created * a new record. Otherwise, we are done. */ if (ifma->ifma_protospec != 0) return ifma->ifma_protospec; /* XXX - if_addmulti uses M_WAITOK. Can this really be called at interrupt time? If so, need to fix if_addmulti. XXX */ in6m = (struct in6_multi *)malloc(sizeof(*in6m), M_IPMADDR, M_NOWAIT); if (in6m == NULL) { splx(s); return (NULL); } bzero(in6m, sizeof *in6m); in6m->in6m_addr = *maddr6; in6m->in6m_ifp = ifp; in6m->in6m_ifma = ifma; ifma->ifma_protospec = in6m; LIST_INSERT_HEAD(&in6_multihead, in6m, in6m_entry); /* * Let MLD6 know that we have joined a new IP6 multicast * group. */ mld6_start_listening(in6m); splx(s); return(in6m);}/* * Delete a multicast address record. */voidin6_delmulti(in6m) struct in6_multi *in6m;{ struct ifmultiaddr *ifma = in6m->in6m_ifma; int s = splnet(); if (ifma->ifma_refcount == 1) { /* * No remaining claims to this record; let MLD6 know * that we are leaving the multicast group. */ mld6_stop_listening(in6m); ifma->ifma_protospec = 0; LIST_REMOVE(in6m, in6m_entry); free(in6m, M_IPMADDR); } /* XXX - should be separate API for when we have an ifma? */ if_delmulti(ifma->ifma_ifp, ifma->ifma_addr); splx(s);}#endif /* not FreeBSD3 */struct in6_multi_mship *in6_joingroup(ifp, addr, errorp) struct ifnet *ifp; struct in6_addr *addr; int *errorp;{ struct in6_multi_mship *imm; imm = malloc(sizeof(*imm), M_IPMADDR, M_NOWAIT); if (!imm) { *errorp = ENOBUFS; return NULL; } imm->i6mm_maddr = in6_addmulti(addr, ifp, errorp); if (!imm->i6mm_maddr) { /* *errorp is alrady set */ free(imm, M_IPMADDR); return NULL; } return imm;}intin6_leavegroup(imm) struct in6_multi_mship *imm;{ if (imm->i6mm_maddr) in6_delmulti(imm->i6mm_maddr); free(imm, M_IPMADDR); return 0;}/* * Find an IPv6 interface link-local address specific to an interface. */struct in6_ifaddr *in6ifa_ifpforlinklocal(ifp, ignoreflags) struct ifnet *ifp; int ignoreflags;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -