X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/2e56471e6b4cf3dae6d40cdec21817677d3f6c46..6e7edb25cc39d3c7a292ffbce29991ab528249e3:/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 41ecfad71a..ee21021f4e 100644 --- a/usr/src/sys/netinet/ip_output.c +++ b/usr/src/sys/netinet/ip_output.c @@ -1,204 +1,216 @@ -/* ip_output.c 1.5 81/10/26 */ +/* ip_output.c 1.40 82/10/20 */ #include "../h/param.h" -#include "../bbnnet/net.h" -#include "../bbnnet/mbuf.h" -#include "../bbnnet/host.h" -#include "../bbnnet/tcp.h" -#include "../bbnnet/ip.h" -#include "../bbnnet/imp.h" -#include "../bbnnet/ucb.h" - -ip_output(mp) - struct mbuf *mp; +#include "../h/mbuf.h" +#include "../vax/mtpr.h" +#include "../h/socket.h" +#include "../h/socketvar.h" +#include "../netinet/in.h" +#include "../netinet/in_systm.h" +#include "../net/if.h" +#include "../netinet/ip.h" +#include "../netinet/ip_var.h" +#include "../net/route.h" +#include + +int ipnorouteprint = 0; + +ip_output(m, opt, ro, allowbroadcast) + struct mbuf *m; + struct mbuf *opt; + struct route *ro; + int allowbroadcast; { - register i, rnd; - register struct mbuf *m, *n; - register struct ip *p; - struct mbuf *mm; - int hlen, adj, max, len, off; - -COUNT(IP_OUTPUT); - p = (struct ip *)((int)mp + mp->m_off); /* -> ip header */ - hlen = sizeof (struct ip); /* header length */ - + register struct ip *ip = mtod(m, struct ip *); + register struct ifnet *ifp; + int len, hlen = sizeof (struct ip), off, error = 0; + struct route iproute; + struct sockaddr *dst; + + if (opt) /* XXX */ + (void) m_free(opt); /* XXX */ /* - * Fill in and byte swap ip header. + * Fill in IP header. */ - 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 = netcb.n_ip_cnt++; - - if (p->ip_len > MTU) { /* must fragment */ - if (p->ip_off & ip_df) - return (0); - max = MTU - hlen; /* maximum data length in fragment */ - len = p->ip_len - hlen; /* data length */ - off = 0; /* fragment offset */ - m = mp; - - while (len > 0) { - - /* correct the header */ - - p->ip_off |= off >> 3; - - /* find the end of the fragment */ - - i = -hlen; - while (m != NULL) { - i += m->m_len; - if (i > max) - break; - n = m; - m = m->m_next; - } - - if (i < max || m == NULL) { /* last fragment */ - p->ip_off = p->ip_off & ~ip_mf; - p->ip_len = i + hlen; - break; - - } else { /* more fragments */ - - /* allocate header mbuf for next fragment */ - - if ((mm = m_get(1)) == NULL) /* no more bufs */ - return(0); - - p->ip_off |= ip_mf; - - /* terminate fragment at 8 byte boundary (round down) */ - - i -= m->m_len; - rnd = i & ~7; /* fragment length */ - adj = i - rnd; /* leftover in mbuf */ - p->ip_len = rnd + hlen; - - /* setup header for next fragment and - append remaining fragment data */ + ip->ip_v = IPVERSION; + ip->ip_hl = hlen >> 2; + ip->ip_off &= IP_DF; + ip->ip_id = htons(ip_id++); - n->m_next = NULL; - mm->m_next = m; - m = mm; - m->m_off = MMAXOFF - hlen - adj; - m->m_len = hlen + adj; - - /* copy old header to new */ + /* + * Route packet. + */ + if (ro == 0) { + ro = &iproute; + bzero((caddr_t)ro, sizeof (*ro)); + } + dst = &ro->ro_dst; + if (ro->ro_rt == 0) { + ro->ro_dst.sa_family = AF_INET; + ((struct sockaddr_in *)&ro->ro_dst)->sin_addr = ip->ip_dst; + /* + * If routing to interface only, short circuit routing lookup. + */ + if (ro == &routetoif) { + /* check ifp is AF_INET??? */ + ifp = if_ifonnetof(in_netof(ip->ip_dst)); + if (ifp == 0) + goto unreachable; + goto gotif; + } + rtalloc(ro); + } + if (ro->ro_rt == 0 || (ifp = ro->ro_rt->rt_ifp) == 0) + goto unreachable; + ro->ro_rt->rt_use++; + if (ro->ro_rt->rt_flags & RTF_GATEWAY) + dst = &ro->ro_rt->rt_gateway; +gotif: + /* + * If source address not specified yet, use address + * of outgoing interface. + */ + if (ip->ip_src.s_addr == 0) + ip->ip_src.s_addr = + ((struct sockaddr_in *)&ifp->if_addr)->sin_addr.s_addr; - bcopy(p, (caddr_t)((int)m + m->m_off), hlen); + /* + * Have interface for packet. Allow + * broadcasts only by authorized users. + */ + if (!allowbroadcast && (ifp->if_flags & IFF_BROADCAST)) { + struct sockaddr_in *sin; - /* copy leftover data from previous frag */ + sin = (struct sockaddr_in *)&ifp->if_broadaddr; + if (sin->sin_addr.s_addr == ip->ip_dst.s_addr) { + error = EACCES; + goto bad; + } + } - 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); - } - } + /* + * If small enough for interface, can just send directly. + */ + if (ip->ip_len <= ifp->if_mtu) { +#if vax || pdp11 || ns16032 + 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); + error = (*ifp->if_output)(ifp, m, dst); + goto done; + } - ip_send(p); /* pass frag to local net level */ + /* + * Too large for interface; fragment if possible. + * Must be able to put at least 8 bytes per fragment. + */ + if (ip->ip_off & IP_DF) { + error = EMSGSIZE; + goto bad; + } + len = (ifp->if_mtu - hlen) &~ 7; + if (len < 8) { + error = EMSGSIZE; + goto bad; + } - p = (struct ip *)((int)m + m->m_off); /* -> new hdr */ - len -= rnd; - off += rnd; + /* + * 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) { + error = ENOBUFS; + 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; } + mhip->ip_len += sizeof (struct ip); +#if vax || pdp11 || ns16032 + 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); + error = ENOBUFS; /* ??? */ + goto bad; + } +#if vax || pdp11 || ns16032 + mhip->ip_off = htons((u_short)mhip->ip_off); +#endif + mhip->ip_sum = 0; + mhip->ip_sum = in_cksum(mh, hlen); + if (error = (*ifp->if_output)(ifp, mh, dst)) + break; } - - return(ip_send(p)); /* pass datagram to local net level */ + m_freem(m); + goto done; + +unreachable: + if (ipnorouteprint) + printf("no route to %x (from %x, len %d)\n", + ip->ip_dst.s_addr, ip->ip_src.s_addr, ip->ip_len); + error = ENETUNREACH; +bad: + m_freem(m); +done: + if (ro == &iproute && ro->ro_rt) + RTFREE(ro->ro_rt); + return (error); } -ip_send(p) /* format header and send message to 1822 level */ -struct ip *p; -{ - register struct mbuf *m; - register struct imp *l; - int s; -COUNT(IP_SEND); - - m = dtom(p); /* ->header mbuf */ - - /* set up 1822 leader fields for transmit */ - - l = (struct imp *)((int)m + m->m_off - L1822); /* - l->i_hst = p->ip_dst.s_host; - l->i_impno = p->ip_dst.s_imp; - l->i_mlen = p->ip_len + L1822; - l->i_link = IPLINK; - l->i_type = 0; - l->i_htype = 0; - l->i_stype = 0; -*/ - if ((l->i_shost = p->ip_src.s_host) == 0) - l->i_shost = 253; - if ((l->i_dhost = p->ip_dst.s_host) == 0) - l->i_dhost = 253; - l->i_type = IPTYPE; - - /* finish ip leader by calculating checksum and doing - necessary byte-swapping */ - - p->ip_sum = 0; - ip_bswap(p); - p->ip_sum = cksum(m, sizeof(struct ip)); - - m->m_off -= L1822; /* -> 1822 leader */ - m->m_len += L1822; - - m->m_act = NULL; - -#ifndef IMPLOOP - - /* put output message on queue */ - - s = spl_imp(); - 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 no outstanding output, start some */ - - if (!imp_stat.outactive) - imp_output(0); - -#else - /* software looping: put msg chain on input queue */ - - if (imp_stat.inq_head != NULL) - imp_stat.inq_tail->m_act = m; - else - imp_stat.inq_head = m; - imp_stat.inq_tail = m; - -#endif IMPLOOP - return (1); -} - -ip_setup(up, m, len) /* setup an ip header for raw write */ -register struct ucb *up; -register struct mbuf *m; -int len; + * 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 ip *ip; -COUNT(IP_SETUP); - - m->m_off = MMAXOFF - sizeof(struct ip); - m->m_len = sizeof(struct ip); - - ip = (struct ip *)((int)m + m->m_off); - - ip->ip_tos = 0; - ip->ip_id = 0; - ip->ip_off = 0; - ip->ip_p = up->uc_lolink; - ip->ip_len = len + sizeof(struct ip); - - ip->ip_src.s_addr = netcb.n_lhost.s_addr; - ip->ip_dst.s_addr = up->uc_host->h_addr.s_addr; + 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[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); }