Thread View: comp.bugs.4bsd.ucb-fixes
1 messages
1 total messages
Started by Keith Bostic
Tue, 05 Apr 1988 03:18
V1.50 ((inet 4 of 4) updated IP/TCP and XNS sources for 4.3BSD)
Author: Keith Bostic
Date: Tue, 05 Apr 1988 03:18
Date: Tue, 05 Apr 1988 03:18
2950 lines
78925 bytes
78925 bytes
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
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads