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

📄 ip_output.c

📁 <B>Digital的Unix操作系统VAX 4.2源码</B>
💻 C
📖 第 1 页 / 共 2 页
字号:
			if (so){				smp_lock(&so->lk_socket, LK_RETRY);				so->ref = 0;			}		}		}		if (error)			break;		else { /* bump up counters for network management */			IPSTAT(ips_totalsent++);			/* a packet was successfully fragmented */			if(ip->ip_off & IP_MF) {				IPSTAT(ips_outpktsfrag++);			}		}	}bad:	m_freem(m);	m = NULL;done:	RTLOCK();	if (ro == &iproute && (flags & IP_ROUTETOIF) == 0 && ro->ro_rt)		rtfree(ro->ro_rt);	RTUNLOCK();	return (error);}/* * Insert IP options into preformed packet. * Adjust IP destination as required for IP source routing, * as indicated by a non-zero in_addr at the start of the options. */struct mbuf *ip_insertoptions(m, opt, phlen)	register struct mbuf *m;	struct mbuf *opt;	int *phlen;{	register struct ipoption *p = mtod(opt, struct ipoption *);	struct mbuf *n;	register struct ip *ip = mtod(m, struct ip *);	unsigned optlen;	optlen = opt->m_len - sizeof(p->ipopt_dst);#ifdef mips	while(optlen&0x03)	/* word align options, if necessary */		optlen++;#endif mips	if (p->ipopt_dst.s_addr)		ip->ip_dst = p->ipopt_dst;	if (m->m_off >= MMAXOFF || MMINOFF + optlen > m->m_off) {		MGET(n, M_DONTWAIT, MT_DATA);		if (n == 0)			return (m);		m->m_len -= sizeof(struct ip);		m->m_off += sizeof(struct ip);		n->m_next = m;		m = n;		m->m_off = MMAXOFF - sizeof(struct ip) - optlen;		m->m_len = optlen + sizeof(struct ip);		bcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip));	} else {		m->m_off -= optlen;		m->m_len += optlen;		ovbcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip));	}	ip = mtod(m, struct ip *);	bcopy((caddr_t)p->ipopt_list, (caddr_t)(ip + 1), (unsigned)optlen);	*phlen = sizeof(struct ip) + optlen;	ip->ip_len += optlen;	return (m);}/* * Copy options from ip to jp. * If off is 0 all options are copied * otherwise copy selectively. */ip_optcopy(ip, jp, off)	struct ip *ip, *jp;	int off;{	register u_char *cp, *dp;	int opt, optlen, cnt;	cp = (u_char *)(ip + 1);	dp = (u_char *)(jp + 1);	cnt = (ip->ip_hl << 2) - sizeof (struct ip);	for (; cnt > 0; cnt -= optlen, cp += optlen) {		opt = cp[0];		if (opt == IPOPT_EOL)			break;		if (opt == IPOPT_NOP)			optlen = 1;		else			optlen = cp[IPOPT_OLEN];		if (optlen > cnt)			/* XXX */			optlen = cnt;			/* XXX */		if (off == 0 || IPOPT_COPIED(opt)) {			bcopy((caddr_t)cp, (caddr_t)dp, (unsigned)optlen);			dp += optlen;		}	}	for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++)		*dp++ = IPOPT_EOL;	return (optlen);}/* * IP socket option processing. */ip_ctloutput(op, so, level, optname, m)	int op;	struct socket *so;	int level, optname;	struct mbuf **m;{	int error = 0;	struct inpcb *inp = sotoinpcb(so);	if (level != IPPROTO_IP)		error = EINVAL;	else switch (op) {	case PRCO_SETOPT:		switch (optname) {		case IP_OPTIONS:			return (ip_pcbopts(&inp->inp_options, *m));		default:			error = EINVAL;			break;		}		break;	case PRCO_GETOPT:		switch (optname) {		case IP_OPTIONS:			*m = m_get(M_DONTWAIT, MT_SOOPTS);			if (*m == NULL){				error = ENOBUFS;				break;			}			if (inp->inp_options) {				(*m)->m_off = inp->inp_options->m_off;				(*m)->m_len = inp->inp_options->m_len;				bcopy(mtod(inp->inp_options, caddr_t),				    mtod(*m, caddr_t), (unsigned)(*m)->m_len);			} else				(*m)->m_len = 0;			break;		default:			error = EINVAL;			break;		}		break;	}	if (op == PRCO_SETOPT && *m)		(void)m_free(*m);	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. */ip_pcbopts(pcbopt, m)	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);	}	if (m->m_len % sizeof(long))		goto bad;	/*	 * IP first-hop destination address will be stored before	 * actual options; move other options back	 * and clear it when none present.	 */#if	MAX_IPOPTLEN >= MMAXOFF - MMINOFF	if (m->m_off + m->m_len + sizeof(struct in_addr) > MAX_IPOPTLEN)		goto bad;#else	if (m->m_off + m->m_len + sizeof(struct in_addr) > MMAXOFF)		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;		}	}	*pcbopt = m;	return (0);bad:	(void)m_free(m);	return (EINVAL);}/* * Attempt to fragment type 2 mbuf chain. * Works only if each mbuf is smaller than a packet. * This saves copying all the data. */ip_frag2(m, ip, maxpacketlen, errorp, ifp, dst, so)	register struct mbuf *m;	register struct ip *ip;	register int maxpacketlen;	int *errorp;	struct ifnet *ifp;	struct sockaddr *dst;	struct socket *so;{	struct mbuf *mm;	struct mbuf *lastm;	register struct mbuf *mh;	register int fraglen, fragoff, pktlen, n;	struct ip *nextip;	int saveaffinity;	/*	 * Check whether we can do it.	 */	mm = m;	n = 0;	while (m) {		if (m->m_off > MMAXOFF && m->m_cltype == 2) {			n++;		}		if (m->m_len + sizeof (struct ip) > maxpacketlen) {			return (0);		}		m = m->m_next;	}	if (n == 0) {	/* higher level does type 1 chain better */		return (0);	}	m = mm;	fragoff = 0;	while (m) {		pktlen = 0;		mm = m;		/*		 * Gather up all the mbufs that will fit in a frag.		 */		while (m && pktlen + m->m_len <= maxpacketlen) {			pktlen += m->m_len;			lastm = m;			m = m->m_next;		}		fraglen = pktlen - sizeof (struct ip);		lastm->m_next = 0;		if (m) {			/*			 * There are more frags, so we prepend			 * a copy of the ip hdr to the rest			 * of the chain.			 */			MGET(mh, M_DONTWAIT, MT_DATA);			if (mh == 0) {				*errorp = ENOBUFS;				IPSTAT(ips_outdiscard++); /* a packet was							   * discarded							   */				break;			}			mh->m_off = MMAXOFF - sizeof (struct ip) - 8;			nextip = mtod(mh, struct ip *);			/* copy the ip header */			*nextip = *ip;			mh->m_len = sizeof (struct ip);			mh->m_next = m;			m = mh;			if (n = (fraglen & 7)) {				/*				 * IP fragments must be a multiple of				 * 8 bytes long so we must play games.				 */				bcopy(mtod(lastm, caddr_t) + lastm->m_len					- n, (caddr_t) (nextip + 1), n);				lastm->m_len -= n;				mh->m_len += n;				pktlen -= n;				fraglen -= n;			}			ip->ip_off = htons((u_short) ((fragoff >> 3) | IP_MF));		} else {			ip->ip_off = htons((u_short) (fragoff >> 3));		}		/*		 * Fix up the ip header for the mm chain and send it off.		 */		if (ip->ip_len < pktlen) {			ip->ip_len = htons((u_short) ip->ip_len);			if (m) {				m_freem(m);				m = 0;			}		} else {			ip->ip_len = htons((u_short) pktlen);			if (m) {				nextip->ip_len -= fraglen;			}		}		ip->ip_sum = 0;		ip->ip_sum = in_cksum(mm, sizeof (struct ip));		/* Support for nonsymm net devices. 8.9.88.us */		if (!smp)			*errorp = (*ifp->if_output)(ifp, mm, dst);		else{		if (ifp->d_affinity != boot_cpu_mask)			*errorp = (*ifp->if_output)(ifp, mm, dst);		else{			if (so){				so->ref = 26;				smp_unlock(&so->lk_socket);			}			CALL_TO_NONSMP_DRIVER( (*ifp), saveaffinity);			*errorp = (*ifp->if_output)(ifp, mm, dst);			RETURN_FROM_NONSMP_DRIVER( (*ifp), saveaffinity);			if (so){				smp_lock(&so->lk_socket, LK_RETRY);				so->ref = 0;			}		}		}		if (*errorp){			if(m)				m_freem(m);			break;		} else {			IPSTAT(ips_totalsent++); 			/* fragmentation was successfull */ 			IPSTAT(ips_outtotalfrag++); 		}		ip = nextip;		fragoff += fraglen;	}	return (1);}

⌨️ 快捷键说明

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