📄 ip_output.c
字号:
} } if (m->m_len > MAX_IPOPTLEN + sizeof(struct in_addr)) goto bad; *pcbopt = m; return (0);bad: (void)m_free(m); return (EINVAL);}/* * Set the IP multicast options in response to user setsockopt(). */static int ip_setmoptions ( int optname, struct inpcb * pInPcb, struct mbuf * m ){ register int error = 0; u_char loop; struct in_addr addr; register struct ip_mreq *mreq; register struct ifnet *ifp; register struct ip_moptions ** imop = &pInPcb->inp_moptions; register struct ip_moptions *imo = *imop; struct route ro; register struct sockaddr_in *dst; struct in_multi * pInMulti; M_BLK_ID pInmMblk = NULL; M_BLK ** ppMblk; if (imo == NULL) { /* * No multicast option buffer attached to the pcb; * allocate one and initialize to default values. */ MALLOC(imo,struct ip_moptions *, sizeof (*imo), MT_IPMOPTS, M_WAIT); if (imo == NULL) return (ENOBUFS); *imop = imo; imo->imo_multicast_ifp = NULL; imo->imo_multicast_ttl = IP_DEFAULT_MULTICAST_TTL; imo->imo_multicast_loop = IP_DEFAULT_MULTICAST_LOOP; imo->imo_num_memberships = 0; imo->pInmMblk = NULL; } switch (optname) { case IP_MULTICAST_IF: /* * Select the interface for outgoing multicast packets. */ if (m == NULL || m->m_len != sizeof(struct in_addr)) { error = EINVAL; break; } addr = *(mtod(m, struct in_addr *)); /* * INADDR_ANY is used to remove a previous selection. * When no interface is selected, a default one is * chosen every time a multicast packet is sent. */ if (addr.s_addr == INADDR_ANY) { imo->imo_multicast_ifp = NULL; break; } /* * The selected interface is identified by its local * IP address. Find the interface and confirm that * it supports multicasting. */ INADDR_TO_IFP(addr, ifp); if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) { error = EADDRNOTAVAIL; break; } imo->imo_multicast_ifp = ifp; break; case IP_MULTICAST_TTL: /* * Set the IP time-to-live for outgoing multicast packets. */ if (m == NULL || m->m_len != 1) { error = EINVAL; break; } imo->imo_multicast_ttl = *(mtod(m, u_char *)); break; case IP_MULTICAST_LOOP: /* * Set the loopback flag for outgoing multicast packets. * Must be zero or one. */ if (m == NULL || m->m_len != 1 || (loop = *(mtod(m, u_char *))) > 1) { error = EINVAL; break; } imo->imo_multicast_loop = loop; break; case IP_ADD_MEMBERSHIP: /* * Add a multicast group membership. * Group must be a valid IP multicast address. */ if (m == NULL || m->m_len != sizeof(struct ip_mreq)) { error = EINVAL; break; } mreq = mtod(m, struct ip_mreq *); if (!IN_MULTICAST(ntohl(mreq->imr_multiaddr.s_addr))) { error = EINVAL; break; } /* * If no interface address was provided, use the interface of * the route to the given multicast address. */ if (mreq->imr_interface.s_addr == INADDR_ANY) { ro.ro_rt = NULL; dst = (struct sockaddr_in *)&ro.ro_dst; dst->sin_len = sizeof(*dst); dst->sin_family = AF_INET; dst->sin_addr = mreq->imr_multiaddr; rtalloc(&ro); if (ro.ro_rt == NULL) { error = EADDRNOTAVAIL; break; } ifp = ro.ro_rt->rt_ifp; rtfree(ro.ro_rt); } else { INADDR_TO_IFP(mreq->imr_interface, ifp); } /* * See if we found an interface, and confirm that it * supports multicast. */ if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) { error = EADDRNOTAVAIL; break; } ppMblk = &imo->pInmMblk; while (*ppMblk) { pInMulti = mtod (*ppMblk, struct in_multi*); if ((pInMulti->inm_ifp == ifp) && (pInMulti->inm_addr.s_addr == mreq->imr_multiaddr.s_addr)) break; /* jump out of the while loop */ ppMblk = &(*ppMblk)->mBlkHdr.mNext; } if (*ppMblk == NULL) { if ((pInmMblk = in_addmulti (&mreq->imr_multiaddr, ifp, pInPcb)) == NULL) { error = ENOBUFS; break; } *ppMblk = pInmMblk; /* add to the list */ ++imo->imo_num_memberships; } else error = EADDRINUSE; break; case IP_DROP_MEMBERSHIP: /* * Drop a multicast group membership. * Group must be a valid IP multicast address. */ if (m == NULL || m->m_len != sizeof(struct ip_mreq)) { error = EINVAL; break; } mreq = mtod(m, struct ip_mreq *); if (!IN_MULTICAST(ntohl(mreq->imr_multiaddr.s_addr))) { error = EINVAL; break; } /* * If an interface address was specified, get a pointer * to its ifnet structure. */ if (mreq->imr_interface.s_addr == INADDR_ANY) ifp = NULL; else { INADDR_TO_IFP(mreq->imr_interface, ifp); if (ifp == NULL) { error = EADDRNOTAVAIL; break; } } { ppMblk = &imo->pInmMblk; while (*ppMblk) { pInMulti = mtod (*ppMblk, struct in_multi*); if ((pInMulti->inm_ifp == ifp) && (pInMulti->inm_addr.s_addr == mreq->imr_multiaddr.s_addr)) { pInmMblk = *ppMblk; /* delete from the list */ *ppMblk = (*ppMblk)->mBlkHdr.mNext; break; /* jump out of the while loop */ } ppMblk = &(*ppMblk)->mBlkHdr.mNext; } if (pInmMblk == NULL) { error = EADDRNOTAVAIL; break; } /* * Give up the multicast address record to which the * membership points. */ in_delmulti (pInmMblk, pInPcb); --imo->imo_num_memberships; break; } default: error = EOPNOTSUPP; break; } /* * If all options have default values, no need to keep the mbuf. */ if (imo->imo_multicast_ifp == NULL && imo->imo_multicast_ttl == IP_DEFAULT_MULTICAST_TTL && imo->imo_multicast_loop == IP_DEFAULT_MULTICAST_LOOP && imo->imo_num_memberships == 0) { FREE(*imop, MT_IPMOPTS); *imop = NULL; } return (error);}/* * Return the IP multicast options in response to user getsockopt(). */intip_getmoptions(optname, imo, mp) int optname; register struct ip_moptions *imo; register struct mbuf **mp;{ u_char *ttl; u_char *loop; struct in_addr *addr; struct in_ifaddr *ia; *mp = mBufClGet(M_WAIT, MT_SOOPTS, CL_SIZE_128, TRUE); if (*mp == NULL) return (ENOBUFS); switch (optname) { case IP_MULTICAST_IF: addr = mtod(*mp, struct in_addr *); (*mp)->m_len = sizeof(struct in_addr); if (imo == NULL || imo->imo_multicast_ifp == NULL) addr->s_addr = INADDR_ANY; else { IFP_TO_IA(imo->imo_multicast_ifp, ia); addr->s_addr = (ia == NULL) ? INADDR_ANY : IA_SIN(ia)->sin_addr.s_addr; } return (0); case IP_MULTICAST_TTL: ttl = mtod(*mp, u_char *); (*mp)->m_len = 1; *ttl = (imo == NULL) ? IP_DEFAULT_MULTICAST_TTL : imo->imo_multicast_ttl; return (0); case IP_MULTICAST_LOOP: loop = mtod(*mp, u_char *); (*mp)->m_len = 1; *loop = (imo == NULL) ? IP_DEFAULT_MULTICAST_LOOP : imo->imo_multicast_loop; return (0); default: return (EOPNOTSUPP); }}/* * Discard the IP multicast options. */voidip_freemoptions(imo, pInPcb) register struct ip_moptions *imo; struct inpcb * pInPcb; { M_BLK_ID pInmMblk; M_BLK_ID pInmMblkNext; if (imo != NULL) { pInmMblk = imo->pInmMblk; pInmMblkNext = imo->pInmMblk; while ((pInmMblk = pInmMblkNext) != NULL) { pInmMblkNext = pInmMblk->mBlkHdr.mNext; in_delmulti (pInmMblk, pInPcb); } FREE(imo, MT_IPMOPTS); }}/* * Routine called from ip_output() to loop back a copy of an IP multicast * packet to the input queue of a specified interface. Note that this * calls the output routine of the loopback "driver", but with an interface * pointer that might NOT be &loif -- easier than replicating that code here. */static voidip_mloopback(ifp, m, dst) struct ifnet *ifp; register struct mbuf *m; register struct sockaddr_in *dst;{ register struct ip *ip; struct mbuf *copym; struct mbuf * pMbuf; copym = m_copy(m, 0, M_COPYALL); if (copym != NULL) { /* * We don't bother to fragment if the IP length is greater * than the interface's MTU. Can this possibly matter? */ ip = mtod(copym, struct ip *); /* * This copying of ip header is done because the same * ip header is shared by looutput and the code under the * the label sendit: in ip_output. so a fresh mbuf has to be * linked to the data. */ if ((pMbuf = mBufClGet (M_DONTWAIT, MT_DATA, sizeof(struct ip), TRUE)) == NULL) { m_freem (copym); return; } /* copy the ip header */ bcopy ((char *)ip , (char *)(mtod(pMbuf, char *)), sizeof(struct ip)); pMbuf->m_len = sizeof (struct ip); pMbuf->m_flags = copym->m_flags; /* copy the flags */ pMbuf->m_pkthdr = copym->m_pkthdr; /* copy the pkt hdr */ pMbuf->m_next = copym; copym->m_flags &= ~M_PKTHDR; copym->m_len -= sizeof(struct ip); copym->m_data += sizeof(struct ip); ip = mtod(pMbuf, struct ip *); copym = pMbuf; ip->ip_len = htons((u_short)ip->ip_len); ip->ip_off = htons((u_short)ip->ip_off); ip->ip_sum = 0; if (_ipCfgFlags & IP_DO_CHECKSUM_SND) ip->ip_sum = in_cksum(copym, ip->ip_hl << 2); (void) looutput(ifp, copym, (struct sockaddr *)dst, NULL); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -