📄 ipproto.c
字号:
if (ifp->ac_if.if_resolve) { pDrvCtrl = (IP_DRV_CTRL*)ifp->ac_if.pCookie; ifr = (struct ifreq *)data; inetaddr = &ifr->ifr_addr; pMblk = KHEAP_ALLOC(sizeof(M_BLK)); if (pMblk == NULL) { error = ENOBUFS; break; } bzero ( (char *)pMblk, sizeof (M_BLK)); pMblk->mBlkHdr.mFlags |= M_MCAST; /* * call the registered address resolution function * to do the mapping */ if (ifp->ac_if.if_resolve (&ipMcastResume, pMblk, inetaddr, &ifp->ac_if, SIOCADDMULTI, &mapMCastBuff) == 0) { KHEAP_FREE( (char *)pMblk); break; /* not yet resolved */ } KHEAP_FREE( (char *)pMblk); /* register the mapped multicast MAC address */ error = muxMCastAddrAdd (pDrvCtrl->pIpCookie, (char *)&mapMCastBuff); } break; /* if no resolve function, return OK */ case SIOCDELMULTI: /* Don't allow group membership on non-multicast interfaces. */ if ((ifp->ac_if.if_flags & IFF_MULTICAST) == 0) return EOPNOTSUPP; if (ifp->ac_if.if_resolve) { pDrvCtrl = ifp->ac_if.pCookie; ifr = (struct ifreq *)data; inetaddr = (&ifr->ifr_addr); pMblk = KHEAP_ALLOC(sizeof (M_BLK)); if (pMblk == NULL) { error = ENOBUFS; break; } bzero ( (char *)pMblk, sizeof (M_BLK)); pMblk->mBlkHdr.mFlags |= M_MCAST; /* * call the registered address resolution function to do * the mapping */ if (ifp->ac_if.if_resolve (&ipMcastResume, pMblk, inetaddr, &ifp->ac_if, SIOCDELMULTI, &mapMCastBuff) == 0) { KHEAP_FREE( (char *)pMblk); break; /* not yet resolved */ } KHEAP_FREE( (char *)pMblk); /* delete the mapped multicast MAC address */ error = muxMCastAddrDel (pDrvCtrl->pIpCookie, (char *)&mapMCastBuff); } break; /* if no resolve routine, return OK */ case SIOCGETMULTI: break; case SIOCSIFFLAGS: ifr = (struct ifreq *) data; /* * Turn off all flags that are disabled in the request * correcting for the conversion from short to long */ flagsMask = (unsigned short) (~ ifr->ifr_flags); /* Two's complement used to disable flags by muxIoctl () */ flagsMask = -flagsMask - 1; error = muxIoctl (pDrvCtrl->pIpCookie, EIOCSFLAGS, (caddr_t) flagsMask); /* * Next set all flags that are set in request correcting for * the conversion from short to long. */ flagsMask = (unsigned short) ifr->ifr_flags; error |= muxIoctl (pDrvCtrl->pIpCookie, EIOCSFLAGS, (caddr_t) flagsMask); break; case SIOCGMCASTLIST: error = muxIoctl (pDrvCtrl->pIpCookie, EIOCGMCASTLIST, data); if (error != OK) return (EINVAL); break; default: error = muxIoctl (pDrvCtrl->pIpCookie, cmd, data); break; } return (error); }/******************************************************************************** ipOutput - transmit routine for IP packets using END or NPT devices.** This routine handles the final processing before transferring a* network packet (contained in the <m0> argument) to the transmit* device.** For END devices, it encapsulates a packet in the link-level frame* before transferring it to the driver. The output processing constructs* Ethernet frames unless the device provides a custom routine to form the* appropriate frame header.** For NPT devices, the routine just inserts the destination link-level* address at the front of the mBlk chain. Later processing hands that* address to the driver along with an mBlk chain containing the network* packet (with no link-level header).** NOTE: It assumes that ifp is actually a pointer to an arpcom structure.** NOMANUAL*/LOCAL int ipOutput ( register struct ifnet *ifp, struct mbuf *m0, struct sockaddr *dst, struct rtentry *rt0 ) { u_short etype = 0; int s, error = 0; register struct mbuf *m = m0; register struct rtentry *rt; int off; struct arpcom *ac = (struct arpcom *)ifp; struct ether_header* eh; IP_DRV_CTRL* pDrvCtrl; pDrvCtrl = (IP_DRV_CTRL *)ifp->pCookie; if (pDrvCtrl->pIpCookie == NULL) senderr (EINVAL); if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_CRITICAL event */ WV_NET_EVENT_1 (NET_CORE_EVENT, WV_NET_CRITICAL, 2, 3, WV_NETEVENT_ETHEROUT_IFDOWN, WV_NET_SEND, ifp)#endif /* INCLUDE_WVNET */#endif senderr(ENETDOWN); } ifp->if_lastchange = tickGet(); if ((rt = rt0)) { if ((rt->rt_flags & RTF_UP) == 0) { if ((rt0 = rt = rtalloc1(dst, 1, 1))) rt->rt_refcnt--; else {#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_CRITICAL event */ WV_NET_EVENT_1 (NET_CORE_EVENT, WV_NET_CRITICAL, 4, 5, WV_NETEVENT_ETHEROUT_NOROUTE, WV_NET_SEND, ((struct sockaddr_in *)dst)->sin_addr.s_addr)#endif /* INCLUDE_WVNET */#endif senderr(EHOSTUNREACH); } } if (rt->rt_flags & RTF_GATEWAY) { if (rt->rt_gwroute == 0) goto lookup; if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { rtfree(rt); rt = rt0; lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1, 0); if ((rt = rt->rt_gwroute) == 0) {#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_CRITICAL event */ WV_NET_EVENT_1 (NET_CORE_EVENT, WV_NET_CRITICAL, 4, 5, WV_NETEVENT_ETHEROUT_NOROUTE, WV_NET_SEND, ((struct sockaddr_in *)rt->rt_gateway)->sin_addr.s_addr)#endif /* INCLUDE_WVNET */#endif senderr(EHOSTUNREACH); } } } if (rt->rt_flags & RTF_REJECT) { if (rt->rt_rmx.rmx_expire == 0 || tickGet() < rt->rt_rmx.rmx_expire) {#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_CRITICAL event */ WV_NET_EVENT_0 (NET_CORE_EVENT, WV_NET_CRITICAL, 5, 6, WV_NETEVENT_ETHEROUT_RTREJECT, WV_NET_SEND)#endif /* INCLUDE_WVNET */#endif senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); } } } /* if (rt = rt0) */ switch (dst->sa_family) { case AF_INET: if (ifp->if_resolve != NULL) if (!ifp->if_resolve (&ipOutputResume, m, dst, ifp, rt, pDrvCtrl->pDstAddr)) return (0); /* if not yet resolved */#ifdef ROUTER_STACK /* * If we are forwarding the packet, check if we need to * supply the forwarding information to Fastpath. We do not * want to call Fastpath with a broadcast or multicast address */ if ((m->m_flags & M_FORWARD) && pIpv4FFRouteCompleteFn != NULL && !(m->m_flags & M_MCAST || m->m_flags & M_BCAST)) (*pIpv4FFRouteCompleteFn) (rt0, pDrvCtrl, ifp, dst);#endif /* ROUTER_STACK */ /* If broadcasting on a simplex interface, loopback a copy */ if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX) && !(m->m_flags & M_PROXY)) ip_mloopback (ifp, m, (struct sockaddr_in *)dst, (struct rtentry*)rt); off = m->m_pkthdr.len - m->m_len; etype = ETHERTYPE_IP; break; case AF_UNSPEC: /* * WARNING: At the moment this code ONLY handles 14 byte * headers of the type like Ethernet. */ switch (ifp->if_type) { case M2_ifType_ethernet_csmacd: case M2_ifType_fastEther: case M2_ifType_gigabitEthernet: case M2_ifType_iso88023_csmacd: case M2_ifType_iso88024_tokenBus: case M2_ifType_iso88025_tokenRing: case M2_ifType_iso88026_man: case M2_ifType_fddi: eh = (struct ether_header *)dst->sa_data; bcopy((caddr_t)eh->ether_dhost, (caddr_t)pDrvCtrl->pDstAddr, ifp->if_addrlen); etype = eh->ether_type; break; default: error=ERROR; } if(!error) break; /* fall-through */ default: logMsg ("%s%d: can't handle af%d\n", (int)ifp->if_name, ifp->if_unit, dst->sa_family, 0, 0, 0);#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_ERROR event */ WV_NET_EVENT_1 (NET_CORE_EVENT, WV_NET_ERROR, 3, 7, WV_NETEVENT_ETHEROUT_AFNOTSUPP, WV_NET_SEND, dst->sa_family)#endif /* INCLUDE_WVNET */#endif senderr(EAFNOSUPPORT); } etype = htons(etype); if (pDrvCtrl->nptFlag) { /* * For NPT devices, insert the destination address (if any) and * network protocol type at the beginning of the network packet * for later use. */ if (ifp->if_addrlen) { M_PREPEND(m, ifp->if_addrlen, M_DONTWAIT); if (m == NULL) { senderr(ENOBUFS); } ((M_BLK_ID)m)->mBlkPktHdr.rcvif = 0; /* Store the destination address. */ bcopy (pDrvCtrl->pDstAddr, m->m_data, ifp->if_addrlen); } /* Save the network protocol type. */ ((M_BLK_ID)m)->mBlkHdr.reserved = etype; } else { /* * For END devices, build and prepend the complete frame instead. * NOTE: currently, the ac_enaddr field is only valid for specific * device types. (See the ipAttach routine). */ pDrvCtrl->pSrc->m_data = (char *)&ac->ac_enaddr; pDrvCtrl->pDst->mBlkHdr.reserved = etype; pDrvCtrl->pSrc->mBlkHdr.reserved = etype; m = muxAddressForm (pDrvCtrl->pIpCookie, m, pDrvCtrl->pSrc, pDrvCtrl->pDst); if (m == NULL) {#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_CRITICAL event */ WV_NET_EVENT_1 (NET_CORE_EVENT, WV_NET_CRITICAL, 3, 4, WV_NETEVENT_ETHEROUT_NOBUFS, WV_NET_SEND, ifp)#endif /* INCLUDE_WVNET */#endif senderr(ENOBUFS); } } s = splimp(); /* * Queue message on interface, and start output if interface * not yet active. */ if (IF_QFULL(&ifp->if_snd)) { IF_DROP(&ifp->if_snd); splx(s);#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_CRITICAL event */ WV_NET_EVENT_1 (NET_CORE_EVENT, WV_NET_CRITICAL, 3, 4, WV_NETEVENT_ETHEROUT_NOBUFS, WV_NET_SEND, ifp)#endif /* INCLUDE_WVNET */#endif senderr(ENOBUFS); } IF_ENQUEUE(&ifp->if_snd, m); (*ifp->if_start)(ifp); splx(s); ifp->if_obytes += m->mBlkHdr.mLen; if (m->m_flags & M_MCAST || m->m_flags & M_BCAST) ifp->if_omcasts++;#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_NOTICE event */ WV_NET_EVENT_2 (NET_CORE_EVENT, WV_NET_NOTICE, 3, 12, WV_NETEVENT_ETHEROUT_FINISH, WV_NET_SEND, ifp, error)#endif /* INCLUDE_WVNET */#endif return (error); bad: if (m) netMblkClChainFree(m); return (error); }/********************************************************************************* ipOutputResume - transmit routine called after delayed address resolution** When sending an IP packet, all address resolution functions responsible* for converting an IP address to a link-layer address receive a pointer
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -