X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/ae348eeadb89e419b478405d4e044baf8c26b383..6e7edb25cc39d3c7a292ffbce29991ab528249e3:/usr/src/sys/netinet/ip_output.c diff --git a/usr/src/sys/netinet/ip_output.c b/usr/src/sys/netinet/ip_output.c index e0b6060f8e..ee21021f4e 100644 --- a/usr/src/sys/netinet/ip_output.c +++ b/usr/src/sys/netinet/ip_output.c @@ -1,124 +1,216 @@ -/* ip_output.c 1.7 81/10/31 */ +/* ip_output.c 1.40 82/10/20 */ #include "../h/param.h" #include "../h/mbuf.h" +#include "../vax/mtpr.h" #include "../h/socket.h" -#include "../inet/inet.h" -#include "../inet/inet_systm.h" -#include "../inet/imp.h" -#include "../inet/inet_host.h" -#include "../inet/ip.h" -#include "../inet/tcp.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 -ip_output(mp) - struct mbuf *mp; +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; + 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; -COUNT(IP_OUTPUT); - p = (struct ip *)((int)mp + mp->m_off); /* -> ip header */ - hlen = sizeof (struct ip); /* header length */ + 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. + * 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. */ - 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++; + if (ip->ip_src.s_addr == 0) + ip->ip_src.s_addr = + ((struct sockaddr_in *)&ifp->if_addr)->sin_addr.s_addr; - 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; + /* + * Have interface for packet. Allow + * broadcasts only by authorized users. + */ + if (!allowbroadcast && (ifp->if_flags & IFF_BROADCAST)) { + struct sockaddr_in *sin; + + sin = (struct sockaddr_in *)&ifp->if_broadaddr; + if (sin->sin_addr.s_addr == ip->ip_dst.s_addr) { + error = EACCES; + goto bad; } - 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 || 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; + } + + /* + * 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; + } + + /* + * 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; } - 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 || 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; } - ip_send(p); - p = (struct ip *)((int)m + m->m_off); - len -= rnd; - off += rnd; +#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; } + 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) - struct ip *p; +/* + * 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; - int s; -COUNT(IP_SEND); + register u_char *cp, *dp; + int opt, optlen, cnt; - m = dtom(p); - l = (struct imp *)((int)m + m->m_off - L1822); - 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; - p->ip_sum = 0; - p->ip_len = htons(p->ip_len); - p->ip_id = htons(p->ip_id); - p->ip_off = htons(p->ip_off); - p->ip_sum = cksum(m, sizeof(struct ip)); - m->m_off -= L1822; /* -> 1822 leader */ - 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; -#endif IMPLOOP - return (1); + 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); }