bostic@OKEEFFE.BERKELEY.EDU (Keith Bostic) (04/05/88)
Subject: (inet 4 of 4) updated IP/TCP and XNS sources for 4.3BSD Index: sys 4.3BSD Description: This is number 5 of 11 total articles posted to the newsgroup comp.bugs.4bsd.ucb-fixes. This archive is number 4 of the 4 articles that make up the inet posting. # This is a shell archive. Save it in a file, remove anything before # this line, and then unpack it by entering "sh file". Note, it may # create directories; files and directories will be owned by you and # have default permissions. # # This archive contains: # # netinet # netinet/ip.h # netinet/ip_icmp.c # netinet/ip_icmp.h # netinet/ip_input.c # netinet/ip_output.c # netinet/ip_var.h # netinet/raw_ip.c # netinet/udp.h # netinet/udp_usrreq.c # netinet/udp_var.h # echo c - netinet mkdir netinet > /dev/null 2>&1 echo x - netinet/ip.h sed 's/^X//' >netinet/ip.h << 'END-of-netinet/ip.h' X/* X * Copyright (c) 1982, 1986 Regents of the University of California. X * All rights reserved. X * X * Redistribution and use in source and binary forms are permitted X * provided that this notice is preserved and that due credit is given X * to the University of California at Berkeley. The name of the University X * may not be used to endorse or promote products derived from this X * software without specific prior written permission. This software X * is provided ``as is'' without express or implied warranty. X * X * @(#)ip.h 7.6.1.1 (Berkeley) 3/15/88 X */ X#ifndef BYTE_ORDER X/* X * Definitions for byte order, X * according to byte significance from low address to high. X */ X#define LITTLE_ENDIAN 1234 /* least-significant byte first (vax) */ X#define BIG_ENDIAN 4321 /* most-significant byte first (IBM, net) */ X#define PDP_ENDIAN 3412 /* LSB first in word, MSW first in long (pdp) */ X X#ifdef vax X#define BYTE_ORDER LITTLE_ENDIAN X#else X#define BYTE_ORDER BIG_ENDIAN /* mc68000, tahoe, most others */ X#endif X#endif BYTE_ORDER X X/* X * Definitions for internet protocol version 4. X * Per RFC 791, September 1981. X */ X#define IPVERSION 4 X X/* X * Structure of an internet header, naked of options. X * X * We declare ip_len and ip_off to be short, rather than u_short X * pragmatically since otherwise unsigned comparisons can result X * against negative integers quite easily, and fail in subtle ways. X */ Xstruct ip { X#if BYTE_ORDER == LITTLE_ENDIAN X u_char ip_hl:4, /* header length */ X ip_v:4; /* version */ X#endif X#if BYTE_ORDER == BIG_ENDIAN X u_char ip_v:4, /* version */ X ip_hl:4; /* header length */ X#endif X u_char ip_tos; /* type of service */ X short ip_len; /* total length */ X u_short ip_id; /* identification */ X short ip_off; /* fragment offset field */ X#define IP_DF 0x4000 /* dont fragment flag */ X#define IP_MF 0x2000 /* more fragments flag */ X u_char ip_ttl; /* time to live */ X u_char ip_p; /* protocol */ X u_short ip_sum; /* checksum */ X struct in_addr ip_src,ip_dst; /* source and dest address */ X}; X X#define IP_MAXPACKET 65535 /* maximum packet size */ X X/* X * Definitions for options. X */ X#define IPOPT_COPIED(o) ((o)&0x80) X#define IPOPT_CLASS(o) ((o)&0x60) X#define IPOPT_NUMBER(o) ((o)&0x1f) X X#define IPOPT_CONTROL 0x00 X#define IPOPT_RESERVED1 0x20 X#define IPOPT_DEBMEAS 0x40 X#define IPOPT_RESERVED2 0x60 X X#define IPOPT_EOL 0 /* end of option list */ X#define IPOPT_NOP 1 /* no operation */ X X#define IPOPT_RR 7 /* record packet route */ X#define IPOPT_TS 68 /* timestamp */ X#define IPOPT_SECURITY 130 /* provide s,c,h,tcc */ X#define IPOPT_LSRR 131 /* loose source route */ X#define IPOPT_SATID 136 /* satnet id */ X#define IPOPT_SSRR 137 /* strict source route */ X X/* X * Offsets to fields in options other than EOL and NOP. X */ X#define IPOPT_OPTVAL 0 /* option ID */ X#define IPOPT_OLEN 1 /* option length */ X#define IPOPT_OFFSET 2 /* offset within option */ X#define IPOPT_MINOFF 4 /* min value of above */ X X/* X * Time stamp option structure. X */ Xstruct ip_timestamp { X u_char ipt_code; /* IPOPT_TS */ X u_char ipt_len; /* size of structure (variable) */ X u_char ipt_ptr; /* index of current entry */ X#if BYTE_ORDER == LITTLE_ENDIAN X u_char ipt_flg:4, /* flags, see below */ X ipt_oflw:4; /* overflow counter */ X#endif X#if BYTE_ORDER == BIG_ENDIAN X u_char ipt_oflw:4, /* overflow counter */ X ipt_flg:4; /* flags, see below */ X#endif X union ipt_timestamp { X n_long ipt_time[1]; X struct ipt_ta { X struct in_addr ipt_addr; X n_long ipt_time; X } ipt_ta[1]; X } ipt_timestamp; X}; X X/* flag bits for ipt_flg */ X#define IPOPT_TS_TSONLY 0 /* timestamps only */ X#define IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */ X#define IPOPT_TS_PRESPEC 2 /* specified modules only */ X X/* bits for security (not byte swapped) */ X#define IPOPT_SECUR_UNCLASS 0x0000 X#define IPOPT_SECUR_CONFID 0xf135 X#define IPOPT_SECUR_EFTO 0x789a X#define IPOPT_SECUR_MMMM 0xbc4d X#define IPOPT_SECUR_RESTR 0xaf13 X#define IPOPT_SECUR_SECRET 0xd788 X#define IPOPT_SECUR_TOPSECRET 0x6bc5 X X/* X * Internet implementation parameters. X */ X#define MAXTTL 255 /* maximum time to live (seconds) */ X#define IPFRAGTTL 60 /* time to live for frags, slowhz */ X#define IPTTLDEC 1 /* subtracted when forwarding */ X X#define IP_MSS 576 /* default maximum segment size */ END-of-netinet/ip.h echo x - netinet/ip_icmp.c sed 's/^X//' >netinet/ip_icmp.c << 'END-of-netinet/ip_icmp.c' X/* X * Copyright (c) 1982, 1986 Regents of the University of California. X * All rights reserved. X * X * Redistribution and use in source and binary forms are permitted X * provided that this notice is preserved and that due credit is given X * to the University of California at Berkeley. The name of the University X * may not be used to endorse or promote products derived from this X * software without specific prior written permission. This software X * is provided ``as is'' without express or implied warranty. X * X * @(#)ip_icmp.c 7.7 (Berkeley) 12/7/87 X */ X X#include "param.h" X#include "systm.h" X#include "mbuf.h" X#include "protosw.h" X#include "socket.h" X#include "time.h" X#include "kernel.h" X X#include "../net/route.h" X#include "../net/if.h" X X#include "in.h" X#include "in_systm.h" X#include "in_var.h" X#include "ip.h" X#include "ip_icmp.h" X#include "icmp_var.h" X X#ifdef ICMPPRINTFS X/* X * ICMP routines: error generation, receive packet processing, and X * routines to turnaround packets back to the originator, and X * host table maintenance routines. X */ Xint icmpprintfs = 0; X#endif X X/* X * Generate an error packet of type error X * in response to bad packet ip. X */ X/*VARARGS4*/ Xicmp_error(oip, type, code, ifp, dest) X struct ip *oip; X int type, code; X struct ifnet *ifp; X struct in_addr dest; X{ X register unsigned oiplen = oip->ip_hl << 2; X register struct icmp *icp; X struct mbuf *m; X struct ip *nip; X unsigned icmplen; X X#ifdef ICMPPRINTFS X if (icmpprintfs) X printf("icmp_error(%x, %d, %d)\n", oip, type, code); X#endif X if (type != ICMP_REDIRECT) X icmpstat.icps_error++; X /* X * Don't send error if not the first fragment of message. X * Don't error if the old packet protocol was ICMP X * error message, only known informational types. X */ X if (oip->ip_off &~ (IP_MF|IP_DF)) X goto free; X if (oip->ip_p == IPPROTO_ICMP && type != ICMP_REDIRECT && X !ICMP_INFOTYPE(((struct icmp *)((caddr_t)oip + oiplen))->icmp_type)) { X icmpstat.icps_oldicmp++; X goto free; X } X X /* X * First, formulate icmp message X */ X m = m_get(M_DONTWAIT, MT_HEADER); X if (m == NULL) X goto free; X icmplen = oiplen + MIN(8, oip->ip_len); X m->m_len = icmplen + ICMP_MINLEN; X m->m_off = MMAXOFF - m->m_len; X icp = mtod(m, struct icmp *); X if ((u_int)type > ICMP_MAXTYPE) X panic("icmp_error"); X icmpstat.icps_outhist[type]++; X icp->icmp_type = type; X if (type == ICMP_REDIRECT) X icp->icmp_gwaddr = dest; X else X icp->icmp_void = 0; X if (type == ICMP_PARAMPROB) { X icp->icmp_pptr = code; X code = 0; X } X icp->icmp_code = code; X bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, icmplen); X nip = &icp->icmp_ip; X nip->ip_len += oiplen; X nip->ip_len = htons((u_short)nip->ip_len); X X /* X * Now, copy old ip header in front of icmp message. X */ X if (m->m_len + oiplen > MLEN) X oiplen = sizeof(struct ip); X if (m->m_len + oiplen > MLEN) X panic("icmp len"); X m->m_off -= oiplen; X m->m_len += oiplen; X nip = mtod(m, struct ip *); X bcopy((caddr_t)oip, (caddr_t)nip, oiplen); X nip->ip_len = m->m_len; X nip->ip_p = IPPROTO_ICMP; X icmp_reflect(nip, ifp); X Xfree: X m_freem(dtom(oip)); X} X Xstatic struct sockproto icmproto = { AF_INET, IPPROTO_ICMP }; Xstatic struct sockaddr_in icmpsrc = { AF_INET }; Xstatic struct sockaddr_in icmpdst = { AF_INET }; Xstatic struct sockaddr_in icmpgw = { AF_INET }; Xstruct in_ifaddr *ifptoia(); X X/* X * Process a received ICMP message. X */ Xicmp_input(m, ifp) X register struct mbuf *m; X struct ifnet *ifp; X{ X register struct icmp *icp; X register struct ip *ip = mtod(m, struct ip *); X int icmplen = ip->ip_len, hlen = ip->ip_hl << 2; X register int i; X struct in_ifaddr *ia; X int (*ctlfunc)(), code; X extern u_char ip_protox[]; X extern struct in_addr in_makeaddr(); X X /* X * Locate icmp structure in mbuf, and check X * that not corrupted and of at least minimum length. X */ X#ifdef ICMPPRINTFS X if (icmpprintfs) X printf("icmp_input from %x, len %d\n", ip->ip_src, icmplen); X#endif X if (icmplen < ICMP_MINLEN) { X icmpstat.icps_tooshort++; X goto free; X } X i = hlen + MIN(icmplen, ICMP_ADVLENMIN); X if ((m->m_off > MMAXOFF || m->m_len < i) && X (m = m_pullup(m, i)) == 0) { X icmpstat.icps_tooshort++; X return; X } X ip = mtod(m, struct ip *); X m->m_len -= hlen; X m->m_off += hlen; X icp = mtod(m, struct icmp *); X if (in_cksum(m, icmplen)) { X icmpstat.icps_checksum++; X goto free; X } X m->m_len += hlen; X m->m_off -= hlen; X X#ifdef ICMPPRINTFS X /* X * Message type specific processing. X */ X if (icmpprintfs) X printf("icmp_input, type %d code %d\n", icp->icmp_type, X icp->icmp_code); X#endif X if (icp->icmp_type > ICMP_MAXTYPE) X goto raw; X icmpstat.icps_inhist[icp->icmp_type]++; X code = icp->icmp_code; X switch (icp->icmp_type) { X X case ICMP_UNREACH: X if (code > 5) X goto badcode; X code += PRC_UNREACH_NET; X goto deliver; X X case ICMP_TIMXCEED: X if (code > 1) X goto badcode; X code += PRC_TIMXCEED_INTRANS; X goto deliver; X X case ICMP_PARAMPROB: X if (code) X goto badcode; X code = PRC_PARAMPROB; X goto deliver; X X case ICMP_SOURCEQUENCH: X if (code) X goto badcode; X code = PRC_QUENCH; X deliver: X /* X * Problem with datagram; advise higher level routines. X */ X icp->icmp_ip.ip_len = ntohs((u_short)icp->icmp_ip.ip_len); X if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) { X icmpstat.icps_badlen++; X goto free; X } X#ifdef ICMPPRINTFS X if (icmpprintfs) X printf("deliver to protocol %d\n", icp->icmp_ip.ip_p); X#endif X icmpsrc.sin_addr = icp->icmp_ip.ip_dst; X if (ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput) X (*ctlfunc)(code, (struct sockaddr *)&icmpsrc); X break; X X badcode: X icmpstat.icps_badcode++; X break; X X case ICMP_ECHO: X icp->icmp_type = ICMP_ECHOREPLY; X goto reflect; X X case ICMP_TSTAMP: X if (icmplen < ICMP_TSLEN) { X icmpstat.icps_badlen++; X break; X } X icp->icmp_type = ICMP_TSTAMPREPLY; X icp->icmp_rtime = iptime(); X icp->icmp_ttime = icp->icmp_rtime; /* bogus, do later! */ X goto reflect; X X case ICMP_IREQ: X#define satosin(sa) ((struct sockaddr_in *)(sa)) X if (in_netof(ip->ip_src) == 0 && (ia = ifptoia(ifp))) X ip->ip_src = in_makeaddr(in_netof(IA_SIN(ia)->sin_addr), X in_lnaof(ip->ip_src)); X icp->icmp_type = ICMP_IREQREPLY; X goto reflect; X X case ICMP_MASKREQ: X if (icmplen < ICMP_MASKLEN || (ia = ifptoia(ifp)) == 0) X break; X icp->icmp_type = ICMP_MASKREPLY; X icp->icmp_mask = htonl(ia->ia_subnetmask); X if (ip->ip_src.s_addr == 0) { X if (ia->ia_ifp->if_flags & IFF_BROADCAST) X ip->ip_src = satosin(&ia->ia_broadaddr)->sin_addr; X else if (ia->ia_ifp->if_flags & IFF_POINTOPOINT) X ip->ip_src = satosin(&ia->ia_dstaddr)->sin_addr; X } Xreflect: X ip->ip_len += hlen; /* since ip_input deducts this */ X icmpstat.icps_reflect++; X icmpstat.icps_outhist[icp->icmp_type]++; X icmp_reflect(ip, ifp); X return; X X case ICMP_REDIRECT: X if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) { X icmpstat.icps_badlen++; X break; X } X /* X * Short circuit routing redirects to force X * immediate change in the kernel's routing X * tables. The message is also handed to anyone X * listening on a raw socket (e.g. the routing X * daemon for use in updating its tables). X */ X icmpgw.sin_addr = ip->ip_src; X icmpdst.sin_addr = icp->icmp_gwaddr; X#ifdef ICMPPRINTFS X if (icmpprintfs) X printf("redirect dst %x to %x\n", icp->icmp_ip.ip_dst, X icp->icmp_gwaddr); X#endif X if (code == ICMP_REDIRECT_NET || code == ICMP_REDIRECT_TOSNET) { X icmpsrc.sin_addr = X in_makeaddr(in_netof(icp->icmp_ip.ip_dst), INADDR_ANY); X rtredirect((struct sockaddr *)&icmpsrc, X (struct sockaddr *)&icmpdst, RTF_GATEWAY, X (struct sockaddr *)&icmpgw); X icmpsrc.sin_addr = icp->icmp_ip.ip_dst; X pfctlinput(PRC_REDIRECT_NET, X (struct sockaddr *)&icmpsrc); X } else { X icmpsrc.sin_addr = icp->icmp_ip.ip_dst; X rtredirect((struct sockaddr *)&icmpsrc, X (struct sockaddr *)&icmpdst, RTF_GATEWAY | RTF_HOST, X (struct sockaddr *)&icmpgw); X pfctlinput(PRC_REDIRECT_HOST, X (struct sockaddr *)&icmpsrc); X } X break; X X /* X * No kernel processing for the following; X * just fall through to send to raw listener. X */ X case ICMP_ECHOREPLY: X case ICMP_TSTAMPREPLY: X case ICMP_IREQREPLY: X case ICMP_MASKREPLY: X default: X break; X } X Xraw: X icmpsrc.sin_addr = ip->ip_src; X icmpdst.sin_addr = ip->ip_dst; X raw_input(m, &icmproto, (struct sockaddr *)&icmpsrc, X (struct sockaddr *)&icmpdst); X return; X Xfree: X m_freem(m); X} X X/* X * Reflect the ip packet back to the source X */ Xicmp_reflect(ip, ifp) X register struct ip *ip; X struct ifnet *ifp; X{ X register struct in_ifaddr *ia; X struct in_addr t; X struct mbuf *opts = 0, *ip_srcroute(); X int optlen = (ip->ip_hl << 2) - sizeof(struct ip); X X t = ip->ip_dst; X ip->ip_dst = ip->ip_src; X /* X * If the incoming packet was addressed directly to us, X * use dst as the src for the reply. Otherwise (broadcast X * or anonymous), use the address which corresponds X * to the incoming interface. X */ X for (ia = in_ifaddr; ia; ia = ia->ia_next) { X if (t.s_addr == IA_SIN(ia)->sin_addr.s_addr) X break; X if ((ia->ia_ifp->if_flags & IFF_BROADCAST) && X t.s_addr == satosin(&ia->ia_broadaddr)->sin_addr.s_addr) X break; X } X if (ia == (struct in_ifaddr *)0) X ia = ifptoia(ifp); X if (ia == (struct in_ifaddr *)0) X ia = in_ifaddr; X t = IA_SIN(ia)->sin_addr; X ip->ip_src = t; X ip->ip_ttl = MAXTTL; X X if (optlen > 0) { X /* X * Retrieve any source routing from the incoming packet X * and strip out other options. Adjust the IP length. X */ X opts = ip_srcroute(); X ip->ip_len -= optlen; X ip_stripoptions(ip, (struct mbuf *)0); X } X icmp_send(ip, opts); X if (opts) X (void)m_free(opts); X} X Xstruct in_ifaddr * Xifptoia(ifp) X struct ifnet *ifp; X{ X register struct in_ifaddr *ia; X X for (ia = in_ifaddr; ia; ia = ia->ia_next) X if (ia->ia_ifp == ifp) X return (ia); X return ((struct in_ifaddr *)0); X} X X/* X * Send an icmp packet back to the ip level, X * after supplying a checksum. X */ Xicmp_send(ip, opts) X register struct ip *ip; X struct mbuf *opts; X{ X register int hlen; X register struct icmp *icp; X register struct mbuf *m; X X m = dtom(ip); X hlen = ip->ip_hl << 2; X m->m_off += hlen; X m->m_len -= hlen; X icp = mtod(m, struct icmp *); X icp->icmp_cksum = 0; X icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen); X m->m_off -= hlen; X m->m_len += hlen; X#ifdef ICMPPRINTFS X if (icmpprintfs) X printf("icmp_send dst %x src %x\n", ip->ip_dst, ip->ip_src); X#endif X (void) ip_output(m, opts, (struct route *)0, 0); X} X Xn_time Xiptime() X{ X struct timeval atv; X u_long t; X X microtime(&atv); X t = (atv.tv_sec % (24*60*60)) * 1000 + atv.tv_usec / 1000; X return (htonl(t)); X} END-of-netinet/ip_icmp.c echo x - netinet/ip_icmp.h sed 's/^X//' >netinet/ip_icmp.h << 'END-of-netinet/ip_icmp.h' X/* X * Copyright (c) 1982, 1986 Regents of the University of California. X * All rights reserved. X * X * Redistribution and use in source and binary forms are permitted X * provided that this notice is preserved and that due credit is given X * to the University of California at Berkeley. The name of the University X * may not be used to endorse or promote products derived from this X * software without specific prior written permission. This software X * is provided ``as is'' without express or implied warranty. X * X * @(#)ip_icmp.h 7.3 (Berkeley) 12/7/87 X */ X X/* X * Interface Control Message Protocol Definitions. X * Per RFC 792, September 1981. X */ X X/* X * Structure of an icmp header. X */ Xstruct icmp { X u_char icmp_type; /* type of message, see below */ X u_char icmp_code; /* type sub code */ X u_short icmp_cksum; /* ones complement cksum of struct */ X union { X u_char ih_pptr; /* ICMP_PARAMPROB */ X struct in_addr ih_gwaddr; /* ICMP_REDIRECT */ X struct ih_idseq { X n_short icd_id; X n_short icd_seq; X } ih_idseq; X int ih_void; X } icmp_hun; X#define icmp_pptr icmp_hun.ih_pptr X#define icmp_gwaddr icmp_hun.ih_gwaddr X#define icmp_id icmp_hun.ih_idseq.icd_id X#define icmp_seq icmp_hun.ih_idseq.icd_seq X#define icmp_void icmp_hun.ih_void X union { X struct id_ts { X n_time its_otime; X n_time its_rtime; X n_time its_ttime; X } id_ts; X struct id_ip { X struct ip idi_ip; X /* options and then 64 bits of data */ X } id_ip; X u_long id_mask; X char id_data[1]; X } icmp_dun; X#define icmp_otime icmp_dun.id_ts.its_otime X#define icmp_rtime icmp_dun.id_ts.its_rtime X#define icmp_ttime icmp_dun.id_ts.its_ttime X#define icmp_ip icmp_dun.id_ip.idi_ip X#define icmp_mask icmp_dun.id_mask X#define icmp_data icmp_dun.id_data X}; X X/* X * Lower bounds on packet lengths for various types. X * For the error advice packets must first insure that the X * packet is large enought to contain the returned ip header. X * Only then can we do the check to see if 64 bits of packet X * data have been returned, since we need to check the returned X * ip header length. X */ X#define ICMP_MINLEN 8 /* abs minimum */ X#define ICMP_TSLEN (8 + 3 * sizeof (n_time)) /* timestamp */ X#define ICMP_MASKLEN 12 /* address mask */ X#define ICMP_ADVLENMIN (8 + sizeof (struct ip) + 8) /* min */ X#define ICMP_ADVLEN(p) (8 + ((p)->icmp_ip.ip_hl << 2) + 8) X /* N.B.: must separately check that ip_hl >= 5 */ X X/* X * Definition of type and code field values. X */ X#define ICMP_ECHOREPLY 0 /* echo reply */ X#define ICMP_UNREACH 3 /* dest unreachable, codes: */ X#define ICMP_UNREACH_NET 0 /* bad net */ X#define ICMP_UNREACH_HOST 1 /* bad host */ X#define ICMP_UNREACH_PROTOCOL 2 /* bad protocol */ X#define ICMP_UNREACH_PORT 3 /* bad port */ X#define ICMP_UNREACH_NEEDFRAG 4 /* IP_DF caused drop */ X#define ICMP_UNREACH_SRCFAIL 5 /* src route failed */ X#define ICMP_SOURCEQUENCH 4 /* packet lost, slow down */ X#define ICMP_REDIRECT 5 /* shorter route, codes: */ X#define ICMP_REDIRECT_NET 0 /* for network */ X#define ICMP_REDIRECT_HOST 1 /* for host */ X#define ICMP_REDIRECT_TOSNET 2 /* for tos and net */ X#define ICMP_REDIRECT_TOSHOST 3 /* for tos and host */ X#define ICMP_ECHO 8 /* echo service */ X#define ICMP_TIMXCEED 11 /* time exceeded, code: */ X#define ICMP_TIMXCEED_INTRANS 0 /* ttl==0 in transit */ X#define ICMP_TIMXCEED_REASS 1 /* ttl==0 in reass */ X#define ICMP_PARAMPROB 12 /* ip header bad */ X#define ICMP_TSTAMP 13 /* timestamp request */ X#define ICMP_TSTAMPREPLY 14 /* timestamp reply */ X#define ICMP_IREQ 15 /* information request */ X#define ICMP_IREQREPLY 16 /* information reply */ X#define ICMP_MASKREQ 17 /* address mask request */ X#define ICMP_MASKREPLY 18 /* address mask reply */ X X#define ICMP_MAXTYPE 18 X X#define ICMP_INFOTYPE(type) \ X ((type) == ICMP_ECHOREPLY || (type) == ICMP_ECHO || \ X (type) == ICMP_TSTAMP || (type) == ICMP_TSTAMPREPLY || \ X (type) == ICMP_IREQ || (type) == ICMP_IREQREPLY || \ X (type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY) END-of-netinet/ip_icmp.h echo x - netinet/ip_input.c sed 's/^X//' >netinet/ip_input.c << 'END-of-netinet/ip_input.c' X/* X * Copyright (c) 1982, 1986 Regents of the University of California. X * All rights reserved. X * X * Redistribution and use in source and binary forms are permitted X * provided that this notice is preserved and that due credit is given X * to the University of California at Berkeley. The name of the University X * may not be used to endorse or promote products derived from this X * software without specific prior written permission. This software X * is provided ``as is'' without express or implied warranty. X * X * @(#)ip_input.c 7.9 (Berkeley) 3/15/88 X */ X X#include "param.h" X#include "systm.h" X#include "mbuf.h" X#include "domain.h" X#include "protosw.h" X#include "socket.h" X#include "errno.h" X#include "time.h" X#include "kernel.h" X X#include "../net/if.h" X#include "../net/route.h" X X#include "in.h" X#include "in_pcb.h" X#include "in_systm.h" X#include "in_var.h" X#include "ip.h" X#include "ip_var.h" X#include "ip_icmp.h" X#include "tcp.h" X Xu_char ip_protox[IPPROTO_MAX]; Xint ipqmaxlen = IFQ_MAXLEN; Xstruct in_ifaddr *in_ifaddr; /* first inet address */ X X/* X * We need to save the IP options in case a protocol wants to respond X * to an incoming packet over the same route if the packet got here X * using IP source routing. This allows connection establishment and X * maintenance when the remote end is on a network that is not known X * to us. X */ Xint ip_nhops = 0; Xstatic struct ip_srcrt { X char nop; /* one NOP to align */ X char srcopt[IPOPT_OFFSET + 1]; /* OPTVAL, OLEN and OFFSET */ X struct in_addr route[MAX_IPOPTLEN]; X} ip_srcrt; X X/* X * IP initialization: fill in IP protocol switch table. X * All protocols not implemented in kernel go to raw IP protocol handler. X */ Xip_init() X{ X register struct protosw *pr; X register int i; X X pr = pffindproto(PF_INET, IPPROTO_RAW, SOCK_RAW); X if (pr == 0) X panic("ip_init"); X for (i = 0; i < IPPROTO_MAX; i++) X ip_protox[i] = pr - inetsw; X for (pr = inetdomain.dom_protosw; X pr < inetdomain.dom_protoswNPROTOSW; pr++) X if (pr->pr_domain->dom_family == PF_INET && X pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW) X ip_protox[pr->pr_protocol] = pr - inetsw; X ipq.next = ipq.prev = &ipq; X ip_id = time.tv_sec & 0xffff; X ipintrq.ifq_maxlen = ipqmaxlen; X} X Xu_char ipcksum = 1; Xstruct ip *ip_reass(); Xstruct sockaddr_in ipaddr = { AF_INET }; Xstruct route ipforward_rt; X X/* X * Ip input routine. Checksum and byte swap header. If fragmented X * try to reassamble. If complete and fragment queue exists, discard. X * Process options. Pass to next level. X */ Xipintr() X{ X register struct ip *ip; X register struct mbuf *m; X struct mbuf *m0; X register int i; X register struct ipq *fp; X register struct in_ifaddr *ia; X struct ifnet *ifp; X int hlen, s; X Xnext: X /* X * Get next datagram off input queue and get IP header X * in first mbuf. X */ X s = splimp(); X IF_DEQUEUEIF(&ipintrq, m, ifp); X splx(s); X if (m == 0) X return; X /* X * If no IP addresses have been set yet but the interfaces X * are receiving, can't do anything with incoming packets yet. X */ X if (in_ifaddr == NULL) X goto bad; X ipstat.ips_total++; X if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct ip)) && X (m = m_pullup(m, sizeof (struct ip))) == 0) { X ipstat.ips_toosmall++; X goto next; X } X ip = mtod(m, struct ip *); X hlen = ip->ip_hl << 2; X if (hlen < sizeof(struct ip)) { /* minimum header length */ X ipstat.ips_badhlen++; X goto bad; X } X if (hlen > m->m_len) { X if ((m = m_pullup(m, hlen)) == 0) { X ipstat.ips_badhlen++; X goto next; X } X ip = mtod(m, struct ip *); X } X if (ipcksum) X if (ip->ip_sum = in_cksum(m, hlen)) { X ipstat.ips_badsum++; X goto bad; X } X X /* X * Convert fields to host representation. X */ X ip->ip_len = ntohs((u_short)ip->ip_len); X if (ip->ip_len < hlen) { X ipstat.ips_badlen++; X goto bad; X } X ip->ip_id = ntohs(ip->ip_id); X ip->ip_off = ntohs((u_short)ip->ip_off); X X /* X * Check that the amount of data in the buffers X * is as at least much as the IP header would have us expect. X * Trim mbufs if longer than we expect. X * Drop packet if shorter than we expect. X */ X i = -(u_short)ip->ip_len; X m0 = m; X for (;;) { X i += m->m_len; X if (m->m_next == 0) X break; X m = m->m_next; X } X if (i != 0) { X if (i < 0) { X ipstat.ips_tooshort++; X m = m0; X goto bad; X } X if (i <= m->m_len) X m->m_len -= i; X else X m_adj(m0, -i); X } X m = m0; X X /* X * Process options and, if not destined for us, X * ship it on. ip_dooptions returns 1 when an X * error was detected (causing an icmp message X * to be sent and the original packet to be freed). X */ X ip_nhops = 0; /* for source routed packets */ X if (hlen > sizeof (struct ip) && ip_dooptions(ip, ifp)) X goto next; X X /* X * Check our list of addresses, to see if the packet is for us. X */ X for (ia = in_ifaddr; ia; ia = ia->ia_next) { X#define satosin(sa) ((struct sockaddr_in *)(sa)) X X if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr) X goto ours; X if ( X#ifdef DIRECTED_BROADCAST X ia->ia_ifp == ifp && X#endif X (ia->ia_ifp->if_flags & IFF_BROADCAST)) { X u_long t; X X if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr == X ip->ip_dst.s_addr) X goto ours; X if (ip->ip_dst.s_addr == ia->ia_netbroadcast.s_addr) X goto ours; X /* X * Look for all-0's host part (old broadcast addr), X * either for subnet or net. X */ X t = ntohl(ip->ip_dst.s_addr); X if (t == ia->ia_subnet) X goto ours; X if (t == ia->ia_net) X goto ours; X } X } X if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST) X goto ours; X if (ip->ip_dst.s_addr == INADDR_ANY) X goto ours; X X /* X * Not for us; forward if possible and desirable. X */ X ip_forward(ip, ifp); X goto next; X Xours: X /* X * If offset or IP_MF are set, must reassemble. X * Otherwise, nothing need be done. X * (We could look in the reassembly queue to see X * if the packet was previously fragmented, X * but it's not worth the time; just let them time out.) X */ X if (ip->ip_off &~ IP_DF) { X /* X * Look for queue of fragments X * of this datagram. X */ X for (fp = ipq.next; fp != &ipq; fp = fp->next) X if (ip->ip_id == fp->ipq_id && X ip->ip_src.s_addr == fp->ipq_src.s_addr && X ip->ip_dst.s_addr == fp->ipq_dst.s_addr && X ip->ip_p == fp->ipq_p) X goto found; X fp = 0; Xfound: X X /* X * Adjust ip_len to not reflect header, X * set ip_mff if more fragments are expected, X * convert offset of this to bytes. X */ X ip->ip_len -= hlen; X ((struct ipasfrag *)ip)->ipf_mff = 0; X if (ip->ip_off & IP_MF) X ((struct ipasfrag *)ip)->ipf_mff = 1; X ip->ip_off <<= 3; X X /* X * If datagram marked as having more fragments X * or if this is not the first fragment, X * attempt reassembly; if it succeeds, proceed. X */ X if (((struct ipasfrag *)ip)->ipf_mff || ip->ip_off) { X ipstat.ips_fragments++; X ip = ip_reass((struct ipasfrag *)ip, fp); X if (ip == 0) X goto next; X m = dtom(ip); X } else X if (fp) X ip_freef(fp); X } else X ip->ip_len -= hlen; X X /* X * Switch out to protocol's input routine. X */ X (*inetsw[ip_protox[ip->ip_p]].pr_input)(m, ifp); X goto next; Xbad: X m_freem(m); X goto next; X} X X/* X * Take incoming datagram fragment and try to X * reassemble it into whole datagram. If a chain for X * reassembly of this datagram already exists, then it X * is given as fp; otherwise have to make a chain. X */ Xstruct ip * Xip_reass(ip, fp) X register struct ipasfrag *ip; X register struct ipq *fp; X{ X register struct mbuf *m = dtom(ip); X register struct ipasfrag *q; X struct mbuf *t; X int hlen = ip->ip_hl << 2; X int i, next; X X /* X * Presence of header sizes in mbufs X * would confuse code below. X */ X m->m_off += hlen; X m->m_len -= hlen; X X /* X * If first fragment to arrive, create a reassembly queue. X */ X if (fp == 0) { X if ((t = m_get(M_DONTWAIT, MT_FTABLE)) == NULL) X goto dropfrag; X fp = mtod(t, struct ipq *); X insque(fp, &ipq); X fp->ipq_ttl = IPFRAGTTL; X fp->ipq_p = ip->ip_p; X fp->ipq_id = ip->ip_id; X fp->ipq_next = fp->ipq_prev = (struct ipasfrag *)fp; X fp->ipq_src = ((struct ip *)ip)->ip_src; X fp->ipq_dst = ((struct ip *)ip)->ip_dst; X q = (struct ipasfrag *)fp; X goto insert; X } X X /* X * Find a segment which begins after this one does. X */ X for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next) X if (q->ip_off > ip->ip_off) X break; X X /* X * If there is a preceding segment, it may provide some of X * our data already. If so, drop the data from the incoming X * segment. If it provides all of our data, drop us. X */ X if (q->ipf_prev != (struct ipasfrag *)fp) { X i = q->ipf_prev->ip_off + q->ipf_prev->ip_len - ip->ip_off; X if (i > 0) { X if (i >= ip->ip_len) X goto dropfrag; X m_adj(dtom(ip), i); X ip->ip_off += i; X ip->ip_len -= i; X } X } X X /* X * While we overlap succeeding segments trim them or, X * if they are completely covered, dequeue them. X */ X while (q != (struct ipasfrag *)fp && ip->ip_off + ip->ip_len > q->ip_off) { X i = (ip->ip_off + ip->ip_len) - q->ip_off; X if (i < q->ip_len) { X q->ip_len -= i; X q->ip_off += i; X m_adj(dtom(q), i); X break; X } X q = q->ipf_next; X m_freem(dtom(q->ipf_prev)); X ip_deq(q->ipf_prev); X } X Xinsert: X /* X * Stick new segment in its place; X * check for complete reassembly. X */ X ip_enq(ip, q->ipf_prev); X next = 0; X for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = q->ipf_next) { X if (q->ip_off != next) X return (0); X next += q->ip_len; X } X if (q->ipf_prev->ipf_mff) X return (0); X X /* X * Reassembly is complete; concatenate fragments. X */ X q = fp->ipq_next; X m = dtom(q); X t = m->m_next; X m->m_next = 0; X m_cat(m, t); X q = q->ipf_next; X while (q != (struct ipasfrag *)fp) { X t = dtom(q); X q = q->ipf_next; X m_cat(m, t); X } X X /* X * Create header for new ip packet by X * modifying header of first packet; X * dequeue and discard fragment reassembly header. X * Make header visible. X */ X ip = fp->ipq_next; X ip->ip_len = next; X ((struct ip *)ip)->ip_src = fp->ipq_src; X ((struct ip *)ip)->ip_dst = fp->ipq_dst; X remque(fp); X (void) m_free(dtom(fp)); X m = dtom(ip); X m->m_len += (ip->ip_hl << 2); X m->m_off -= (ip->ip_hl << 2); X return ((struct ip *)ip); X Xdropfrag: X ipstat.ips_fragdropped++; X m_freem(m); X return (0); X} X X/* X * Free a fragment reassembly header and all X * associated datagrams. X */ Xip_freef(fp) X struct ipq *fp; X{ X register struct ipasfrag *q, *p; X X for (q = fp->ipq_next; q != (struct ipasfrag *)fp; q = p) { X p = q->ipf_next; X ip_deq(q); X m_freem(dtom(q)); X } X remque(fp); X (void) m_free(dtom(fp)); X} X X/* X * Put an ip fragment on a reassembly chain. X * Like insque, but pointers in middle of structure. X */ Xip_enq(p, prev) X register struct ipasfrag *p, *prev; X{ X X p->ipf_prev = prev; X p->ipf_next = prev->ipf_next; X prev->ipf_next->ipf_prev = p; X prev->ipf_next = p; X} X X/* X * To ip_enq as remque is to insque. X */ Xip_deq(p) X register struct ipasfrag *p; X{ X X p->ipf_prev->ipf_next = p->ipf_next; X p->ipf_next->ipf_prev = p->ipf_prev; X} X X/* X * IP timer processing; X * if a timer expires on a reassembly X * queue, discard it. X */ Xip_slowtimo() X{ X register struct ipq *fp; X int s = splnet(); X X fp = ipq.next; X if (fp == 0) { X splx(s); X return; X } X while (fp != &ipq) { X --fp->ipq_ttl; X fp = fp->next; X if (fp->prev->ipq_ttl == 0) { X ipstat.ips_fragtimeout++; X ip_freef(fp->prev); X } X } X splx(s); X} X X/* X * Drain off all datagram fragments. X */ Xip_drain() X{ X X while (ipq.next != &ipq) { X ipstat.ips_fragdropped++; X ip_freef(ipq.next); X } X} X Xextern struct in_ifaddr *ifptoia(); Xstruct in_ifaddr *ip_rtaddr(); X X/* X * Do option processing on a datagram, X * possibly discarding it if bad options X * are encountered. X */ Xip_dooptions(ip, ifp) X register struct ip *ip; X struct ifnet *ifp; X{ X register u_char *cp; X int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB; X register struct ip_timestamp *ipt; X register struct in_ifaddr *ia; X struct in_addr *sin; X n_time ntime; X X cp = (u_char *)(ip + 1); X cnt = (ip->ip_hl << 2) - sizeof (struct ip); X for (; cnt > 0; cnt -= optlen, cp += optlen) { X opt = cp[IPOPT_OPTVAL]; X if (opt == IPOPT_EOL) X break; X if (opt == IPOPT_NOP) X optlen = 1; X else { X optlen = cp[IPOPT_OLEN]; X if (optlen <= 0 || optlen > cnt) { X code = &cp[IPOPT_OLEN] - (u_char *)ip; X goto bad; X } X } X switch (opt) { X X default: X break; X X /* X * Source routing with record. X * Find interface with current destination address. X * If none on this machine then drop if strictly routed, X * or do nothing if loosely routed. X * Record interface address and bring up next address X * component. If strictly routed make sure next X * address on directly accessible net. X */ X case IPOPT_LSRR: X case IPOPT_SSRR: X if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { X code = &cp[IPOPT_OFFSET] - (u_char *)ip; X goto bad; X } X ipaddr.sin_addr = ip->ip_dst; X ia = (struct in_ifaddr *) X ifa_ifwithaddr((struct sockaddr *)&ipaddr); X if (ia == 0) { X if (opt == IPOPT_SSRR) { X type = ICMP_UNREACH; X code = ICMP_UNREACH_SRCFAIL; X goto bad; X } X /* X * Loose routing, and not at next destination X * yet; nothing to do except forward. X */ X break; X } X off--; /* 0 origin */ X if (off > optlen - sizeof(struct in_addr)) { X /* X * End of source route. Should be for us. X */ X save_rte(cp, ip->ip_src); X break; X } X /* X * locate outgoing interface X */ X bcopy((caddr_t)(cp + off), (caddr_t)&ipaddr.sin_addr, X sizeof(ipaddr.sin_addr)); X if ((opt == IPOPT_SSRR && X in_iaonnetof(in_netof(ipaddr.sin_addr)) == 0) || X (ia = ip_rtaddr(ipaddr.sin_addr)) == 0) { X type = ICMP_UNREACH; X code = ICMP_UNREACH_SRCFAIL; X goto bad; X } X ip->ip_dst = ipaddr.sin_addr; X bcopy((caddr_t)&(IA_SIN(ia)->sin_addr), X (caddr_t)(cp + off), sizeof(struct in_addr)); X cp[IPOPT_OFFSET] += sizeof(struct in_addr); X break; X X case IPOPT_RR: X if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { X code = &cp[IPOPT_OFFSET] - (u_char *)ip; X goto bad; X } X /* X * If no space remains, ignore. X */ X off--; /* 0 origin */ X if (off > optlen - sizeof(struct in_addr)) X break; X bcopy((caddr_t)(&ip->ip_dst), (caddr_t)&ipaddr.sin_addr, X sizeof(ipaddr.sin_addr)); X /* X * locate outgoing interface X */ X if ((ia = ip_rtaddr(ipaddr.sin_addr)) == 0) { X type = ICMP_UNREACH; X code = ICMP_UNREACH_HOST; X goto bad; X } X bcopy((caddr_t)&(IA_SIN(ia)->sin_addr), X (caddr_t)(cp + off), sizeof(struct in_addr)); X cp[IPOPT_OFFSET] += sizeof(struct in_addr); X break; X X case IPOPT_TS: X code = cp - (u_char *)ip; X ipt = (struct ip_timestamp *)cp; X if (ipt->ipt_len < 5) X goto bad; X if (ipt->ipt_ptr > ipt->ipt_len - sizeof (long)) { X if (++ipt->ipt_oflw == 0) X goto bad; X break; X } X sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1); X switch (ipt->ipt_flg) { X X case IPOPT_TS_TSONLY: X break; X X case IPOPT_TS_TSANDADDR: X if (ipt->ipt_ptr + sizeof(n_time) + X sizeof(struct in_addr) > ipt->ipt_len) X goto bad; X ia = ifptoia(ifp); X bcopy((caddr_t)&IA_SIN(ia)->sin_addr, X (caddr_t)sin, sizeof(struct in_addr)); X ipt->ipt_ptr += sizeof(struct in_addr); X break; X X case IPOPT_TS_PRESPEC: X if (ipt->ipt_ptr + sizeof(n_time) + X sizeof(struct in_addr) > ipt->ipt_len) X goto bad; X bcopy((caddr_t)sin, (caddr_t)&ipaddr.sin_addr, X sizeof(struct in_addr)); X if (ifa_ifwithaddr((struct sockaddr *)&ipaddr) == 0) X continue; X ipt->ipt_ptr += sizeof(struct in_addr); X break; X X default: X goto bad; X } X ntime = iptime(); X bcopy((caddr_t)&ntime, (caddr_t)cp + ipt->ipt_ptr - 1, X sizeof(n_time)); X ipt->ipt_ptr += sizeof(n_time); X } X } X return (0); Xbad: X icmp_error(ip, type, code, ifp); X return (1); X} X X/* X * Given address of next destination (final or next hop), X * return internet address info of interface to be used to get there. X */ Xstruct in_ifaddr * Xip_rtaddr(dst) X struct in_addr dst; X{ X register struct sockaddr_in *sin; X register struct in_ifaddr *ia; X X sin = (struct sockaddr_in *) &ipforward_rt.ro_dst; X X if (ipforward_rt.ro_rt == 0 || dst.s_addr != sin->sin_addr.s_addr) { X if (ipforward_rt.ro_rt) { X RTFREE(ipforward_rt.ro_rt); X ipforward_rt.ro_rt = 0; X } X sin->sin_family = AF_INET; X sin->sin_addr = dst; X X rtalloc(&ipforward_rt); X } X if (ipforward_rt.ro_rt == 0) X return ((struct in_ifaddr *)0); X /* X * Find address associated with outgoing interface. X */ X for (ia = in_ifaddr; ia; ia = ia->ia_next) X if (ia->ia_ifp == ipforward_rt.ro_rt->rt_ifp) X break; X return (ia); X} X X/* X * Save incoming source route for use in replies, X * to be picked up later by ip_srcroute if the receiver is interested. X */ Xsave_rte(option, dst) X u_char *option; X struct in_addr dst; X{ X unsigned olen; X extern ipprintfs; X X olen = option[IPOPT_OLEN]; X if (olen > sizeof(ip_srcrt) - 1) { X if (ipprintfs) X printf("save_rte: olen %d\n", olen); X return; X } X bcopy((caddr_t)option, (caddr_t)ip_srcrt.srcopt, olen); X ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr); X ip_srcrt.route[ip_nhops++] = dst; X} X X/* X * Retrieve incoming source route for use in replies, X * in the same form used by setsockopt. X * The first hop is placed before the options, will be removed later. X */ Xstruct mbuf * Xip_srcroute() X{ X register struct in_addr *p, *q; X register struct mbuf *m; X X if (ip_nhops == 0) X return ((struct mbuf *)0); X m = m_get(M_DONTWAIT, MT_SOOPTS); X if (m == 0) X return ((struct mbuf *)0); X m->m_len = ip_nhops * sizeof(struct in_addr) + IPOPT_OFFSET + 1 + 1; X X /* X * First save first hop for return route X */ X p = &ip_srcrt.route[ip_nhops - 1]; X *(mtod(m, struct in_addr *)) = *p--; X X /* X * Copy option fields and padding (nop) to mbuf. X */ X ip_srcrt.nop = IPOPT_NOP; X bcopy((caddr_t)&ip_srcrt, mtod(m, caddr_t) + sizeof(struct in_addr), X IPOPT_OFFSET + 1 + 1); X q = (struct in_addr *)(mtod(m, caddr_t) + X sizeof(struct in_addr) + IPOPT_OFFSET + 1 + 1); X /* X * Record return path as an IP source route, X * reversing the path (pointers are now aligned). X */ X while (p >= ip_srcrt.route) X *q++ = *p--; X return (m); X} X X/* X * Strip out IP options, at higher X * level protocol in the kernel. X * Second argument is buffer to which options X * will be moved, and return value is their length. X */ Xip_stripoptions(ip, mopt) X struct ip *ip; X struct mbuf *mopt; X{ X register int i; X register struct mbuf *m; X register caddr_t opts; X int olen; X X olen = (ip->ip_hl<<2) - sizeof (struct ip); X m = dtom(ip); X opts = (caddr_t)(ip + 1); X if (mopt) { X mopt->m_len = olen; X mopt->m_off = MMINOFF; X bcopy(opts, mtod(mopt, caddr_t), (unsigned)olen); X } X i = m->m_len - (sizeof (struct ip) + olen); X bcopy(opts + olen, opts, (unsigned)i); X m->m_len -= olen; X ip->ip_hl = sizeof(struct ip) >> 2; X} X Xu_char inetctlerrmap[PRC_NCMDS] = { X 0, 0, 0, 0, X 0, 0, EHOSTDOWN, EHOSTUNREACH, X ENETUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED, X EMSGSIZE, EHOSTUNREACH, 0, 0, X 0, 0, 0, 0, X ENOPROTOOPT X}; X X#ifndef IPFORWARDING X#define IPFORWARDING 1 X#endif X#ifndef IPSENDREDIRECTS X#define IPSENDREDIRECTS 1 X#endif Xint ipprintfs = 0; Xint ipforwarding = IPFORWARDING; Xextern int in_interfaces; Xint ipsendredirects = IPSENDREDIRECTS; X X/* X * Forward a packet. If some error occurs return the sender X * an icmp packet. Note we can't always generate a meaningful X * icmp message because icmp doesn't have a large enough repertoire X * of codes and types. X * X * If not forwarding (possibly because we have only a single external X * network), just drop the packet. This could be confusing if ipforwarding X * was zero but some routing protocol was advancing us as a gateway X * to somewhere. However, we must let the routing protocol deal with that. X */ Xip_forward(ip, ifp) X register struct ip *ip; X struct ifnet *ifp; X{ X register int error, type = 0, code; X register struct sockaddr_in *sin; X struct mbuf *mcopy; X struct in_addr dest; X X dest.s_addr = 0; X if (ipprintfs) X printf("forward: src %x dst %x ttl %x\n", ip->ip_src, X ip->ip_dst, ip->ip_ttl); X ip->ip_id = htons(ip->ip_id); X if (ipforwarding == 0 || in_interfaces <= 1) { X ipstat.ips_cantforward++; X#ifdef GATEWAY X type = ICMP_UNREACH, code = ICMP_UNREACH_NET; X goto sendicmp; X#else X m_freem(dtom(ip)); X return; X#endif X } X if (in_canforward(ip->ip_dst) == 0) { X m_freem(dtom(ip)); X return; X } X if (ip->ip_ttl <= IPTTLDEC) { X type = ICMP_TIMXCEED, code = ICMP_TIMXCEED_INTRANS; X goto sendicmp; X } X ip->ip_ttl -= IPTTLDEC; X X /* X * Save at most 64 bytes of the packet in case X * we need to generate an ICMP message to the src. X */ X mcopy = m_copy(dtom(ip), 0, imin((int)ip->ip_len, 64)); X X sin = (struct sockaddr_in *)&ipforward_rt.ro_dst; X if (ipforward_rt.ro_rt == 0 || X ip->ip_dst.s_addr != sin->sin_addr.s_addr) { X if (ipforward_rt.ro_rt) { X RTFREE(ipforward_rt.ro_rt); X ipforward_rt.ro_rt = 0; X } X sin->sin_family = AF_INET; X sin->sin_addr = ip->ip_dst; X X rtalloc(&ipforward_rt); X } X /* X * If forwarding packet using same interface that it came in on, X * perhaps should send a redirect to sender to shortcut a hop. X * Only send redirect if source is sending directly to us, X * and if packet was not source routed (or has any options). X * Also, don't send redirect if forwarding using a default route X * or a route modfied by a redirect. X */ X#define satosin(sa) ((struct sockaddr_in *)(sa)) X if (ipforward_rt.ro_rt && ipforward_rt.ro_rt->rt_ifp == ifp && X (ipforward_rt.ro_rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 && X satosin(&ipforward_rt.ro_rt->rt_dst)->sin_addr.s_addr != 0 && X ipsendredirects && ip->ip_hl == (sizeof(struct ip) >> 2)) { X struct in_ifaddr *ia; X u_long src = ntohl(ip->ip_src.s_addr); X u_long dst = ntohl(ip->ip_dst.s_addr); X X if ((ia = ifptoia(ifp)) && X (src & ia->ia_subnetmask) == ia->ia_subnet) { X if (ipforward_rt.ro_rt->rt_flags & RTF_GATEWAY) X dest = satosin(&ipforward_rt.ro_rt->rt_gateway)->sin_addr; X else X dest = ip->ip_dst; X /* X * If the destination is reached by a route to host, X * is on a subnet of a local net, or is directly X * on the attached net (!), use host redirect. X * (We may be the correct first hop for other subnets.) X */ X type = ICMP_REDIRECT; X code = ICMP_REDIRECT_NET; X if ((ipforward_rt.ro_rt->rt_flags & RTF_HOST) || X (ipforward_rt.ro_rt->rt_flags & RTF_GATEWAY) == 0) X code = ICMP_REDIRECT_HOST; X else for (ia = in_ifaddr; ia = ia->ia_next; ) X if ((dst & ia->ia_netmask) == ia->ia_net) { X if (ia->ia_subnetmask != ia->ia_netmask) X code = ICMP_REDIRECT_HOST; X break; X } X if (ipprintfs) X printf("redirect (%d) to %x\n", code, dest); X } X } X X error = ip_output(dtom(ip), (struct mbuf *)0, &ipforward_rt, X IP_FORWARDING); X if (error) X ipstat.ips_cantforward++; X else if (type) X ipstat.ips_redirectsent++; X else { X if (mcopy) X m_freem(mcopy); X ipstat.ips_forward++; X return; X } X if (mcopy == NULL) X return; X ip = mtod(mcopy, struct ip *); X type = ICMP_UNREACH; X switch (error) { X X case 0: /* forwarded, but need redirect */ X type = ICMP_REDIRECT; X /* code set above */ X break; X X case ENETUNREACH: X case ENETDOWN: X if (in_localaddr(ip->ip_dst)) X code = ICMP_UNREACH_HOST; X else X code = ICMP_UNREACH_NET; X break; X X case EMSGSIZE: X code = ICMP_UNREACH_NEEDFRAG; X break; X X case EPERM: X code = ICMP_UNREACH_PORT; X break; X X case ENOBUFS: X type = ICMP_SOURCEQUENCH; X break; X X case EHOSTDOWN: X case EHOSTUNREACH: X code = ICMP_UNREACH_HOST; X break; X } Xsendicmp: X icmp_error(ip, type, code, ifp, dest); X} END-of-netinet/ip_input.c echo x - netinet/ip_output.c sed 's/^X//' >netinet/ip_output.c << 'END-of-netinet/ip_output.c' X/* X * Copyright (c) 1982, 1986 Regents of the University of California. X * All rights reserved. X * X * Redistribution and use in source and binary forms are permitted X * provided that this notice is preserved and that due credit is given X * to the University of California at Berkeley. The name of the University X * may not be used to endorse or promote products derived from this X * software without specific prior written permission. This software X * is provided ``as is'' without express or implied warranty. X * X * @(#)ip_output.c 7.9 (Berkeley) 3/15/88 X */ X X#include "param.h" X#include "mbuf.h" X#include "errno.h" X#include "protosw.h" X#include "socket.h" X#include "socketvar.h" X X#include "../net/if.h" X#include "../net/route.h" X X#include "in.h" X#include "in_pcb.h" X#include "in_systm.h" X#include "in_var.h" X#include "ip.h" X#include "ip_var.h" X X#ifdef vax X#include "../machine/mtpr.h" X#endif X Xstruct mbuf *ip_insertoptions(); X X/* X * IP output. The packet in mbuf chain m contains a skeletal IP X * header (with len, off, ttl, proto, tos, src, dst). X * The mbuf chain containing the packet will be freed. X * The mbuf opt, if present, will not be freed. X */ Xip_output(m0, opt, ro, flags) X struct mbuf *m0; X struct mbuf *opt; X struct route *ro; X int flags; X{ X register struct ip *ip, *mhip; X register struct ifnet *ifp; X register struct mbuf *m = m0; X register int hlen = sizeof (struct ip); X int len, off, error = 0; X struct route iproute; X struct sockaddr_in *dst; X X if (opt) { X m = ip_insertoptions(m, opt, &len); X hlen = len; X } X ip = mtod(m, struct ip *); X /* X * Fill in IP header. X */ X if ((flags & IP_FORWARDING) == 0) { X ip->ip_v = IPVERSION; X ip->ip_off &= IP_DF; X ip->ip_id = htons(ip_id++); X ip->ip_hl = hlen >> 2; X } else X hlen = ip->ip_hl << 2; X X /* X * Route packet. X */ X if (ro == 0) { X ro = &iproute; X bzero((caddr_t)ro, sizeof (*ro)); X } X dst = (struct sockaddr_in *)&ro->ro_dst; X /* X * If there is a cached route, X * check that it is to the same destination X * and is still up. If not, free it and try again. X */ X if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 || X dst->sin_addr.s_addr != ip->ip_dst.s_addr)) { X RTFREE(ro->ro_rt); X ro->ro_rt = (struct rtentry *)0; X } X if (ro->ro_rt == 0) { X dst->sin_family = AF_INET; X dst->sin_addr = ip->ip_dst; X } X /* X * If routing to interface only, X * short circuit routing lookup. X */ X if (flags & IP_ROUTETOIF) { X struct in_ifaddr *ia; X X ia = (struct in_ifaddr *)ifa_ifwithdstaddr(dst); X if (ia == 0) X ia = in_iaonnetof(in_netof(ip->ip_dst)); X if (ia == 0) { X error = ENETUNREACH; X goto bad; X } X ifp = ia->ia_ifp; X } else { X if (ro->ro_rt == 0) X rtalloc(ro); X if (ro->ro_rt == 0 || (ifp = ro->ro_rt->rt_ifp) == 0) { X if (in_localaddr(ip->ip_dst)) X error = EHOSTUNREACH; X else X error = ENETUNREACH; X goto bad; X } X ro->ro_rt->rt_use++; X if (ro->ro_rt->rt_flags & RTF_GATEWAY) X dst = (struct sockaddr_in *)&ro->ro_rt->rt_gateway; X } X#ifndef notdef X /* X * If source address not specified yet, use address X * of outgoing interface. X */ X if (ip->ip_src.s_addr == INADDR_ANY) { X register struct in_ifaddr *ia; X X for (ia = in_ifaddr; ia; ia = ia->ia_next) X if (ia->ia_ifp == ifp) { X ip->ip_src = IA_SIN(ia)->sin_addr; X break; X } X } X#endif X /* X * Look for broadcast address and X * and verify user is allowed to send X * such a packet. X */ X if (in_broadcast(dst->sin_addr)) { X if ((ifp->if_flags & IFF_BROADCAST) == 0) { X error = EADDRNOTAVAIL; X goto bad; X } X if ((flags & IP_ALLOWBROADCAST) == 0) { X error = EACCES; X goto bad; X } X /* don't allow broadcast messages to be fragmented */ X if (ip->ip_len > ifp->if_mtu) { X error = EMSGSIZE; X goto bad; X } X } X X /* X * If small enough for interface, can just send directly. X */ X if (ip->ip_len <= ifp->if_mtu) { X ip->ip_len = htons((u_short)ip->ip_len); X ip->ip_off = htons((u_short)ip->ip_off); X ip->ip_sum = 0; X ip->ip_sum = in_cksum(m, hlen); X error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst); X goto done; X } X X /* X * Too large for interface; fragment if possible. X * Must be able to put at least 8 bytes per fragment. X */ X if (ip->ip_off & IP_DF) { X error = EMSGSIZE; X goto bad; X } X len = (ifp->if_mtu - hlen) &~ 7; X if (len < 8) { X error = EMSGSIZE; X goto bad; X } X X { X int mhlen, firstlen = len; X struct mbuf **mnext = &m->m_act; X X /* X * Loop through length of segment after first fragment, X * make new header and copy data of each part and link onto chain. X */ X m0 = m; X mhlen = sizeof (struct ip); X for (off = hlen + len; off < ip->ip_len; off += len) { X MGET(m, M_DONTWAIT, MT_HEADER); X if (m == 0) { X error = ENOBUFS; X goto bad; X } X m->m_off = MMAXOFF - hlen; X mhip = mtod(m, struct ip *); X *mhip = *ip; X if (hlen > sizeof (struct ip)) { X mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip); X mhip->ip_hl = mhlen >> 2; X } X m->m_len = mhlen; X mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF); X if (ip->ip_off & IP_MF) X mhip->ip_off |= IP_MF; X if (off + len >= ip->ip_len) X len = ip->ip_len - off; X else X mhip->ip_off |= IP_MF; X mhip->ip_len = htons((u_short)(len + mhlen)); X m->m_next = m_copy(m0, off, len); X if (m->m_next == 0) { X error = ENOBUFS; /* ??? */ X goto sendorfree; X } X mhip->ip_off = htons((u_short)mhip->ip_off); X mhip->ip_sum = 0; X mhip->ip_sum = in_cksum(m, mhlen); X *mnext = m; X mnext = &m->m_act; X } X /* X * Update first fragment by trimming what's been copied out X * and updating header, then send each fragment (in order). X */ X m_adj(m0, hlen + firstlen - ip->ip_len); X ip->ip_len = hlen + firstlen; X ip->ip_off |= IP_MF; X ip->ip_sum = 0; X ip->ip_sum = in_cksum(m0, hlen); Xsendorfree: X for (m = m0; m; m = m0) { X m0 = m->m_act; X m->m_act = 0; X if (error == 0) X error = (*ifp->if_output)(ifp, m, X (struct sockaddr *)dst); X else X m_freem(m); X } X } Xdone: X if (ro == &iproute && (flags & IP_ROUTETOIF) == 0 && ro->ro_rt) X RTFREE(ro->ro_rt); X return (error); Xbad: X m_freem(m0); X goto done; X} X X/* X * Insert IP options into preformed packet. X * Adjust IP destination as required for IP source routing, X * as indicated by a non-zero in_addr at the start of the options. X */ Xstruct mbuf * Xip_insertoptions(m, opt, phlen) X register struct mbuf *m; X struct mbuf *opt; X int *phlen; X{ X register struct ipoption *p = mtod(opt, struct ipoption *); X struct mbuf *n; X register struct ip *ip = mtod(m, struct ip *); X unsigned optlen; X X optlen = opt->m_len - sizeof(p->ipopt_dst); X if (p->ipopt_dst.s_addr) X ip->ip_dst = p->ipopt_dst; X if (m->m_off >= MMAXOFF || MMINOFF + optlen > m->m_off) { X MGET(n, M_DONTWAIT, MT_HEADER); X if (n == 0) X return (m); X m->m_len -= sizeof(struct ip); X m->m_off += sizeof(struct ip); X n->m_next = m; X m = n; X m->m_off = MMAXOFF - sizeof(struct ip) - optlen; X m->m_len = optlen + sizeof(struct ip); X bcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip)); X } else { X m->m_off -= optlen; X m->m_len += optlen; X ovbcopy((caddr_t)ip, mtod(m, caddr_t), sizeof(struct ip)); X } X ip = mtod(m, struct ip *); X bcopy((caddr_t)p->ipopt_list, (caddr_t)(ip + 1), (unsigned)optlen); X *phlen = sizeof(struct ip) + optlen; X ip->ip_len += optlen; X return (m); X} X X/* X * Copy options from ip to jp, X * omitting those not copied during fragmentation. X */ Xip_optcopy(ip, jp) X struct ip *ip, *jp; X{ X register u_char *cp, *dp; X int opt, optlen, cnt; X X cp = (u_char *)(ip + 1); X dp = (u_char *)(jp + 1); X cnt = (ip->ip_hl << 2) - sizeof (struct ip); X for (; cnt > 0; cnt -= optlen, cp += optlen) { X opt = cp[0]; X if (opt == IPOPT_EOL) X break; X if (opt == IPOPT_NOP) X optlen = 1; X else X optlen = cp[IPOPT_OLEN]; X /* bogus lengths should have been caught by ip_dooptions */ X if (optlen > cnt) X optlen = cnt; X if (IPOPT_COPIED(opt)) { X bcopy((caddr_t)cp, (caddr_t)dp, (unsigned)optlen); X dp += optlen; X } X } X for (optlen = dp - (u_char *)(jp+1); optlen & 0x3; optlen++) X *dp++ = IPOPT_EOL; X return (optlen); X} X X/* X * IP socket option processing. X */ Xip_ctloutput(op, so, level, optname, m) X int op; X struct socket *so; X int level, optname; X struct mbuf **m; X{ X int error = 0; X struct inpcb *inp = sotoinpcb(so); X X if (level != IPPROTO_IP) X error = EINVAL; X else switch (op) { X X case PRCO_SETOPT: X switch (optname) { X case IP_OPTIONS: X return (ip_pcbopts(&inp->inp_options, *m)); X X default: X error = EINVAL; X break; X } X break; X X case PRCO_GETOPT: X switch (optname) { X case IP_OPTIONS: X *m = m_get(M_WAIT, MT_SOOPTS); X if (inp->inp_options) { X (*m)->m_off = inp->inp_options->m_off; X (*m)->m_len = inp->inp_options->m_len; X bcopy(mtod(inp->inp_options, caddr_t), X mtod(*m, caddr_t), (unsigned)(*m)->m_len); X } else X (*m)->m_len = 0; X break; X default: X error = EINVAL; X break; X } X break; X } X if (op == PRCO_SETOPT && *m) X (void)m_free(*m); X return (error); X} X X/* X * Set up IP options in pcb for insertion in output packets. X * Store in mbuf with pointer in pcbopt, adding pseudo-option X * with destination address if source routed. X */ Xip_pcbopts(pcbopt, m) X struct mbuf **pcbopt; X register struct mbuf *m; X{ X register cnt, optlen; X register u_char *cp; X u_char opt; X X /* turn off any old options */ X if (*pcbopt) X (void)m_free(*pcbopt); X *pcbopt = 0; X if (m == (struct mbuf *)0 || m->m_len == 0) { X /* X * Only turning off any previous options. X */ X if (m) X (void)m_free(m); X return (0); X } X X#ifndef vax X if (m->m_len % sizeof(long)) X goto bad; X#endif X /* X * IP first-hop destination address will be stored before X * actual options; move other options back X * and clear it when none present. X */ X#if MAX_IPOPTLEN >= MMAXOFF - MMINOFF X if (m->m_off + m->m_len + sizeof(struct in_addr) > MAX_IPOPTLEN) X goto bad; X#else X if (m->m_off + m->m_len + sizeof(struct in_addr) > MMAXOFF) X goto bad; X#endif X cnt = m->m_len; X m->m_len += sizeof(struct in_addr); X cp = mtod(m, u_char *) + sizeof(struct in_addr); X ovbcopy(mtod(m, caddr_t), (caddr_t)cp, (unsigned)cnt); X bzero(mtod(m, caddr_t), sizeof(struct in_addr)); X X for (; cnt > 0; cnt -= optlen, cp += optlen) { X opt = cp[IPOPT_OPTVAL]; X if (opt == IPOPT_EOL) X break; X if (opt == IPOPT_NOP) X optlen = 1; X else { X optlen = cp[IPOPT_OLEN]; X if (optlen <= IPOPT_OLEN || optlen > cnt) X goto bad; X } X switch (opt) { X X default: X break; X X case IPOPT_LSRR: X case IPOPT_SSRR: X /* X * user process specifies route as: X * ->A->B->C->D X * D must be our final destination (but we can't X * check that since we may not have connected yet). X * A is first hop destination, which doesn't appear in X * actual IP option, but is stored before the options. X */ X if (optlen < IPOPT_MINOFF - 1 + sizeof(struct in_addr)) X goto bad; X m->m_len -= sizeof(struct in_addr); X cnt -= sizeof(struct in_addr); X optlen -= sizeof(struct in_addr); X cp[IPOPT_OLEN] = optlen; X /* X * Move first hop before start of options. X */ X bcopy((caddr_t)&cp[IPOPT_OFFSET+1], mtod(m, caddr_t), X sizeof(struct in_addr)); X /* X * Then copy rest of options back X * to close up the deleted entry. X */ X ovbcopy((caddr_t)(&cp[IPOPT_OFFSET+1] + X sizeof(struct in_addr)), X (caddr_t)&cp[IPOPT_OFFSET+1], X (unsigned)cnt + sizeof(struct in_addr)); X break; X } X } X *pcbopt = m; X return (0); X Xbad: X (void)m_free(m); X return (EINVAL); X} END-of-netinet/ip_output.c echo x - netinet/ip_var.h sed 's/^X//' >netinet/ip_var.h << 'END-of-netinet/ip_var.h' X/* X * Copyright (c) 1982, 1986 Regents of the University of California. X * All rights reserved. X * X * Redistribution and use in source and binary forms are permitted X * provided that this notice is preserved and that due credit is given X * to the University of California at Berkeley. The name of the University X * may not be used to endorse or promote products derived from this X * software without specific prior written permission. This software X * is provided ``as is'' without express or implied warranty. X * X * @(#)ip_var.h 7.4 (Berkeley) 1/7/88 X */ X X/* X * Overlay for ip header used by other protocols (tcp, udp). X */ Xstruct ipovly { X caddr_t ih_next, ih_prev; /* for protocol sequence q's */ X u_char ih_x1; /* (unused) */ X u_char ih_pr; /* protocol */ X short ih_len; /* protocol length */ X struct in_addr ih_src; /* source internet address */ X struct in_addr ih_dst; /* destination internet address */ X}; X X/* X * Ip reassembly queue structure. Each fragment X * being reassembled is attached to one of these structures. X * They are timed out after ipq_ttl drops to 0, and may also X * be reclaimed if memory becomes tight. X */ Xstruct ipq { X struct ipq *next,*prev; /* to other reass headers */ X u_char ipq_ttl; /* time for reass q to live */ X u_char ipq_p; /* protocol of this fragment */ X u_short ipq_id; /* sequence id for reassembly */ X struct ipasfrag *ipq_next,*ipq_prev; X /* to ip headers of fragments */ X struct in_addr ipq_src,ipq_dst; X}; X X/* X * Ip header, when holding a fragment. X * X * Note: ipf_next must be at same offset as ipq_next above X */ Xstruct ipasfrag { X#if BYTE_ORDER == LITTLE_ENDIAN X u_char ip_hl:4, X ip_v:4; X#endif X#if BYTE_ORDER == BIG_ENDIAN X u_char ip_v:4, X ip_hl:4; X#endif X u_char ipf_mff; /* copied from (ip_off&IP_MF) */ X short ip_len; X u_short ip_id; X short ip_off; X u_char ip_ttl; X u_char ip_p; X u_short ip_sum; X struct ipasfrag *ipf_next; /* next fragment */ X struct ipasfrag *ipf_prev; /* previous fragment */ X}; X X/* X * Structure stored in mbuf in inpcb.ip_options X * and passed to ip_output when ip options are in use. X * The actual length of the options (including ipopt_dst) X * is in m_len. X */ X#define MAX_IPOPTLEN 40 X Xstruct ipoption { X struct in_addr ipopt_dst; /* first-hop dst if source routed */ X char ipopt_list[MAX_IPOPTLEN]; /* options proper */ X}; X Xstruct ipstat { X long ips_total; /* total packets received */ X long ips_badsum; /* checksum bad */ X long ips_tooshort; /* packet too short */ X long ips_toosmall; /* not enough data */ X long ips_badhlen; /* ip header length < data size */ X long ips_badlen; /* ip length < ip header length */ X long ips_fragments; /* fragments received */ X long ips_fragdropped; /* frags dropped (dups, out of space) */ X long ips_fragtimeout; /* fragments timed out */ X long ips_forward; /* packets forwarded */ X long ips_cantforward; /* packets rcvd for unreachable dest */ X long ips_redirectsent; /* packets forwarded on same net */ X}; X X#ifdef KERNEL X/* flags passed to ip_output as last parameter */ X#define IP_FORWARDING 0x1 /* most of ip header exists */ X#define IP_ROUTETOIF SO_DONTROUTE /* bypass routing tables */ X#define IP_ALLOWBROADCAST SO_BROADCAST /* can send broadcast packets */ X Xstruct ipstat ipstat; Xstruct ipq ipq; /* ip reass. queue */ Xu_short ip_id; /* ip packet ctr, for ids */ X Xstruct mbuf *ip_srcroute(); X#endif END-of-netinet/ip_var.h echo x - netinet/raw_ip.c sed 's/^X//' >netinet/raw_ip.c << 'END-of-netinet/raw_ip.c' X/* X * Copyright (c) 1982, 1986 Regents of the University of California. X * All rights reserved. X * X * Redistribution and use in source and binary forms are permitted X * provided that this notice is preserved and that due credit is given X * to the University of California at Berkeley. The name of the University X * may not be used to endorse or promote products derived from this X * software without specific prior written permission. This software X * is provided ``as is'' without express or implied warranty. X * X * @(#)raw_ip.c 7.3 (Berkeley) 12/7/87 X */ X X#include "param.h" X#include "mbuf.h" X#include "socket.h" X#include "protosw.h" X#include "socketvar.h" X#include "errno.h" X X#include "../net/if.h" X#include "../net/route.h" X#include "../net/raw_cb.h" X X#include "in.h" X#include "in_systm.h" X#include "ip.h" X#include "ip_var.h" X X/* X * Raw interface to IP protocol. X */ X Xstruct sockaddr_in ripdst = { AF_INET }; Xstruct sockaddr_in ripsrc = { AF_INET }; Xstruct sockproto ripproto = { PF_INET }; X/* X * Setup generic address and protocol structures X * for raw_input routine, then pass them along with X * mbuf chain. X */ Xrip_input(m) X struct mbuf *m; X{ X register struct ip *ip = mtod(m, struct ip *); X X ripproto.sp_protocol = ip->ip_p; X ripdst.sin_addr = ip->ip_dst; X ripsrc.sin_addr = ip->ip_src; X raw_input(m, &ripproto, (struct sockaddr *)&ripsrc, X (struct sockaddr *)&ripdst); X} X X/* X * Generate IP header and pass packet to ip_output. X * Tack on options user may have setup with control call. X */ Xrip_output(m0, so) X struct mbuf *m0; X struct socket *so; X{ X register struct mbuf *m; X register struct ip *ip; X int len = 0, error; X struct rawcb *rp = sotorawcb(so); X struct sockaddr_in *sin; X X /* X * Calculate data length and get an mbuf X * for IP header. X */ X for (m = m0; m; m = m->m_next) X len += m->m_len; X m = m_get(M_DONTWAIT, MT_HEADER); X if (m == 0) { X error = ENOBUFS; X goto bad; X } X X /* X * Fill in IP header as needed. X */ X m->m_off = MMAXOFF - sizeof(struct ip); X m->m_len = sizeof(struct ip); X m->m_next = m0; X ip = mtod(m, struct ip *); X ip->ip_tos = 0; X ip->ip_off = 0; X ip->ip_p = rp->rcb_proto.sp_protocol; X ip->ip_len = sizeof(struct ip) + len; X if (rp->rcb_flags & RAW_LADDR) { X sin = (struct sockaddr_in *)&rp->rcb_laddr; X if (sin->sin_family != AF_INET) { X error = EAFNOSUPPORT; X goto bad; X } X ip->ip_src.s_addr = sin->sin_addr.s_addr; X } else X ip->ip_src.s_addr = 0; X ip->ip_dst = ((struct sockaddr_in *)&rp->rcb_faddr)->sin_addr; X ip->ip_ttl = MAXTTL; X return (ip_output(m, rp->rcb_options, &rp->rcb_route, X (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST)); Xbad: X m_freem(m); X return (error); X} X X/* X * Raw IP socket option processing. X */ Xrip_ctloutput(op, so, level, optname, m) X int op; X struct socket *so; X int level, optname; X struct mbuf **m; X{ X int error = 0; X register struct rawcb *rp = sotorawcb(so); X X if (level != IPPROTO_IP) X error = EINVAL; X else switch (op) { X X case PRCO_SETOPT: X switch (optname) { X case IP_OPTIONS: X return (ip_pcbopts(&rp->rcb_options, *m)); X X default: X error = EINVAL; X break; X } X break; X X case PRCO_GETOPT: X switch (optname) { X case IP_OPTIONS: X *m = m_get(M_WAIT, MT_SOOPTS); X if (rp->rcb_options) { X (*m)->m_off = rp->rcb_options->m_off; X (*m)->m_len = rp->rcb_options->m_len; X bcopy(mtod(rp->rcb_options, caddr_t), X mtod(*m, caddr_t), (unsigned)(*m)->m_len); X } else X (*m)->m_len = 0; X break; X default: X error = EINVAL; X break; X } X break; X } X if (op == PRCO_SETOPT && *m) X (void)m_free(*m); X return (error); X} END-of-netinet/raw_ip.c echo x - netinet/udp.h sed 's/^X//' >netinet/udp.h << 'END-of-netinet/udp.h' X/* X * Copyright (c) 1982, 1986 Regents of the University of California. X * All rights reserved. X * X * Redistribution and use in source and binary forms are permitted X * provided that this notice is preserved and that due credit is given X * to the University of California at Berkeley. The name of the University X * may not be used to endorse or promote products derived from this X * software without specific prior written permission. This software X * is provided ``as is'' without express or implied warranty. X * X * @(#)udp.h 7.2 (Berkeley) 12/7/87 X */ X X/* X * Udp protocol header. X * Per RFC 768, September, 1981. X */ Xstruct udphdr { X u_short uh_sport; /* source port */ X u_short uh_dport; /* destination port */ X short uh_ulen; /* udp length */ X u_short uh_sum; /* udp checksum */ X}; END-of-netinet/udp.h echo x - netinet/udp_usrreq.c sed 's/^X//' >netinet/udp_usrreq.c << 'END-of-netinet/udp_usrreq.c' X/* X * Copyright (c) 1982, 1986 Regents of the University of California. X * All rights reserved. X * X * Redistribution and use in source and binary forms are permitted X * provided that this notice is preserved and that due credit is given X * to the University of California at Berkeley. The name of the University X * may not be used to endorse or promote products derived from this X * software without specific prior written permission. This software X * is provided ``as is'' without express or implied warranty. X * X * @(#)udp_usrreq.c 7.5 (Berkeley) 3/11/88 X */ X X#include "param.h" X#include "dir.h" X#include "user.h" X#include "mbuf.h" X#include "protosw.h" X#include "socket.h" X#include "socketvar.h" X#include "errno.h" X#include "stat.h" X X#include "../net/if.h" X#include "../net/route.h" X X#include "in.h" X#include "in_pcb.h" X#include "in_systm.h" X#include "ip.h" X#include "ip_var.h" X#include "ip_icmp.h" X#include "udp.h" X#include "udp_var.h" X X/* X * UDP protocol implementation. X * Per RFC 768, August, 1980. X */ Xudp_init() X{ X X udb.inp_next = udb.inp_prev = &udb; X} X X#ifndef COMPAT_42 Xint udpcksum = 1; X#else Xint udpcksum = 0; /* XXX */ X#endif Xint udp_ttl = UDP_TTL; X Xstruct sockaddr_in udp_in = { AF_INET }; X Xudp_input(m0, ifp) X struct mbuf *m0; X struct ifnet *ifp; X{ X register struct udpiphdr *ui; X register struct inpcb *inp; X register struct mbuf *m; X int len; X struct ip ip; X X /* X * Get IP and UDP header together in first mbuf. X */ X m = m0; X if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct udpiphdr)) && X (m = m_pullup(m, sizeof (struct udpiphdr))) == 0) { X udpstat.udps_hdrops++; X return; X } X ui = mtod(m, struct udpiphdr *); X if (((struct ip *)ui)->ip_hl > (sizeof (struct ip) >> 2)) X ip_stripoptions((struct ip *)ui, (struct mbuf *)0); X X /* X * Make mbuf data length reflect UDP length. X * If not enough data to reflect UDP length, drop. X */ X len = ntohs((u_short)ui->ui_ulen); X if (((struct ip *)ui)->ip_len != len) { X if (len > ((struct ip *)ui)->ip_len) { X udpstat.udps_badlen++; X goto bad; X } X m_adj(m, len - ((struct ip *)ui)->ip_len); X /* ((struct ip *)ui)->ip_len = len; */ X } X /* X * Save a copy of the IP header in case we want restore it for ICMP. X */ X ip = *(struct ip*)ui; X X /* X * Checksum extended UDP header and data. X */ X if (udpcksum && ui->ui_sum) { X ui->ui_next = ui->ui_prev = 0; X ui->ui_x1 = 0; X ui->ui_len = ui->ui_ulen; X if (ui->ui_sum = in_cksum(m, len + sizeof (struct ip))) { X udpstat.udps_badsum++; X m_freem(m); X return; X } X } X X /* X * Locate pcb for datagram. X */ X inp = in_pcblookup(&udb, X ui->ui_src, ui->ui_sport, ui->ui_dst, ui->ui_dport, X INPLOOKUP_WILDCARD); X if (inp == 0) { X /* don't send ICMP response for broadcast packet */ X if (in_broadcast(ui->ui_dst)) X goto bad; X *(struct ip *)ui = ip; X icmp_error((struct ip *)ui, ICMP_UNREACH, ICMP_UNREACH_PORT, X ifp); X return; X } X X /* X * Construct sockaddr format source address. X * Stuff source address and datagram in user buffer. X */ X udp_in.sin_port = ui->ui_sport; X udp_in.sin_addr = ui->ui_src; X m->m_len -= sizeof (struct udpiphdr); X m->m_off += sizeof (struct udpiphdr); X if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, X m, (struct mbuf *)0) == 0) X goto bad; X sorwakeup(inp->inp_socket); X return; Xbad: X m_freem(m); X} X X/* X * Notify a udp user of an asynchronous error; X * just wake up so that he can collect error status. X */ Xudp_notify(inp) X register struct inpcb *inp; X{ X X sorwakeup(inp->inp_socket); X sowwakeup(inp->inp_socket); X} X Xudp_ctlinput(cmd, sa) X int cmd; X struct sockaddr *sa; X{ X extern u_char inetctlerrmap[]; X struct sockaddr_in *sin; X int in_rtchange(); X X if ((unsigned)cmd > PRC_NCMDS) X return; X if (sa->sa_family != AF_INET && sa->sa_family != AF_IMPLINK) X return; X sin = (struct sockaddr_in *)sa; X if (sin->sin_addr.s_addr == INADDR_ANY) X return; X X switch (cmd) { X X case PRC_QUENCH: X break; X X case PRC_ROUTEDEAD: X case PRC_REDIRECT_NET: X case PRC_REDIRECT_HOST: X case PRC_REDIRECT_TOSNET: X case PRC_REDIRECT_TOSHOST: X in_pcbnotify(&udb, &sin->sin_addr, 0, in_rtchange); X break; X X default: X if (inetctlerrmap[cmd] == 0) X return; /* XXX */ X in_pcbnotify(&udb, &sin->sin_addr, (int)inetctlerrmap[cmd], X udp_notify); X } X} X Xudp_output(inp, m0) X register struct inpcb *inp; X struct mbuf *m0; X{ X register struct mbuf *m; X register struct udpiphdr *ui; X register int len = 0; X X /* X * Calculate data length and get a mbuf X * for UDP and IP headers. X */ X for (m = m0; m; m = m->m_next) X len += m->m_len; X MGET(m, M_DONTWAIT, MT_HEADER); X if (m == 0) { X m_freem(m0); X return (ENOBUFS); X } X X /* X * Fill in mbuf with extended UDP header X * and addresses and length put into network format. X */ X m->m_off = MMAXOFF - sizeof (struct udpiphdr); X m->m_len = sizeof (struct udpiphdr); X m->m_next = m0; X ui = mtod(m, struct udpiphdr *); X ui->ui_next = ui->ui_prev = 0; X ui->ui_x1 = 0; X ui->ui_pr = IPPROTO_UDP; X ui->ui_len = htons((u_short)len + sizeof (struct udphdr)); X ui->ui_src = inp->inp_laddr; X ui->ui_dst = inp->inp_faddr; X ui->ui_sport = inp->inp_lport; X ui->ui_dport = inp->inp_fport; X ui->ui_ulen = ui->ui_len; X X /* X * Stuff checksum and output datagram. X */ X ui->ui_sum = 0; X if (udpcksum) { X if ((ui->ui_sum = in_cksum(m, sizeof (struct udpiphdr) + len)) == 0) X ui->ui_sum = 0xffff; X } X ((struct ip *)ui)->ip_len = sizeof (struct udpiphdr) + len; X ((struct ip *)ui)->ip_ttl = udp_ttl; X return (ip_output(m, inp->inp_options, &inp->inp_route, X inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST))); X} X Xint udp_sendspace = 2048; /* really max datagram size */ Xint udp_recvspace = 4 * (1024+sizeof(struct sockaddr_in)); /* 4 1K dgrams */ X X/*ARGSUSED*/ Xudp_usrreq(so, req, m, nam, rights) X struct socket *so; X int req; X struct mbuf *m, *nam, *rights; X{ X struct inpcb *inp = sotoinpcb(so); X int error = 0; X X if (req == PRU_CONTROL) X return (in_control(so, (int)m, (caddr_t)nam, X (struct ifnet *)rights)); X if (rights && rights->m_len) { X error = EINVAL; X goto release; X } X if (inp == NULL && req != PRU_ATTACH) { X error = EINVAL; X goto release; X } X switch (req) { X X case PRU_ATTACH: X if (inp != NULL) { X error = EINVAL; X break; X } X error = in_pcballoc(so, &udb); X if (error) X break; X error = soreserve(so, udp_sendspace, udp_recvspace); X if (error) X break; X break; X X case PRU_DETACH: X in_pcbdetach(inp); X break; X X case PRU_BIND: X error = in_pcbbind(inp, nam); X break; X X case PRU_LISTEN: X error = EOPNOTSUPP; X break; X X case PRU_CONNECT: X if (inp->inp_faddr.s_addr != INADDR_ANY) { X error = EISCONN; X break; X } X error = in_pcbconnect(inp, nam); X if (error == 0) X soisconnected(so); X break; X X case PRU_CONNECT2: X error = EOPNOTSUPP; X break; X X case PRU_ACCEPT: X error = EOPNOTSUPP; X break; X X case PRU_DISCONNECT: X if (inp->inp_faddr.s_addr == INADDR_ANY) { X error = ENOTCONN; X break; X } X in_pcbdisconnect(inp); X so->so_state &= ~SS_ISCONNECTED; /* XXX */ X break; X X case PRU_SHUTDOWN: X socantsendmore(so); X break; X X case PRU_SEND: { X struct in_addr laddr; X int s; X X if (nam) { X laddr = inp->inp_laddr; X if (inp->inp_faddr.s_addr != INADDR_ANY) { X error = EISCONN; X break; X } X /* X * Must block input while temporarily connected. X */ X s = splnet(); X error = in_pcbconnect(inp, nam); X if (error) { X splx(s); X break; X } X } else { X if (inp->inp_faddr.s_addr == INADDR_ANY) { X error = ENOTCONN; X break; X } X } X error = udp_output(inp, m); X m = NULL; X if (nam) { X in_pcbdisconnect(inp); X inp->inp_laddr = laddr; X splx(s); X } X } X break; X X case PRU_ABORT: X soisdisconnected(so); X in_pcbdetach(inp); X break; X X case PRU_SOCKADDR: X in_setsockaddr(inp, nam); X break; X X case PRU_PEERADDR: X in_setpeeraddr(inp, nam); X break; X X case PRU_SENSE: X /* X * stat: don't bother with a blocksize. X */ X return (0); X X case PRU_SENDOOB: X case PRU_FASTTIMO: X case PRU_SLOWTIMO: X case PRU_PROTORCV: X case PRU_PROTOSEND: X error = EOPNOTSUPP; X break; X X case PRU_RCVD: X case PRU_RCVOOB: X return (EOPNOTSUPP); /* do not free mbuf's */ X X default: X panic("udp_usrreq"); X } Xrelease: X if (m != NULL) X m_freem(m); X return (error); X} END-of-netinet/udp_usrreq.c echo x - netinet/udp_var.h sed 's/^X//' >netinet/udp_var.h << 'END-of-netinet/udp_var.h' X/* X * Copyright (c) 1982, 1986 Regents of the University of California. X * All rights reserved. X * X * Redistribution and use in source and binary forms are permitted X * provided that this notice is preserved and that due credit is given X * to the University of California at Berkeley. The name of the University X * may not be used to endorse or promote products derived from this X * software without specific prior written permission. This software X * is provided ``as is'' without express or implied warranty. X * X * @(#)udp_var.h 7.3 (Berkeley) 12/7/87 X */ X X/* X * UDP kernel structures and variables. X */ Xstruct udpiphdr { X struct ipovly ui_i; /* overlaid ip structure */ X struct udphdr ui_u; /* udp header */ X}; X#define ui_next ui_i.ih_next X#define ui_prev ui_i.ih_prev X#define ui_x1 ui_i.ih_x1 X#define ui_pr ui_i.ih_pr X#define ui_len ui_i.ih_len X#define ui_src ui_i.ih_src X#define ui_dst ui_i.ih_dst X#define ui_sport ui_u.uh_sport X#define ui_dport ui_u.uh_dport X#define ui_ulen ui_u.uh_ulen X#define ui_sum ui_u.uh_sum X Xstruct udpstat { X int udps_hdrops; X int udps_badsum; X int udps_badlen; X}; X X#define UDP_TTL 30 /* deflt time to live for UDP packets */ X X#ifdef KERNEL Xstruct inpcb udb; Xstruct udpstat udpstat; X#endif END-of-netinet/udp_var.h exit