xref: /csrg-svn/sys/netinet/ip_output.c (revision 4967)
1*4967Swnj /*	ip_output.c	1.16	81/11/20	*/
24571Swnj 
34496Swnj #include "../h/param.h"
44662Swnj #include "../h/mbuf.h"
54724Swnj #include "../h/mtpr.h"
64662Swnj #include "../h/socket.h"
74924Swnj #include "../h/socketvar.h"
84802Swnj #include "../net/inet.h"
94802Swnj #include "../net/inet_systm.h"
104802Swnj #include "../net/imp.h"
114802Swnj #include "../net/ip.h"
124899Swnj #include "../net/ip_var.h"
134496Swnj 
144924Swnj ip_output(m)
154924Swnj 	struct mbuf *m;
164496Swnj {
174924Swnj 	register struct ip *ip = mtod(m, struct ip *);
184924Swnj 	int len, hlen = ip->ip_hl << 2, off;
194496Swnj 
204496Swnj COUNT(IP_OUTPUT);
214924Swnj 	/*
224924Swnj 	 * Fill in IP header.
234924Swnj 	 */
244924Swnj 	ip->ip_v = IPVERSION;
254924Swnj 	ip->ip_hl = hlen >> 2;
264924Swnj 	ip->ip_off &= IP_DF;
274924Swnj 	ip->ip_ttl = MAXTTL;
284924Swnj 	ip->ip_id = ip_id++;
294496Swnj 
304545Swnj 	/*
314924Swnj 	 * If small enough for interface, can just send directly.
324545Swnj 	 */
334924Swnj 	if (ip->ip_len <= MTU) {
344924Swnj 		ip_send(ip);
354908Swnj 		return;
364908Swnj 	}
374924Swnj 
384924Swnj 	/*
394924Swnj 	 * Too large for interface; fragment if possible.
404924Swnj 	 * Must be able to put at least 8 bytes per fragment.
414924Swnj 	 */
424924Swnj 	if (ip->ip_off & IP_DF)
434924Swnj 		goto bad;
444924Swnj 	len = (MTU-hlen) &~ 7;
454924Swnj 	if (len < 8)
464924Swnj 		goto bad;
474924Swnj 
484924Swnj 	/*
494924Swnj 	 * Discard IP header from logical mbuf for m_copy's sake.
504924Swnj 	 * Loop through length of segment, make a copy of each
514924Swnj 	 * part and output.
524924Swnj 	 */
534924Swnj 	m->m_len -= sizeof (struct ip);
544924Swnj 	m->m_off += sizeof (struct ip);
554924Swnj 	for (off = 0; off < ip->ip_len; off += len) {
564924Swnj 		struct mbuf *mh = m_get(0);
574924Swnj 		struct ip *mhip;
584924Swnj 
594924Swnj 		if (mh == 0)
604924Swnj 			goto bad;
614924Swnj 		mh->m_off = MMAXOFF - hlen;
624924Swnj 		mhip = mtod(mh, struct ip *);
634924Swnj 		*mhip = *ip;
644952Swnj 		if (hlen > sizeof (struct ip)) {
654924Swnj 			int olen = ip_optcopy(ip, mhip, off);
664924Swnj 			mh->m_len = sizeof (struct ip) + olen;
674924Swnj 		} else
684924Swnj 			mh->m_len = sizeof (struct ip);
694924Swnj 		mhip->ip_off = off;
704924Swnj 		if (off + len >= ip->ip_len)
714924Swnj 			mhip->ip_len = ip->ip_len - off;
724924Swnj 		else {
734924Swnj 			mhip->ip_len = len;
744924Swnj 			mhip->ip_off |= IP_MF;
754496Swnj 		}
764924Swnj 		mh->m_next = m_copy(m, off, len);
774924Swnj 		if (mh->m_next == 0) {
78*4967Swnj 			(void) m_free(mh);
794924Swnj 			goto bad;
804674Swnj 		}
814952Swnj 		ip_send(mhip);
824924Swnj 	}
834924Swnj bad:
844924Swnj 	m_freem(m);
854924Swnj }
864924Swnj 
874924Swnj /*
884924Swnj  * Copy options from ip to jp.
894952Swnj  * If off is 0 all options are copied
904924Swnj  * otherwise copy selectively.
914924Swnj  */
924924Swnj ip_optcopy(ip, jp, off)
934924Swnj 	struct ip *ip, *jp;
944924Swnj 	int off;
954924Swnj {
964924Swnj 	register u_char *cp, *dp;
974924Swnj 	int opt, optlen, cnt;
984924Swnj 
994952Swnj COUNT(IP_OPTCOPY);
1004924Swnj 	cp = (u_char *)(ip + 1);
1014924Swnj 	dp = (u_char *)(jp + 1);
1024924Swnj 	cnt = (ip->ip_hl << 2) - sizeof (struct ip);
1034924Swnj 	for (; cnt > 0; cnt -= optlen, cp += optlen) {
1044924Swnj 		opt = cp[0];
1054924Swnj 		if (opt == IPOPT_EOL)
1064924Swnj 			break;
1074924Swnj 		if (opt == IPOPT_NOP)
1084924Swnj 			optlen = 1;
1094924Swnj 		else
1104924Swnj 			optlen = cp[1];
1114924Swnj 		if (optlen > cnt)			/* XXX */
1124924Swnj 			optlen = cnt;			/* XXX */
1134924Swnj 		if (off == 0 || IPOPT_COPIED(opt)) {
1144952Swnj 			bcopy((caddr_t)cp, (caddr_t)dp, (unsigned)optlen);
1154924Swnj 			dp += optlen;
1164674Swnj 		}
1174545Swnj 	}
1184924Swnj 	for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++)
1194924Swnj 		*dp++ = IPOPT_EOL;
1204924Swnj 	return (optlen);
1214496Swnj }
1224496Swnj 
1234952Swnj /* REST OF CODE HERE IS GARBAGE */
1244952Swnj 
1254693Swnj ip_send(ip)
1264924Swnj 	register struct ip *ip;
1274496Swnj {
1284496Swnj 	register struct mbuf *m;
1294496Swnj 	register struct imp *l;
1304924Swnj 	int hlen = ip->ip_hl << 2;
1314545Swnj 	int s;
1324496Swnj COUNT(IP_SEND);
1334496Swnj 
1344693Swnj 	m = dtom(ip);
1354908Swnj 	l = (struct imp *)(mtod(m, caddr_t) - L1822);
1364693Swnj 	l->i_shost = ip->ip_src.s_host;
1374693Swnj 	l->i_dhost = ip->ip_dst.s_host;
1384496Swnj 	l->i_type = IPTYPE;
1394693Swnj 	ip->ip_sum = 0;
1404908Swnj 	ip->ip_len = htons((u_short)ip->ip_len);
1414693Swnj 	ip->ip_id = htons(ip->ip_id);
1424908Swnj 	ip->ip_off = htons((u_short)ip->ip_off);
1434924Swnj 	ip->ip_sum = inet_cksum(m, hlen);
1444693Swnj 	m->m_off -= L1822;
1454496Swnj 	m->m_len += L1822;
1464545Swnj 	m->m_act = NULL;
1474545Swnj #ifndef IMPLOOP
1484662Swnj 	s = splimp();
1494545Swnj 	if (imp_stat.outq_head != NULL)
1504545Swnj 		imp_stat.outq_tail->m_act = m;
1514545Swnj 	else
1524545Swnj 		imp_stat.outq_head = m;
1534545Swnj 	imp_stat.outq_tail = m;
1544545Swnj 	splx(s);
1554545Swnj 	if (!imp_stat.outactive)
1564688Swnj 		enstart(0);
1574545Swnj #else
1584545Swnj 	if (imp_stat.inq_head != NULL)
1594545Swnj 		imp_stat.inq_tail->m_act = m;
1604545Swnj 	else
1614545Swnj 		imp_stat.inq_head = m;
1624545Swnj 	imp_stat.inq_tail = m;
1634724Swnj 	setsoftnet();
1644545Swnj #endif IMPLOOP
1654496Swnj }
1664952Swnj 
1674952Swnj /* END GARBAGE */
168