X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/d52566dd74ca6e30b219fecade6f5ff449867095..1e977657a8a11e8be94e4f9331b3d2fff778c62d:/usr/src/sys/netinet/ip_output.c?ds=inline diff --git a/usr/src/sys/netinet/ip_output.c b/usr/src/sys/netinet/ip_output.c index 291331f967..68a9d19cdf 100644 --- a/usr/src/sys/netinet/ip_output.c +++ b/usr/src/sys/netinet/ip_output.c @@ -1,126 +1,156 @@ -/* ip_output.c 1.11 81/11/08 */ +/* ip_output.c 1.26 82/03/15 */ #include "../h/param.h" #include "../h/mbuf.h" #include "../h/mtpr.h" #include "../h/socket.h" -#include "../net/inet_cksum.h" -#include "../net/inet.h" -#include "../net/inet_systm.h" -#include "../net/imp.h" -#include "../net/inet_host.h" +#include "../h/socketvar.h" +#include "../net/in.h" +#include "../net/in_systm.h" +#include "../net/if.h" #include "../net/ip.h" -#include "../net/tcp.h" +#include "../net/ip_var.h" -ip_output(mp) - struct mbuf *mp; +ip_output(m, opt, allowbroadcast) + struct mbuf *m; + struct mbuf *opt; + int allowbroadcast; { - register i, rnd; - register struct mbuf *m, *n; - register struct ip *p; - struct mbuf *mm; - int hlen, adj, max, len, off; + register struct ip *ip = mtod(m, struct ip *); + register struct ifnet *ifp; + int len, hlen = sizeof (struct ip), off; COUNT(IP_OUTPUT); - p = mtod(mp, struct ip *); - hlen = sizeof (struct ip); + if (opt) /* XXX */ + (void) m_free(opt); /* XXX */ + /* + * Fill in IP header. + */ + ip->ip_v = IPVERSION; + ip->ip_hl = hlen >> 2; + ip->ip_off &= IP_DF; + ip->ip_id = htons(ip_id++); /* - * Fill in and byte swap ip header. + * Find interface for this packet. */ - p->ip_v = IPVERSION; - p->ip_hl = hlen >> 2; - p->ip_off = 0 | (p->ip_off & IP_DF); - p->ip_ttl = MAXTTL; - p->ip_id = ip_id++; + ifp = if_ifonnetof(ip->ip_dst); + if (ifp == 0) { + ifp = if_gatewayfor(ip->ip_dst); + if (ifp == 0) + goto bad; + } + if (!allowbroadcast && ifp->if_broadaddr.s_addr != 0 && + ifp->if_broadaddr.s_addr == ip->ip_dst.s_addr) + goto bad; - if (p->ip_len <= MTU) - return (ip_send(p)); - if (p->ip_off & IP_DF) - return (0); - max = MTU - hlen; - len = p->ip_len - hlen; - off = 0; - m = mp; - while (len > 0) { - p->ip_off |= off >> 3; - i = -hlen; - while (m != NULL) { - i += m->m_len; - if (i > max) - break; - n = m; - m = m->m_next; - } - if (i < max || m == NULL) { - p->ip_off = p->ip_off &~ IP_MF; - p->ip_len = i + hlen; - return (ip_send(p)); + /* + * If small enough for interface, can just send directly. + */ + if (ip->ip_len <= ifp->if_mtu) { +#if vax + ip->ip_len = htons((u_short)ip->ip_len); + ip->ip_off = htons((u_short)ip->ip_off); +#endif + ip->ip_sum = 0; + ip->ip_sum = in_cksum(m, hlen); + return ((*ifp->if_output)(ifp, m, PF_INET)); + } + + /* + * Too large for interface; fragment if possible. + * Must be able to put at least 8 bytes per fragment. + */ + if (ip->ip_off & IP_DF) + goto bad; + len = (ifp->if_mtu - hlen) &~ 7; + if (len < 8) + goto bad; + + /* + * Discard IP header from logical mbuf for m_copy's sake. + * Loop through length of segment, make a copy of each + * part and output. + */ + m->m_len -= sizeof (struct ip); + m->m_off += sizeof (struct ip); + for (off = 0; off < ip->ip_len-hlen; off += len) { + struct mbuf *mh = m_get(M_DONTWAIT); + struct ip *mhip; + + if (mh == 0) + goto bad; + mh->m_off = MMAXOFF - hlen; + mhip = mtod(mh, struct ip *); + *mhip = *ip; + if (hlen > sizeof (struct ip)) { + int olen = ip_optcopy(ip, mhip, off); + mh->m_len = sizeof (struct ip) + olen; + } else + mh->m_len = sizeof (struct ip); + mhip->ip_off = off >> 3; + if (off + len >= ip->ip_len-hlen) + len = mhip->ip_len = ip->ip_len - hlen - off; + else { + mhip->ip_len = len; + mhip->ip_off |= IP_MF; } - if ((mm = m_get(1)) == NULL) /* no more bufs */ - return(0); - p->ip_off |= IP_MF; - i -= m->m_len; - rnd = i & ~7; - adj = i - rnd; - p->ip_len = rnd + hlen; - n->m_next = NULL; - mm->m_next = m; - m = mm; - m->m_off = MMAXOFF - hlen - adj; - m->m_len = hlen + adj; - bcopy(p, (caddr_t)((int)m + m->m_off), hlen); - if (adj) { - n->m_len -= adj; - bcopy((caddr_t)((int)n + n->m_len + n->m_off), - (caddr_t)((int)m + m->m_off + hlen), adj); + mhip->ip_len += sizeof (struct ip); +#if vax + mhip->ip_len = htons((u_short)mhip->ip_len); +#endif + mh->m_next = m_copy(m, off, len); + if (mh->m_next == 0) { + (void) m_free(mh); + goto bad; } - ip_send(p); - p = (struct ip *)((int)m + m->m_off); - len -= rnd; - off += rnd; +#if vax + mhip->ip_off = htons((u_short)mhip->ip_off); +#endif + mhip->ip_sum = 0; + mhip->ip_sum = in_cksum(mh, hlen); + if ((*ifp->if_output)(ifp, mh, PF_INET) == 0) + goto bad; } + m_freem(m); + return (1); +bad: + m_freem(m); + return (0); } -ip_send(ip) - register struct ip *ip; /* known to be r11 */ +/* + * 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 struct mbuf *m; - register struct imp *l; - register int hlen = ip->ip_hl << 2; - int s; -COUNT(IP_SEND); + register u_char *cp, *dp; + int opt, optlen, cnt; - m = dtom(ip); - l = (struct imp *)((int)m + m->m_off - L1822); - l->i_shost = ip->ip_src.s_host; - l->i_dhost = ip->ip_dst.s_host; - l->i_type = IPTYPE; - ip->ip_sum = 0; - ip->ip_len = htons(ip->ip_len); - ip->ip_id = htons(ip->ip_id); - ip->ip_off = htons(ip->ip_off); - CKSUM_IPSET(m, ip, r11, hlen); - m->m_off -= L1822; - m->m_len += L1822; - m->m_act = NULL; -#ifndef IMPLOOP - s = splimp(); - if (imp_stat.outq_head != NULL) - imp_stat.outq_tail->m_act = m; - else - imp_stat.outq_head = m; - imp_stat.outq_tail = m; - splx(s); - if (!imp_stat.outactive) - enstart(0); -#else - if (imp_stat.inq_head != NULL) - imp_stat.inq_tail->m_act = m; - else - imp_stat.inq_head = m; - imp_stat.inq_tail = m; - setsoftnet(); -#endif IMPLOOP - return (1); +COUNT(IP_OPTCOPY); + 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[1]; + 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); }