⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ip_output.c

📁 RTEMS (Real-Time Executive for Multiprocessor Systems) is a free open source real-time operating sys
💻 C
📖 第 1 页 / 共 3 页
字号:
			 * 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 intip_setmoptions(optname, imop, m)	int optname;	struct ip_moptions **imop;	struct mbuf *m;{	register int error = 0;	u_char loop;	register int i;	struct in_addr addr;	register struct ip_mreq *mreq;	register struct ifnet *ifp;	register struct ip_moptions *imo = *imop;	struct route ro;	register struct sockaddr_in *dst;	int s;	if (imo == NULL) {		/*		 * No multicast option buffer attached to the pcb;		 * allocate one and initialize to default values.		 */		imo = (struct ip_moptions*)malloc(sizeof(*imo), M_IPMOPTS,		    M_WAITOK);		if (imo == NULL)			return (ENOBUFS);		*imop = imo;		imo->imo_multicast_ifp = NULL;		imo->imo_multicast_vif = -1;		imo->imo_multicast_ttl = IP_DEFAULT_MULTICAST_TTL;		imo->imo_multicast_loop = IP_DEFAULT_MULTICAST_LOOP;		imo->imo_num_memberships = 0;	}	switch (optname) {	/* store an index number for the vif you wanna use in the send */	case IP_MULTICAST_VIF:		if (!legal_vif_num) {			error = EOPNOTSUPP;			break;		}		if (m == NULL || m->m_len != sizeof(int)) {			error = EINVAL;			break;		}		i = *(mtod(m, int *));		if (!legal_vif_num(i) && (i != -1)) {			error = EINVAL;			break;		}		imo->imo_multicast_vif = i;		break;	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.		 */		s = splimp();		INADDR_TO_IFP(addr, ifp);		if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {			splx(s);			error = EADDRNOTAVAIL;			break;		}		imo->imo_multicast_ifp = ifp;		splx(s);		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;		}		s = splimp();		/*		 * 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) {			bzero((caddr_t)&ro, sizeof(ro));			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;				splx(s);				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;			splx(s);			break;		}		/*		 * See if the membership already exists or if all the		 * membership slots are full.		 */		for (i = 0; i < imo->imo_num_memberships; ++i) {			if (imo->imo_membership[i]->inm_ifp == ifp &&			    imo->imo_membership[i]->inm_addr.s_addr						== mreq->imr_multiaddr.s_addr)				break;		}		if (i < imo->imo_num_memberships) {			error = EADDRINUSE;			splx(s);			break;		}		if (i == IP_MAX_MEMBERSHIPS) {			error = ETOOMANYREFS;			splx(s);			break;		}		/*		 * Everything looks good; add a new record to the multicast		 * address list for the given interface.		 */		if ((imo->imo_membership[i] =		    in_addmulti(&mreq->imr_multiaddr, ifp)) == NULL) {			error = ENOBUFS;			splx(s);			break;		}		++imo->imo_num_memberships;		splx(s);		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;		}		s = splimp();		/*		 * 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;				splx(s);				break;			}		}		/*		 * Find the membership in the membership array.		 */		for (i = 0; i < imo->imo_num_memberships; ++i) {			if ((ifp == NULL ||			     imo->imo_membership[i]->inm_ifp == ifp) &&			     imo->imo_membership[i]->inm_addr.s_addr ==			     mreq->imr_multiaddr.s_addr)				break;		}		if (i == imo->imo_num_memberships) {			error = EADDRNOTAVAIL;			splx(s);			break;		}		/*		 * Give up the multicast address record to which the		 * membership points.		 */		in_delmulti(imo->imo_membership[i]);		/*		 * Remove the gap in the membership array.		 */		for (++i; i < imo->imo_num_memberships; ++i)			imo->imo_membership[i-1] = imo->imo_membership[i];		--imo->imo_num_memberships;		splx(s);		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_vif == -1 &&	    imo->imo_multicast_ttl == IP_DEFAULT_MULTICAST_TTL &&	    imo->imo_multicast_loop == IP_DEFAULT_MULTICAST_LOOP &&	    imo->imo_num_memberships == 0) {		free(*imop, M_IPMOPTS);		*imop = NULL;	}	return (error);}/* * Return the IP multicast options in response to user getsockopt(). */static 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 = m_get(M_WAIT, MT_SOOPTS);	switch (optname) {	case IP_MULTICAST_VIF: 		if (imo != NULL)			*(mtod(*mp, int *)) = imo->imo_multicast_vif;		else			*(mtod(*mp, int *)) = -1;		(*mp)->m_len = sizeof(int);		return(0);	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)	register struct ip_moptions *imo;{	register int i;	if (imo != NULL) {		for (i = 0; i < imo->imo_num_memberships; ++i)			in_delmulti(imo->imo_membership[i]);		free(imo, M_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 a loopback interface -- evil, but easier than * replicating that code here. */static voidip_mloopback(ifp, m, dst, hlen)	struct ifnet *ifp;	register struct mbuf *m;	register struct sockaddr_in *dst;	int hlen;{	register struct ip *ip;	struct mbuf *copym;	copym = m_copy(m, 0, M_COPYALL);	if (copym != NULL && (copym->m_flags & M_EXT || copym->m_len < hlen))		copym = m_pullup(copym, hlen);	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 *);		ip->ip_len = htons((u_short)ip->ip_len);		ip->ip_off = htons((u_short)ip->ip_off);		ip->ip_sum = 0;		if (ip->ip_vhl == IP_VHL_BORING) {			ip->ip_sum = in_cksum_hdr(ip);		} else {			ip->ip_sum = in_cksum(copym, hlen);		}		/*		 * NB:		 * It's not clear whether there are any lingering		 * reentrancy problems in other areas which might		 * be exposed by using ip_input directly (in		 * particular, everything which modifies the packet		 * in-place).  Yet another option is using the		 * protosw directly to deliver the looped back		 * packet.  For the moment, we'll err on the side		 * of safety by continuing to abuse looutput().		 */#ifdef notdef		copym->m_pkthdr.rcvif = ifp;		ip_input(copym)#else		(void) looutput(ifp, copym, (struct sockaddr *)dst, NULL);#endif	}}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -