📄 ip_output.c
字号:
break; } break; } return (error);}/* * Set up IP options in pcb for insertion in output packets. * Store in mbuf with pointer in pcbopt, adding pseudo-option * with destination address if source routed. */int#ifdef notyetip_pcbopts(optname, pcbopt, m) int optname;#elseip_pcbopts(pcbopt, m)#endif struct mbuf **pcbopt; register struct mbuf *m;{ register int cnt, optlen; register u_char *cp; u_char opt; /* turn off any old options */ if (*pcbopt) (void)m_free(*pcbopt); *pcbopt = 0; if (m == (struct mbuf *)0 || m->m_len == 0) { /* * Only turning off any previous options. */ if (m) (void)m_free(m); return (0); }#ifndef vax if (m->m_len % sizeof(long)) goto bad;#endif /* * IP first-hop destination address will be stored before * actual options; move other options back * and clear it when none present. */#if 0 /*XXX changed for default cluster support vinai*/ if (m->m_data + m->m_len + sizeof(struct in_addr) >= &m->m_dat[MLEN]) goto bad;#else if (m->m_data + m->m_len + sizeof(struct in_addr) >= (m->m_extBuf + m->m_extSize)) goto bad;#endif cnt = m->m_len; m->m_len += sizeof(struct in_addr); cp = mtod(m, u_char *) + sizeof(struct in_addr); ovbcopy(mtod(m, caddr_t), (caddr_t)cp, (unsigned)cnt); bzero(mtod(m, caddr_t), sizeof(struct in_addr)); for (; cnt > 0; cnt -= optlen, cp += optlen) { opt = cp[IPOPT_OPTVAL]; if (opt == IPOPT_EOL) break; if (opt == IPOPT_NOP) optlen = 1; else { optlen = cp[IPOPT_OLEN]; if (optlen <= IPOPT_OLEN || optlen > cnt) goto bad; } switch (opt) { default: break; case IPOPT_LSRR: case IPOPT_SSRR: /* * user process specifies route as: * ->A->B->C->D * D must be our final destination (but we can't * check that since we may not have connected yet). * A is first hop destination, which doesn't appear in * actual IP option, but is stored before the options. */ if (optlen < IPOPT_MINOFF - 1 + sizeof(struct in_addr)) goto bad; m->m_len -= sizeof(struct in_addr); cnt -= sizeof(struct in_addr); optlen -= sizeof(struct in_addr); cp[IPOPT_OLEN] = optlen; /* * Move first hop before start of options. */ bcopy((caddr_t)&cp[IPOPT_OFFSET+1], mtod(m, caddr_t), sizeof(struct in_addr)); /* * Then copy rest of options back * to close up the deleted entry. */ ovbcopy((caddr_t)(&cp[IPOPT_OFFSET+1] + sizeof(struct in_addr)), (caddr_t)&cp[IPOPT_OFFSET+1], (unsigned)cnt + sizeof(struct in_addr)); break; } } 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 ((ifp == NULL || 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. */voidip_mloopback(ifp, m, dst, rt) struct ifnet *ifp; register struct mbuf *m; register struct sockaddr_in *dst; struct rtentry *rt;{ register struct ip *ip; struct mbuf *copym; struct mbuf * pMbuf;#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_INFO event */ WV_NET_EVENT_0 (NET_AUX_EVENT, WV_NET_INFO, 12, 7, WV_NETEVENT_IPMLOOP_START, WV_NET_RECV)#endif /* INCLUDE_WVNET */#endif 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, rt); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -