125202Skarels #include "../h/param.h"
225202Skarels #include "../h/systm.h"
325202Skarels #include "../h/mbuf.h"
425202Skarels #include "../h/socket.h"
525202Skarels #include "../h/socketvar.h"
625202Skarels #include "../h/protosw.h"
725202Skarels #include "../h/syslog.h"
825202Skarels 
925202Skarels #include "../net/if.h"
1025202Skarels #include "../net/route.h"
1125202Skarels 
1225202Skarels #include "../bbnnet/in.h"
1325202Skarels #include "../bbnnet/net.h"
1425202Skarels #include "../bbnnet/in_pcb.h"
1525202Skarels #include "../bbnnet/in_var.h"
1625202Skarels #include "../bbnnet/ip.h"
1725202Skarels #include "../bbnnet/icmp.h"
1825202Skarels #include "../bbnnet/nopcb.h"
1925202Skarels 
2025202Skarels extern struct ifnet *inetifp;
2125202Skarels 
2225202Skarels /*
2325202Skarels  * We are generating an ICMP error message in response to this packet sent
2425202Skarels  * to us.  Too bad the device driver doesn't pair a pointer to its ifnet with
2525202Skarels  * the incoming packet.  That would save us a search, and we could use that
2625202Skarels  * for our source address in the ICMP error message.
2725202Skarels  *
2825202Skarels  * Pick a source address for that ICMP error message we send.  We can't
2925202Skarels  * always use ip_dst of the original for the ip_src of the ICMP error
3025202Skarels  * message since the packet may have been broadcast.
3125202Skarels  *
3225202Skarels  * We try to establish a proper interface to respond by in case we're
3325202Skarels  * multi-homed.  Try to respond by interface received on rather than
3425202Skarels  * interface that represents most direct route back.
3525202Skarels  */
3625202Skarels struct in_addr icmp_addr (ip)
3725202Skarels struct ip	*ip;
3825202Skarels {
3925202Skarels     struct in_ifaddr *ia;
4025202Skarels 
4125202Skarels #ifdef bsd42
4225202Skarels     /* don't want broadcasts to match */
4325202Skarels     if (! (ia = in_iawithaddr(ip->ip_dst, FALSE)))
4425202Skarels     {
4525202Skarels 	/* hmm, try for the net... */
4625202Skarels 	if ((ia = in_iawithnet(ip->ip_dst)) == NULL)
4725202Skarels 	{
4825202Skarels 	    struct in_addr l;
4925202Skarels 
5025202Skarels 	    /*
5125202Skarels 	     * The message will be sent by ip_send() who will
5225202Skarels 	     * route the message and discover that a local address
5325202Skarels 	     * should be set on the basis of the route used.
5425202Skarels 	     */
5525202Skarels 	    l.s_addr = INADDR_ANY;
5625202Skarels 	    return (l);
5725202Skarels 	}
5825202Skarels     }
5925202Skarels #endif
6025202Skarels     ia = in_iafromif(inetifp);
6125202Skarels     return (IA_INADDR(ia));
6225202Skarels }
6325202Skarels 
6425202Skarels /*
6525202Skarels  * notes to above mostly apply
6625202Skarels  *
6725202Skarels  * icmp_addr() sort of assumes the packet was addressed to us.  But when we
6825202Skarels  * act as a getway, S sends to A1, and we use A2 to get to D.  We want to
6925202Skarels  * reply with the A1 address, not the A2 address.
7025202Skarels  */
7125202Skarels struct in_addr redir_addr (ip)
7225202Skarels struct ip	*ip;
7325202Skarels {
7425202Skarels     register struct in_ifaddr *ia;
7525202Skarels 
7625202Skarels #ifdef bsd42
7725202Skarels     /* note we use ip_src, not ip_dst here */
7825202Skarels     if ((ia = in_iawithnet(ip->ip_src)) == NULL)
7925202Skarels     {
8025202Skarels 	struct in_addr l;
8125202Skarels 
8225202Skarels 	l.s_addr = INADDR_ANY;
8325202Skarels 	return (l);
8425202Skarels     }
8525202Skarels #endif
8625202Skarels     ia = in_iafromif(inetifp);
8725202Skarels     return (IA_INADDR(ia));
8825202Skarels }
8925202Skarels 
9025202Skarels /*
9125202Skarels  * There are a few icmp output routines since the header has some variable
9225202Skarels  * types in it ...
9325202Skarels  */
9425202Skarels send_redirect (redirip, use, code, icmplen)
9525202Skarels struct ip	*redirip;
9625202Skarels struct in_addr	 use;
9725202Skarels unsigned icmplen;
9825202Skarels {
9925202Skarels     register struct mbuf	*m;
10025202Skarels     int error;
10125202Skarels 
10225202Skarels     if (m = m_get(M_DONTWAIT, MT_HEADER))
10325202Skarels     {
10425202Skarels 	m->m_len = ICMPSIZE + icmplen;
10525202Skarels 	m->m_off = MMAXOFF - m->m_len;
10625202Skarels 	{
10725202Skarels 	register struct icmp	*ic;
10825202Skarels 
10925202Skarels 	ic = mtod(m, struct icmp *);
11025202Skarels 	ic->ic_type = ICMP_REDIR;
11125202Skarels 	ic->ic_code = code;
11225202Skarels 	ic->ic_sum = 0;
11325202Skarels 	ic->ic_gaddr = use;
11425202Skarels 	if (icmplen > 0)
11525202Skarels 	    bcopy ((caddr_t)redirip, ic->ic_data, icmplen);
11625202Skarels 
11725202Skarels 	/* used to use an inline cksum here  */
11825202Skarels 	ic->ic_sum = in_cksum (m, m->m_len);
11925202Skarels 	}
12025202Skarels 
12125202Skarels 	m->m_off -= sizeof(struct ip);
12225202Skarels 	m->m_len += sizeof(struct ip);
12325202Skarels 	{
12425202Skarels 	register struct ip	*ip;
12525202Skarels 
12625202Skarels 	ip = mtod(m, struct ip *);
12725202Skarels 	ip->ip_p = IPPROTO_ICMP;
12825202Skarels 	ip->ip_tos = 0;
12925202Skarels 	ip->ip_dst = redirip->ip_src;
13025202Skarels 	ip->ip_src = redir_addr(redirip);
13125202Skarels 	}
13225202Skarels 	NOPCB_IPSEND (m, (int)icmplen, FALSE, error);
13325202Skarels 
13425202Skarels #ifdef lint
13525202Skarels 	error = error ;
13625202Skarels #endif
13725202Skarels     }
13825202Skarels }
13925202Skarels 
14025202Skarels /*
14125202Skarels  * Send an ICMP error message.  Note that data must not exceed single mbuf.
14225202Skarels  */
14325202Skarels ic_errmsg (src, dst, type, code, off, dlen, dp)
14425202Skarels struct in_addr	 src;
14525202Skarels struct in_addr  dst;
14625202Skarels unsigned dlen;
14725202Skarels caddr_t dp;	/* assumed to be contiguous */
14825202Skarels {
14925202Skarels     register struct mbuf	*m;
15025202Skarels     register unsigned	 len;
15125202Skarels     int error;
15225202Skarels 
15325202Skarels     if ((m = m_get(M_DONTWAIT, MT_HEADER)) == NULL)
15425202Skarels 	return /*ENOBUFS*/;
15525202Skarels 
15625202Skarels     /*
15725202Skarels      * Build ICMP header
15825202Skarels      */
15925202Skarels     len = ICMPSIZE + dlen;
16025202Skarels     m->m_off = MMAXOFF - len;
16125202Skarels     if (m->m_off < (MMINOFF + sizeof(struct ip)))
16225202Skarels     {
163*25205Skarels 	log (LOG_INFO, "ic_errmsg len %d", len);
16425202Skarels 	m_free (m);
16525202Skarels 	return;
16625202Skarels     }
16725202Skarels     m->m_len = len;
16825202Skarels 
16925202Skarels     /* ICMP header */
17025202Skarels     {
17125202Skarels 	register struct icmp	*ic;
17225202Skarels 
17325202Skarels 	ic = mtod(m, struct icmp *);
17425202Skarels 	ic->ic_type	= type;
17525202Skarels 	ic->ic_code	= code;
17625202Skarels 	ic->ic_off	= off;
17725202Skarels 	if (dlen > 0)
17825202Skarels 	    bcopy(dp, ic->ic_data, dlen);
17925202Skarels 	ic->ic_sum	= 0;
18025202Skarels 	ic->ic_sum	= in_cksum(m, len);
18125202Skarels     }
18225202Skarels 
18325202Skarels     /* IP header */
18425202Skarels     {
18525202Skarels 	register struct ip	*ip;
18625202Skarels 
18725202Skarels 	m->m_off -= sizeof(struct ip);
18825202Skarels 	m->m_len += sizeof(struct ip);
18925202Skarels 	ip = mtod(m, struct ip *);
19025202Skarels 	ip->ip_p	= IPPROTO_ICMP;
19125202Skarels 	ip->ip_tos	= 0;
19225202Skarels 	ip->ip_src	= src;
19325202Skarels 	ip->ip_dst	= dst;
19425202Skarels     }
19525202Skarels 
19625202Skarels     NOPCB_IPSEND (m, (int)len, FALSE, error);
19725202Skarels 
19825202Skarels #ifdef lint
19925202Skarels     error = error;
20025202Skarels #endif
20125202Skarels }
20225202Skarels 
20325202Skarels #ifdef BBNPING
20425202Skarels ping(gwaddr)
20525202Skarels struct in_addr gwaddr;
20625202Skarels {
20725202Skarels     register struct mbuf *m;
20825202Skarels 
20925202Skarels     if ((m = m_get(M_DONTWAIT, MT_HEADER)) == NULL)
21025202Skarels 	return;
21125202Skarels     m->m_off = MMAXOFF - ICMPSIZE;
21225202Skarels     m->m_len = ICMPSIZE;
21325202Skarels     {
21425202Skarels 	register struct icmp *ic;
21525202Skarels 
21625202Skarels 	ic = mtod (m, struct icmp *);
21725202Skarels 	ic->ic_type	= ICMP_ECHO;
21825202Skarels 	ic->ic_code	= 0;
21925202Skarels 	ic->ic_id	= MY_ECHO_ID;
22025202Skarels 	ic->ic_sum	= 0;
22125202Skarels 	ic->ic_sum	= in_cksum(m, ICMPSIZE);
22225202Skarels     }
22325202Skarels 
22425202Skarels     m->m_off -= sizeof(struct ip);
22525202Skarels     m->m_len += sizeof(struct ip);
22625202Skarels     {
22725202Skarels 	register struct ip *ip;
22825202Skarels 
22925202Skarels 	ip = mtod(m, struct ip *);
23025202Skarels 	ip->ip_p	= IPPROTO_ICMP;
23125202Skarels 	ip->ip_tos	= 0;
23225202Skarels 	ip->ip_dst	= gwaddr;
23325202Skarels 	ip->ip_src	= icmp_addr (ip);
23425202Skarels     }
23525202Skarels 
23625202Skarels     {
23725202Skarels 	register int error;
23825202Skarels 
23925202Skarels 	NOPCB_IPSEND (m, ICMPSIZE, FALSE, error);
24025202Skarels #ifdef lint
24125202Skarels 	error = error;
24225202Skarels #endif
24325202Skarels     }
24425202Skarels }
24525202Skarels #endif
246