1*18376Skarels /* ip_input.c 6.9 85/03/18 */ 24571Swnj 317060Sbloom #include "param.h" 417060Sbloom #include "systm.h" 517060Sbloom #include "mbuf.h" 617060Sbloom #include "domain.h" 717060Sbloom #include "protosw.h" 817060Sbloom #include "socket.h" 917060Sbloom #include "errno.h" 1017060Sbloom #include "time.h" 1117060Sbloom #include "kernel.h" 128695Sroot 138695Sroot #include "../net/if.h" 148695Sroot #include "../net/route.h" 1510892Ssam 1617060Sbloom #include "in.h" 1717060Sbloom #include "in_pcb.h" 1817060Sbloom #include "in_systm.h" 19*18376Skarels #include "in_var.h" 2017060Sbloom #include "ip.h" 2117060Sbloom #include "ip_var.h" 2217060Sbloom #include "ip_icmp.h" 2317060Sbloom #include "tcp.h" 244495Swnj 254898Swnj u_char ip_protox[IPPROTO_MAX]; 266210Swnj int ipqmaxlen = IFQ_MAXLEN; 27*18376Skarels struct in_ifaddr *in_ifaddr; /* first inet address */ 284898Swnj 294801Swnj /* 305172Swnj * IP initialization: fill in IP protocol switch table. 315161Swnj * All protocols not implemented in kernel go to raw IP protocol handler. 324801Swnj */ 334801Swnj ip_init() 344801Swnj { 354898Swnj register struct protosw *pr; 364898Swnj register int i; 374495Swnj 384898Swnj pr = pffindproto(PF_INET, IPPROTO_RAW); 394898Swnj if (pr == 0) 404898Swnj panic("ip_init"); 414898Swnj for (i = 0; i < IPPROTO_MAX; i++) 429030Sroot ip_protox[i] = pr - inetsw; 439030Sroot for (pr = inetdomain.dom_protosw; 4417551Skarels pr < inetdomain.dom_protoswNPROTOSW; pr++) 4516990Skarels if (pr->pr_domain->dom_family == PF_INET && 464898Swnj pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW) 479030Sroot ip_protox[pr->pr_protocol] = pr - inetsw; 484801Swnj ipq.next = ipq.prev = &ipq; 498172Sroot ip_id = time.tv_sec & 0xffff; 506210Swnj ipintrq.ifq_maxlen = ipqmaxlen; 514801Swnj } 524801Swnj 534898Swnj u_char ipcksum = 1; 544640Swnj struct ip *ip_reass(); 556338Ssam struct sockaddr_in ipaddr = { AF_INET }; 564640Swnj 574640Swnj /* 584640Swnj * Ip input routine. Checksum and byte swap header. If fragmented 594640Swnj * try to reassamble. If complete and fragment queue exists, discard. 604640Swnj * Process options. Pass to next level. 614640Swnj */ 625084Swnj ipintr() 634495Swnj { 644923Swnj register struct ip *ip; 655084Swnj register struct mbuf *m; 668597Sroot struct mbuf *m0; 674640Swnj register int i; 684495Swnj register struct ipq *fp; 69*18376Skarels register struct in_ifaddr *ia; 705084Swnj int hlen, s; 714495Swnj 725084Swnj next: 734640Swnj /* 745084Swnj * Get next datagram off input queue and get IP header 755084Swnj * in first mbuf. 764640Swnj */ 775084Swnj s = splimp(); 785084Swnj IF_DEQUEUE(&ipintrq, m); 795084Swnj splx(s); 805218Swnj if (m == 0) 815084Swnj return; 825306Sroot if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct ip)) && 8311232Ssam (m = m_pullup(m, sizeof (struct ip))) == 0) { 8411232Ssam ipstat.ips_toosmall++; 8511232Ssam goto next; 8611232Ssam } 874640Swnj ip = mtod(m, struct ip *); 88*18376Skarels hlen = ip->ip_hl << 2; 89*18376Skarels if (hlen < 10) { /* minimum header length */ 90*18376Skarels ipstat.ips_badhlen++; 91*18376Skarels goto next; 92*18376Skarels } 93*18376Skarels if (hlen > m->m_len) { 9411232Ssam if ((m = m_pullup(m, hlen)) == 0) { 9511232Ssam ipstat.ips_badhlen++; 9611232Ssam goto next; 9711232Ssam } 985161Swnj ip = mtod(m, struct ip *); 995161Swnj } 1004951Swnj if (ipcksum) 1015217Swnj if (ip->ip_sum = in_cksum(m, hlen)) { 1024951Swnj ipstat.ips_badsum++; 1034951Swnj goto bad; 1044495Swnj } 1054951Swnj 1064951Swnj /* 1074951Swnj * Convert fields to host representation. 1084951Swnj */ 1094907Swnj ip->ip_len = ntohs((u_short)ip->ip_len); 11011232Ssam if (ip->ip_len < hlen) { 11111232Ssam ipstat.ips_badlen++; 11211232Ssam goto bad; 11311232Ssam } 1144640Swnj ip->ip_id = ntohs(ip->ip_id); 1154951Swnj ip->ip_off = ntohs((u_short)ip->ip_off); 1164495Swnj 1174543Swnj /* 1184640Swnj * Check that the amount of data in the buffers 1194640Swnj * is as at least much as the IP header would have us expect. 1204640Swnj * Trim mbufs if longer than we expect. 1214640Swnj * Drop packet if shorter than we expect. 1224543Swnj */ 1236475Sroot i = -ip->ip_len; 1245161Swnj m0 = m; 1256475Sroot for (;;) { 1264495Swnj i += m->m_len; 1276475Sroot if (m->m_next == 0) 1286475Sroot break; 1296475Sroot m = m->m_next; 1306088Sroot } 1316475Sroot if (i != 0) { 1326475Sroot if (i < 0) { 1335161Swnj ipstat.ips_tooshort++; 13417358Skarels m = m0; 1354951Swnj goto bad; 1365161Swnj } 1376475Sroot if (i <= m->m_len) 1386475Sroot m->m_len -= i; 1396475Sroot else 1406475Sroot m_adj(m0, -i); 1414495Swnj } 1426475Sroot m = m0; 1434495Swnj 1444640Swnj /* 1454640Swnj * Process options and, if not destined for us, 1466583Ssam * ship it on. ip_dooptions returns 1 when an 1476583Ssam * error was detected (causing an icmp message 1486583Ssam * to be sent). 1494640Swnj */ 1506583Ssam if (hlen > sizeof (struct ip) && ip_dooptions(ip)) 1516583Ssam goto next; 1526210Swnj 1536338Ssam /* 154*18376Skarels * Check our list of addresses, to see if the packet is for us. 1556338Ssam */ 156*18376Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) { 157*18376Skarels #define satosin(sa) ((struct sockaddr_in *)(sa)) 1586338Ssam 159*18376Skarels if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr) 160*18376Skarels break; 161*18376Skarels if ((ia->ia_ifp->if_flags & IFF_BROADCAST) && 162*18376Skarels satosin(&ia->ia_broadaddr)->sin_addr.s_addr == 163*18376Skarels ip->ip_dst.s_addr) 164*18376Skarels break; 165*18376Skarels /* 166*18376Skarels * Look for all-0's host part (old broadcast addr). 167*18376Skarels */ 168*18376Skarels if ((ia->ia_ifp->if_flags & IFF_BROADCAST) && 169*18376Skarels ia->ia_subnet == ntohl(ip->ip_dst.s_addr)) 170*18376Skarels break; 1716338Ssam } 172*18376Skarels if (ia == (struct in_ifaddr *)0) { 1736583Ssam ip_forward(ip); 1745084Swnj goto next; 1754543Swnj } 1764495Swnj 1774640Swnj /* 1784640Swnj * Look for queue of fragments 1794640Swnj * of this datagram. 1804640Swnj */ 1814640Swnj for (fp = ipq.next; fp != &ipq; fp = fp->next) 1824640Swnj if (ip->ip_id == fp->ipq_id && 1834640Swnj ip->ip_src.s_addr == fp->ipq_src.s_addr && 1844640Swnj ip->ip_dst.s_addr == fp->ipq_dst.s_addr && 1854640Swnj ip->ip_p == fp->ipq_p) 1864640Swnj goto found; 1874640Swnj fp = 0; 1884640Swnj found: 1894495Swnj 1904640Swnj /* 1914640Swnj * Adjust ip_len to not reflect header, 1924640Swnj * set ip_mff if more fragments are expected, 1934640Swnj * convert offset of this to bytes. 1944640Swnj */ 1954640Swnj ip->ip_len -= hlen; 1964898Swnj ((struct ipasfrag *)ip)->ipf_mff = 0; 1974640Swnj if (ip->ip_off & IP_MF) 1984898Swnj ((struct ipasfrag *)ip)->ipf_mff = 1; 1994640Swnj ip->ip_off <<= 3; 2004495Swnj 2014640Swnj /* 2024640Swnj * If datagram marked as having more fragments 2034640Swnj * or if this is not the first fragment, 2044640Swnj * attempt reassembly; if it succeeds, proceed. 2054640Swnj */ 2064898Swnj if (((struct ipasfrag *)ip)->ipf_mff || ip->ip_off) { 2074898Swnj ip = ip_reass((struct ipasfrag *)ip, fp); 2084640Swnj if (ip == 0) 2095084Swnj goto next; 2104640Swnj hlen = ip->ip_hl << 2; 2114640Swnj m = dtom(ip); 2124640Swnj } else 2134640Swnj if (fp) 21410735Ssam ip_freef(fp); 2154951Swnj 2164951Swnj /* 2174951Swnj * Switch out to protocol's input routine. 2184951Swnj */ 2199030Sroot (*inetsw[ip_protox[ip->ip_p]].pr_input)(m); 2205084Swnj goto next; 2214951Swnj bad: 2224951Swnj m_freem(m); 2235084Swnj goto next; 2244640Swnj } 2254495Swnj 2264640Swnj /* 2274640Swnj * Take incoming datagram fragment and try to 2284951Swnj * reassemble it into whole datagram. If a chain for 2294640Swnj * reassembly of this datagram already exists, then it 2304640Swnj * is given as fp; otherwise have to make a chain. 2314640Swnj */ 2324640Swnj struct ip * 2334640Swnj ip_reass(ip, fp) 2344898Swnj register struct ipasfrag *ip; 2354640Swnj register struct ipq *fp; 2364640Swnj { 2374640Swnj register struct mbuf *m = dtom(ip); 2384898Swnj register struct ipasfrag *q; 2394640Swnj struct mbuf *t; 2404640Swnj int hlen = ip->ip_hl << 2; 2414640Swnj int i, next; 2424543Swnj 2434640Swnj /* 2444640Swnj * Presence of header sizes in mbufs 2454640Swnj * would confuse code below. 2464640Swnj */ 2474640Swnj m->m_off += hlen; 2484640Swnj m->m_len -= hlen; 2494495Swnj 2504640Swnj /* 2514640Swnj * If first fragment to arrive, create a reassembly queue. 2524640Swnj */ 2534640Swnj if (fp == 0) { 2549641Ssam if ((t = m_get(M_WAIT, MT_FTABLE)) == NULL) 2554640Swnj goto dropfrag; 2564640Swnj fp = mtod(t, struct ipq *); 2574640Swnj insque(fp, &ipq); 2584640Swnj fp->ipq_ttl = IPFRAGTTL; 2594640Swnj fp->ipq_p = ip->ip_p; 2604640Swnj fp->ipq_id = ip->ip_id; 2614898Swnj fp->ipq_next = fp->ipq_prev = (struct ipasfrag *)fp; 2624898Swnj fp->ipq_src = ((struct ip *)ip)->ip_src; 2634898Swnj fp->ipq_dst = ((struct ip *)ip)->ip_dst; 2645161Swnj q = (struct ipasfrag *)fp; 2655161Swnj goto insert; 2664640Swnj } 2674495Swnj 2684640Swnj /* 2694640Swnj * Find a segment which begins after this one does. 2704640Swnj */ 2714898Swnj for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next) 2724640Swnj if (q->ip_off > ip->ip_off) 2734640Swnj break; 2744495Swnj 2754640Swnj /* 2764640Swnj * If there is a preceding segment, it may provide some of 2774640Swnj * our data already. If so, drop the data from the incoming 2784640Swnj * segment. If it provides all of our data, drop us. 2794640Swnj */ 2804898Swnj if (q->ipf_prev != (struct ipasfrag *)fp) { 2814898Swnj i = q->ipf_prev->ip_off + q->ipf_prev->ip_len - ip->ip_off; 2824640Swnj if (i > 0) { 2834640Swnj if (i >= ip->ip_len) 2844640Swnj goto dropfrag; 2854640Swnj m_adj(dtom(ip), i); 2864640Swnj ip->ip_off += i; 2874640Swnj ip->ip_len -= i; 2884640Swnj } 2894640Swnj } 2904543Swnj 2914640Swnj /* 2924640Swnj * While we overlap succeeding segments trim them or, 2934640Swnj * if they are completely covered, dequeue them. 2944640Swnj */ 2954898Swnj while (q != (struct ipasfrag *)fp && ip->ip_off + ip->ip_len > q->ip_off) { 2964640Swnj i = (ip->ip_off + ip->ip_len) - q->ip_off; 2974640Swnj if (i < q->ip_len) { 2984640Swnj q->ip_len -= i; 2996256Sroot q->ip_off += i; 3004640Swnj m_adj(dtom(q), i); 3014640Swnj break; 3024495Swnj } 3034898Swnj q = q->ipf_next; 3044898Swnj m_freem(dtom(q->ipf_prev)); 3054898Swnj ip_deq(q->ipf_prev); 3064543Swnj } 3074495Swnj 3085161Swnj insert: 3094640Swnj /* 3104640Swnj * Stick new segment in its place; 3114640Swnj * check for complete reassembly. 3124640Swnj */ 3134898Swnj ip_enq(ip, q->ipf_prev); 3144640Swnj next = 0; 3154898Swnj for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next) { 3164640Swnj if (q->ip_off != next) 3174640Swnj return (0); 3184640Swnj next += q->ip_len; 3194640Swnj } 3204898Swnj if (q->ipf_prev->ipf_mff) 3214640Swnj return (0); 3224495Swnj 3234640Swnj /* 3244640Swnj * Reassembly is complete; concatenate fragments. 3254640Swnj */ 3264640Swnj q = fp->ipq_next; 3274640Swnj m = dtom(q); 3284640Swnj t = m->m_next; 3294640Swnj m->m_next = 0; 3304640Swnj m_cat(m, t); 3316298Swnj q = q->ipf_next; 3326298Swnj while (q != (struct ipasfrag *)fp) { 3336298Swnj t = dtom(q); 3346298Swnj q = q->ipf_next; 3356298Swnj m_cat(m, t); 3366298Swnj } 3374495Swnj 3384640Swnj /* 3394640Swnj * Create header for new ip packet by 3404640Swnj * modifying header of first packet; 3414640Swnj * dequeue and discard fragment reassembly header. 3424640Swnj * Make header visible. 3434640Swnj */ 3444640Swnj ip = fp->ipq_next; 3454640Swnj ip->ip_len = next; 3464898Swnj ((struct ip *)ip)->ip_src = fp->ipq_src; 3474898Swnj ((struct ip *)ip)->ip_dst = fp->ipq_dst; 3484640Swnj remque(fp); 3494907Swnj (void) m_free(dtom(fp)); 3504640Swnj m = dtom(ip); 3514898Swnj m->m_len += sizeof (struct ipasfrag); 3524898Swnj m->m_off -= sizeof (struct ipasfrag); 3534898Swnj return ((struct ip *)ip); 3544495Swnj 3554640Swnj dropfrag: 3564640Swnj m_freem(m); 3574640Swnj return (0); 3584495Swnj } 3594495Swnj 3604640Swnj /* 3614640Swnj * Free a fragment reassembly header and all 3624640Swnj * associated datagrams. 3634640Swnj */ 3644640Swnj ip_freef(fp) 3654640Swnj struct ipq *fp; 3664495Swnj { 36710735Ssam register struct ipasfrag *q, *p; 3684495Swnj 36910735Ssam for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = p) { 37010735Ssam p = q->ipf_next; 37110735Ssam ip_deq(q); 3724640Swnj m_freem(dtom(q)); 37310735Ssam } 37410735Ssam remque(fp); 37510735Ssam (void) m_free(dtom(fp)); 3764495Swnj } 3774495Swnj 3784640Swnj /* 3794640Swnj * Put an ip fragment on a reassembly chain. 3804640Swnj * Like insque, but pointers in middle of structure. 3814640Swnj */ 3824640Swnj ip_enq(p, prev) 3834898Swnj register struct ipasfrag *p, *prev; 3844495Swnj { 3854951Swnj 3864898Swnj p->ipf_prev = prev; 3874898Swnj p->ipf_next = prev->ipf_next; 3884898Swnj prev->ipf_next->ipf_prev = p; 3894898Swnj prev->ipf_next = p; 3904495Swnj } 3914495Swnj 3924640Swnj /* 3934640Swnj * To ip_enq as remque is to insque. 3944640Swnj */ 3954640Swnj ip_deq(p) 3964898Swnj register struct ipasfrag *p; 3974640Swnj { 3984951Swnj 3994898Swnj p->ipf_prev->ipf_next = p->ipf_next; 4004898Swnj p->ipf_next->ipf_prev = p->ipf_prev; 4014495Swnj } 4024495Swnj 4034640Swnj /* 4044640Swnj * IP timer processing; 4054640Swnj * if a timer expires on a reassembly 4064640Swnj * queue, discard it. 4074640Swnj */ 4084801Swnj ip_slowtimo() 4094495Swnj { 4104495Swnj register struct ipq *fp; 4114640Swnj int s = splnet(); 4124951Swnj 4135243Sroot fp = ipq.next; 4145243Sroot if (fp == 0) { 4155243Sroot splx(s); 4165243Sroot return; 4175243Sroot } 41810735Ssam while (fp != &ipq) { 41910735Ssam --fp->ipq_ttl; 42010735Ssam fp = fp->next; 42110735Ssam if (fp->prev->ipq_ttl == 0) 42210735Ssam ip_freef(fp->prev); 42310735Ssam } 4244640Swnj splx(s); 4254495Swnj } 4264495Swnj 4274951Swnj /* 4284951Swnj * Drain off all datagram fragments. 4294951Swnj */ 4304801Swnj ip_drain() 4314801Swnj { 4324801Swnj 4334951Swnj while (ipq.next != &ipq) 43410735Ssam ip_freef(ipq.next); 4354801Swnj } 4364923Swnj 4374640Swnj /* 4384640Swnj * Do option processing on a datagram, 4394640Swnj * possibly discarding it if bad options 4404640Swnj * are encountered. 4414640Swnj */ 4424640Swnj ip_dooptions(ip) 4434640Swnj struct ip *ip; 4444495Swnj { 4454640Swnj register u_char *cp; 4466583Ssam int opt, optlen, cnt, code, type; 4474923Swnj struct in_addr *sin; 4484801Swnj register struct ip_timestamp *ipt; 449*18376Skarels register struct ifaddr *ifa; 4504951Swnj struct in_addr t; 4514495Swnj 4524640Swnj cp = (u_char *)(ip + 1); 4534640Swnj cnt = (ip->ip_hl << 2) - sizeof (struct ip); 4544640Swnj for (; cnt > 0; cnt -= optlen, cp += optlen) { 4554640Swnj opt = cp[0]; 4564640Swnj if (opt == IPOPT_EOL) 4574640Swnj break; 4584640Swnj if (opt == IPOPT_NOP) 4594640Swnj optlen = 1; 46016392Ssam else { 4614640Swnj optlen = cp[1]; 46217551Skarels if (optlen <= 0 || optlen >= cnt) 46317551Skarels goto bad; 46416392Ssam } 4654640Swnj switch (opt) { 4664495Swnj 4674640Swnj default: 4684640Swnj break; 4694495Swnj 4704951Swnj /* 4714951Swnj * Source routing with record. 4724951Swnj * Find interface with current destination address. 4734951Swnj * If none on this machine then drop if strictly routed, 4744951Swnj * or do nothing if loosely routed. 4754951Swnj * Record interface address and bring up next address 4764951Swnj * component. If strictly routed make sure next 4774951Swnj * address on directly accessible net. 4784951Swnj */ 4794640Swnj case IPOPT_LSRR: 4807508Sroot case IPOPT_SSRR: 4814801Swnj if (cp[2] < 4 || cp[2] > optlen - (sizeof (long) - 1)) 4824640Swnj break; 4834923Swnj sin = (struct in_addr *)(cp + cp[2]); 4846338Ssam ipaddr.sin_addr = *sin; 485*18376Skarels ifa = ifa_ifwithaddr((struct sockaddr *)&ipaddr); 4866583Ssam type = ICMP_UNREACH, code = ICMP_UNREACH_SRCFAIL; 487*18376Skarels if (ifa == 0) { 4884951Swnj if (opt == IPOPT_SSRR) 4894951Swnj goto bad; 4904951Swnj break; 4914640Swnj } 4924951Swnj t = ip->ip_dst; ip->ip_dst = *sin; *sin = t; 4934951Swnj cp[2] += 4; 4944951Swnj if (cp[2] > optlen - (sizeof (long) - 1)) 4954951Swnj break; 4964951Swnj ip->ip_dst = sin[1]; 4976338Ssam if (opt == IPOPT_SSRR && 498*18376Skarels in_iaonnetof(in_netof(ip->ip_dst)) == 0) 4994951Swnj goto bad; 5004640Swnj break; 5014495Swnj 5024640Swnj case IPOPT_TS: 5036583Ssam code = cp - (u_char *)ip; 5046583Ssam type = ICMP_PARAMPROB; 5054801Swnj ipt = (struct ip_timestamp *)cp; 5064801Swnj if (ipt->ipt_len < 5) 5074640Swnj goto bad; 5084801Swnj if (ipt->ipt_ptr > ipt->ipt_len - sizeof (long)) { 5094801Swnj if (++ipt->ipt_oflw == 0) 5104640Swnj goto bad; 5114495Swnj break; 5124640Swnj } 5134923Swnj sin = (struct in_addr *)(cp+cp[2]); 5144801Swnj switch (ipt->ipt_flg) { 5154495Swnj 5164640Swnj case IPOPT_TS_TSONLY: 5174640Swnj break; 5184640Swnj 5194640Swnj case IPOPT_TS_TSANDADDR: 5204801Swnj if (ipt->ipt_ptr + 8 > ipt->ipt_len) 5214640Swnj goto bad; 522*18376Skarels if (in_ifaddr == 0) 5236338Ssam goto bad; /* ??? */ 524*18376Skarels *sin++ = IA_SIN(in_ifaddr)->sin_addr; 5254640Swnj break; 5264640Swnj 5274640Swnj case IPOPT_TS_PRESPEC: 5286338Ssam ipaddr.sin_addr = *sin; 529*18376Skarels if (ifa_ifwithaddr((struct sockaddr *)&ipaddr) == 0) 5304951Swnj continue; 5314801Swnj if (ipt->ipt_ptr + 8 > ipt->ipt_len) 5324640Swnj goto bad; 5334801Swnj ipt->ipt_ptr += 4; 5344640Swnj break; 5354640Swnj 5364495Swnj default: 5374640Swnj goto bad; 5384495Swnj } 5394923Swnj *(n_time *)sin = iptime(); 5404801Swnj ipt->ipt_ptr += 4; 5414640Swnj } 5424495Swnj } 5436583Ssam return (0); 5444640Swnj bad: 5456583Ssam icmp_error(ip, type, code); 5466583Ssam return (1); 5474495Swnj } 5484495Swnj 5494640Swnj /* 5504951Swnj * Strip out IP options, at higher 5514951Swnj * level protocol in the kernel. 5524951Swnj * Second argument is buffer to which options 5534951Swnj * will be moved, and return value is their length. 5544640Swnj */ 5555217Swnj ip_stripoptions(ip, mopt) 5564640Swnj struct ip *ip; 5575217Swnj struct mbuf *mopt; 5584495Swnj { 5594640Swnj register int i; 5604640Swnj register struct mbuf *m; 5614640Swnj int olen; 5624640Swnj 5634640Swnj olen = (ip->ip_hl<<2) - sizeof (struct ip); 5644951Swnj m = dtom(ip); 5654951Swnj ip++; 5665217Swnj if (mopt) { 5675217Swnj mopt->m_len = olen; 5685217Swnj mopt->m_off = MMINOFF; 56916544Skarels bcopy((caddr_t)ip, mtod(mopt, caddr_t), (unsigned)olen); 5705217Swnj } 5714640Swnj i = m->m_len - (sizeof (struct ip) + olen); 5724907Swnj bcopy((caddr_t)ip+olen, (caddr_t)ip, (unsigned)i); 5735243Sroot m->m_len -= olen; 5744495Swnj } 5756583Ssam 57614670Ssam u_char inetctlerrmap[PRC_NCMDS] = { 5776583Ssam ECONNABORTED, ECONNABORTED, 0, 0, 57814670Ssam 0, 0, EHOSTDOWN, EHOSTUNREACH, 57914670Ssam ENETUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED, 58014670Ssam EMSGSIZE, 0, 0, 0, 5816583Ssam 0, 0, 0, 0 5826583Ssam }; 5836583Ssam 5846583Ssam ip_ctlinput(cmd, arg) 5856583Ssam int cmd; 5866583Ssam caddr_t arg; 5876583Ssam { 5888775Sroot struct in_addr *in; 58917358Skarels int in_rtchange(), tcp_abort(), udp_abort(); 5906583Ssam extern struct inpcb tcb, udb; 5916583Ssam 5926583Ssam if (cmd < 0 || cmd > PRC_NCMDS) 5936583Ssam return; 5946590Ssam if (inetctlerrmap[cmd] == 0) 5956583Ssam return; /* XXX */ 5966583Ssam if (cmd == PRC_IFDOWN) 5978775Sroot in = &((struct sockaddr_in *)arg)->sin_addr; 5986583Ssam else if (cmd == PRC_HOSTDEAD || cmd == PRC_HOSTUNREACH) 5998775Sroot in = (struct in_addr *)arg; 6006583Ssam else 6018775Sroot in = &((struct icmp *)arg)->icmp_ip.ip_dst; 60217358Skarels /* THIS IS VERY QUESTIONABLE, SHOULD HIT ALL PROTOCOLS */ 60317358Skarels if (cmd == PRC_REDIRECT_NET || cmd == PRC_REDIRECT_HOST) { 60417358Skarels in_pcbnotify(&tcb, in, 0, in_rtchange); 60517358Skarels in_pcbnotify(&udb, in, 0, in_rtchange); 60617358Skarels } else { 60717358Skarels in_pcbnotify(&tcb, in, (int)inetctlerrmap[cmd], tcp_abort); 60817358Skarels in_pcbnotify(&udb, in, (int)inetctlerrmap[cmd], udp_abort); 60917358Skarels } 6106583Ssam } 6116583Ssam 6126583Ssam int ipprintfs = 0; 6136583Ssam int ipforwarding = 1; 6146583Ssam /* 6156583Ssam * Forward a packet. If some error occurs return the sender 616*18376Skarels * an icmp packet. Note we can't always generate a meaningful 6176583Ssam * icmp message because icmp doesn't have a large enough repetoire 6186583Ssam * of codes and types. 6196583Ssam */ 6206583Ssam ip_forward(ip) 6216583Ssam register struct ip *ip; 6226583Ssam { 6236583Ssam register int error, type, code; 624*18376Skarels struct mbuf *mcopy; 6256583Ssam 6266583Ssam if (ipprintfs) 6276583Ssam printf("forward: src %x dst %x ttl %x\n", ip->ip_src, 6286583Ssam ip->ip_dst, ip->ip_ttl); 629*18376Skarels ip->ip_id = htons(ip->ip_id); 6306583Ssam if (ipforwarding == 0) { 6316583Ssam /* can't tell difference between net and host */ 6326583Ssam type = ICMP_UNREACH, code = ICMP_UNREACH_NET; 6336583Ssam goto sendicmp; 6346583Ssam } 6356583Ssam if (ip->ip_ttl < IPTTLDEC) { 6366583Ssam type = ICMP_TIMXCEED, code = ICMP_TIMXCEED_INTRANS; 6376583Ssam goto sendicmp; 6386583Ssam } 6396583Ssam ip->ip_ttl -= IPTTLDEC; 6406609Ssam 6416609Ssam /* 6426609Ssam * Save at most 64 bytes of the packet in case 6436609Ssam * we need to generate an ICMP message to the src. 6446609Ssam */ 6457843Sroot mcopy = m_copy(dtom(ip), 0, imin(ip->ip_len, 64)); 6466583Ssam 647*18376Skarels error = ip_output(dtom(ip), (struct mbuf *)0, (struct route *)0, 648*18376Skarels IP_FORWARDING); 64911540Ssam if (error == 0) { 6506609Ssam if (mcopy) 6516609Ssam m_freem(mcopy); 6526583Ssam return; 6536609Ssam } 65411540Ssam if (mcopy == NULL) 65511540Ssam return; 6566609Ssam ip = mtod(mcopy, struct ip *); 6576609Ssam type = ICMP_UNREACH, code = 0; /* need ``undefined'' */ 6586609Ssam switch (error) { 6596609Ssam 6606609Ssam case ENETUNREACH: 6616609Ssam case ENETDOWN: 6626583Ssam code = ICMP_UNREACH_NET; 6636609Ssam break; 6646609Ssam 6656609Ssam case EMSGSIZE: 6666583Ssam code = ICMP_UNREACH_NEEDFRAG; 6676609Ssam break; 6686609Ssam 6696609Ssam case EPERM: 6706609Ssam code = ICMP_UNREACH_PORT; 6716609Ssam break; 6726609Ssam 6736609Ssam case ENOBUFS: 6746609Ssam type = ICMP_SOURCEQUENCH; 6756609Ssam break; 6766609Ssam 6776609Ssam case EHOSTDOWN: 6786609Ssam case EHOSTUNREACH: 6796609Ssam code = ICMP_UNREACH_HOST; 6806609Ssam break; 6816609Ssam } 6826583Ssam sendicmp: 6836583Ssam icmp_error(ip, type, code); 6846583Ssam } 685