/* ip_icmp.c 6.5 84/03/13 */
#include "../h/protosw.h"
#include "../net/route.h"
#include "../netinet/in.h"
#include "../netinet/in_systm.h"
#include "../netinet/ip.h"
#include "../netinet/ip_icmp.h"
#include "../netinet/icmp_var.h"
* ICMP routines: error generation, receive packet processing, and
* routines to turnaround packets back to the originator, and
* host table maintenance routines.
* Generate an error packet of type error
* in response to bad packet ip.
icmp_error(oip
, type
, code
)
register unsigned oiplen
= oip
->ip_hl
<< 2;
register struct icmp
*icp
;
printf("icmp_error(%x, %d, %d)\n", oip
, type
, code
);
* Make sure that the old IP packet had 8 bytes of data to return;
* if not, don't bother. Also don't EVER error if the old
* packet protocol was ICMP.
icmpstat
.icps_oldshort
++;
if (oip
->ip_p
== IPPROTO_ICMP
) {
* First, formulate icmp message
m
= m_get(M_DONTWAIT
, MT_HEADER
);
m
->m_len
= oiplen
+ 8 + ICMP_MINLEN
;
m
->m_off
= MMAXOFF
- m
->m_len
;
icp
= mtod(m
, struct icmp
*);
if ((u_int
)type
> ICMP_IREQREPLY
)
icmpstat
.icps_outhist
[type
]++;
if (type
== ICMP_PARAMPROB
) {
bcopy((caddr_t
)oip
, (caddr_t
)&icp
->icmp_ip
, oiplen
+ 8);
nip
->ip_len
= htons((u_short
)nip
->ip_len
);
* Now, copy old ip header in front of icmp
* message. This allows us to reuse any source
nip
= mtod(m
, struct ip
*);
bcopy((caddr_t
)oip
, (caddr_t
)nip
, oiplen
);
nip
->ip_len
= m
->m_len
+ oiplen
;
nip
->ip_p
= IPPROTO_ICMP
;
/* icmp_send adds ip header to m_off and m_len, so we deduct here */
static struct sockproto icmproto
= { AF_INET
, IPPROTO_ICMP
};
static struct sockaddr_in icmpsrc
= { AF_INET
};
static struct sockaddr_in icmpdst
= { AF_INET
};
* Process a received ICMP message.
register struct icmp
*icp
;
register struct ip
*ip
= mtod(m
, struct ip
*);
int icmplen
= ip
->ip_len
, hlen
= ip
->ip_hl
<< 2;
extern u_char ip_protox
[];
* Locate icmp structure in mbuf, and check
* that not corrupted and of at least minimum length.
printf("icmp_input from %x, len %d\n", ip
->ip_src
, icmplen
);
if (icmplen
< ICMP_MINLEN
) {
icmpstat
.icps_tooshort
++;
/* THIS LENGTH CHECK STILL MISSES ANY IP OPTIONS IN ICMP_IP */
i
= MIN(icmplen
, ICMP_ADVLENMIN
+ hlen
);
if ((m
->m_off
> MMAXOFF
|| m
->m_len
< i
) &&
(m
= m_pullup(m
, i
)) == 0) {
icmpstat
.icps_tooshort
++;
ip
= mtod(m
, struct ip
*);
icp
= mtod(m
, struct icmp
*);
if (in_cksum(m
, icmplen
)) {
icmpstat
.icps_checksum
++;
* Message type specific processing.
printf("icmp_input, type %d code %d\n", icp
->icmp_type
,
if (icp
->icmp_type
> ICMP_IREQREPLY
)
icmpstat
.icps_inhist
[icp
->icmp_type
]++;
switch (icp
->icmp_type
) {
code
+= PRC_TIMXCEED_INTRANS
;
* Problem with datagram; advise higher level routines.
icp
->icmp_ip
.ip_len
= ntohs((u_short
)icp
->icmp_ip
.ip_len
);
if (icmplen
< ICMP_ADVLENMIN
|| icmplen
< ICMP_ADVLEN(icp
)) {
printf("deliver to protocol %d\n", icp
->icmp_ip
.ip_p
);
if (ctlfunc
= inetsw
[ip_protox
[icp
->icmp_ip
.ip_p
]].pr_ctlinput
)
(*ctlfunc
)(code
, (caddr_t
)icp
);
icp
->icmp_type
= ICMP_ECHOREPLY
;
if (icmplen
< ICMP_TSLEN
) {
icp
->icmp_type
= ICMP_TSTAMPREPLY
;
icp
->icmp_rtime
= iptime();
icp
->icmp_ttime
= icp
->icmp_rtime
; /* bogus, do later! */
/* fill in source address zero fields! */
goto free
; /* not yet implemented: ignore */
if (icmplen
< ICMP_ADVLENMIN
|| icmplen
< ICMP_ADVLEN(icp
)) {
* Short circuit routing redirects to force
* immediate change in the kernel's routing
* tables. The message is also handed to anyone
* listening on a raw socket (e.g. the routing
* daemon for use in updating it's tables).
icmpsrc
.sin_addr
= icp
->icmp_ip
.ip_dst
;
icmpdst
.sin_addr
= icp
->icmp_gwaddr
;
rtredirect((struct sockaddr
*)&icmpsrc
,
(struct sockaddr
*)&icmpdst
,
(code
== ICMP_REDIRECT_NET
|| code
== ICMP_REDIRECT_TOSNET
) ?
RTF_GATEWAY
: (RTF_GATEWAY
| RTF_HOST
));
icmpsrc
.sin_addr
= ip
->ip_src
;
icmpdst
.sin_addr
= ip
->ip_dst
;
raw_input(dtom(icp
), &icmproto
, (struct sockaddr
*)&icmpsrc
,
(struct sockaddr
*)&icmpdst
);
ip
->ip_len
+= hlen
; /* since ip_input deducts this */
* Reflect the ip packet back to the source
* TODO: rearrange ip source routing options.
* Send an icmp packet back to the ip level,
* after supplying a checksum.
register struct icmp
*icp
;
icp
= mtod(m
, struct icmp
*);
icp
->icmp_cksum
= in_cksum(m
, ip
->ip_len
- hlen
);
printf("icmp_send dst %x src %x\n", ip
->ip_dst
, ip
->ip_src
);
(void) ip_output(m
, (struct mbuf
*)0, (struct route
*)0, 0);
t
= (time
.tv_sec
% (24*60*60)) * 1000 + time
.tv_usec
/ 1000;