/* ip_input.c 1.19 81/11/26 */
#include "../h/protosw.h"
#include "../net/in_systm.h"
#include "../net/ip.h" /* belongs before in.h */
#include "../net/ip_var.h"
#include "../net/ip_icmp.h"
u_char ip_protox
[IPPROTO_MAX
];
register struct protosw
*pr
;
pr
= pffindproto(PF_INET
, IPPROTO_RAW
);
for (i
= 0; i
< IPPROTO_MAX
; i
++)
ip_protox
[i
] = pr
- protosw
;
for (pr
= protosw
; pr
<= protoswLAST
; pr
++)
if (pr
->pr_family
== PF_INET
&&
pr
->pr_protocol
&& pr
->pr_protocol
!= IPPROTO_RAW
)
ip_protox
[pr
->pr_protocol
] = pr
- protosw
;
ipq
.next
= ipq
.prev
= &ipq
;
* Ip input routine. Checksum and byte swap header. If fragmented
* try to reassamble. If complete and fragment queue exists, discard.
* Process options. Pass to next level.
* Get next datagram off input queue and get IP header
if (m
->m_len
< sizeof (struct ip
) &&
m_pullup(m
, sizeof (struct ip
)) == 0)
ip
= mtod(m
, struct ip
*);
if ((hlen
= ip
->ip_hl
<< 2) > m
->m_len
&&
if ((ip
->ip_sum
= in_cksum(m
, hlen
)) != 0xffff) {
printf("ip_sum %x\n", ip
->ip_sum
);
* Convert fields to host representation.
ip
->ip_len
= ntohs((u_short
)ip
->ip_len
);
ip
->ip_id
= ntohs(ip
->ip_id
);
ip
->ip_off
= ntohs((u_short
)ip
->ip_off
);
* Check that the amount of data in the buffers
* is as at least much as the IP header would have us expect.
* Trim mbufs if longer than we expect.
* Drop packet if shorter than we expect.
for (m0
= m
; m
!= NULL
; m
= m
->m_next
)
m_adj(m
, ip
->ip_len
- i
);
* Process options and, if not destined for us,
if (hlen
> sizeof (struct ip
))
if (ifnet
&& ip
->ip_dst
.s_addr
!= ifnet
->if_addr
.s_addr
&&
if_ifwithaddr(ip
->ip_dst
) == 0) {
icmp_error(ip
, ICMP_TIMXCEED
, 0);
ip_output(dtom(ip
), (struct mbuf
*)0);
* Look for queue of fragments
for (fp
= ipq
.next
; fp
!= &ipq
; fp
= fp
->next
)
if (ip
->ip_id
== fp
->ipq_id
&&
ip
->ip_src
.s_addr
== fp
->ipq_src
.s_addr
&&
ip
->ip_dst
.s_addr
== fp
->ipq_dst
.s_addr
&&
* Adjust ip_len to not reflect header,
* set ip_mff if more fragments are expected,
* convert offset of this to bytes.
((struct ipasfrag
*)ip
)->ipf_mff
= 0;
((struct ipasfrag
*)ip
)->ipf_mff
= 1;
* If datagram marked as having more fragments
* or if this is not the first fragment,
* attempt reassembly; if it succeeds, proceed.
if (((struct ipasfrag
*)ip
)->ipf_mff
|| ip
->ip_off
) {
ip
= ip_reass((struct ipasfrag
*)ip
, fp
);
* Switch out to protocol's input routine.
(*protosw
[ip_protox
[ip
->ip_p
]].pr_input
)(m
);
* Take incoming datagram fragment and try to
* reassemble it into whole datagram. If a chain for
* reassembly of this datagram already exists, then it
* is given as fp; otherwise have to make a chain.
register struct ipasfrag
*ip
;
register struct mbuf
*m
= dtom(ip
);
register struct ipasfrag
*q
;
int hlen
= ip
->ip_hl
<< 2;
* Presence of header sizes in mbufs
* would confuse code below.
* If first fragment to arrive, create a reassembly queue.
if ((t
= m_get(1)) == NULL
)
fp
= mtod(t
, struct ipq
*);
fp
->ipq_next
= fp
->ipq_prev
= (struct ipasfrag
*)fp
;
fp
->ipq_src
= ((struct ip
*)ip
)->ip_src
;
fp
->ipq_dst
= ((struct ip
*)ip
)->ip_dst
;
* Find a segment which begins after this one does.
for (q
= fp
->ipq_next
; q
!= (struct ipasfrag
*)fp
; q
= q
->ipf_next
)
if (q
->ip_off
> ip
->ip_off
)
* If there is a preceding segment, it may provide some of
* our data already. If so, drop the data from the incoming
* segment. If it provides all of our data, drop us.
if (q
->ipf_prev
!= (struct ipasfrag
*)fp
) {
i
= q
->ipf_prev
->ip_off
+ q
->ipf_prev
->ip_len
- ip
->ip_off
;
* While we overlap succeeding segments trim them or,
* if they are completely covered, dequeue them.
while (q
!= (struct ipasfrag
*)fp
&& ip
->ip_off
+ ip
->ip_len
> q
->ip_off
) {
i
= (ip
->ip_off
+ ip
->ip_len
) - q
->ip_off
;
m_freem(dtom(q
->ipf_prev
));
* Stick new segment in its place;
* check for complete reassembly.
for (q
= fp
->ipq_next
; q
!= (struct ipasfrag
*)fp
; q
= q
->ipf_next
) {
if (q
->ipf_prev
->ipf_mff
)
* Reassembly is complete; concatenate fragments.
while ((q
= q
->ipf_next
) != (struct ipasfrag
*)fp
)
* Create header for new ip packet by
* modifying header of first packet;
* dequeue and discard fragment reassembly header.
((struct ip
*)ip
)->ip_src
= fp
->ipq_src
;
((struct ip
*)ip
)->ip_dst
= fp
->ipq_dst
;
m
->m_len
+= sizeof (struct ipasfrag
);
m
->m_off
-= sizeof (struct ipasfrag
);
return ((struct ip
*)ip
);
* Free a fragment reassembly header and all
register struct ipasfrag
*q
;
for (q
= fp
->ipq_next
; q
!= (struct ipasfrag
*)fp
; q
= q
->ipf_next
)
* Put an ip fragment on a reassembly chain.
* Like insque, but pointers in middle of structure.
register struct ipasfrag
*p
, *prev
;
p
->ipf_next
= prev
->ipf_next
;
prev
->ipf_next
->ipf_prev
= p
;
* To ip_enq as remque is to insque.
register struct ipasfrag
*p
;
p
->ipf_prev
->ipf_next
= p
->ipf_next
;
p
->ipf_next
->ipf_prev
= p
->ipf_prev
;
* if a timer expires on a reassembly
for (fp
= ipq
.next
; fp
!= &ipq
; )
* Drain off all datagram fragments.
(void) ip_freef(ipq
.next
);
* Do option processing on a datagram,
* possibly discarding it if bad options
register struct ip_timestamp
*ipt
;
register struct ifnet
*ifp
;
cnt
= (ip
->ip_hl
<< 2) - sizeof (struct ip
);
for (; cnt
> 0; cnt
-= optlen
, cp
+= optlen
) {
* Source routing with record.
* Find interface with current destination address.
* If none on this machine then drop if strictly routed,
* or do nothing if loosely routed.
* Record interface address and bring up next address
* component. If strictly routed make sure next
* address on directly accessible net.
if (cp
[2] < 4 || cp
[2] > optlen
- (sizeof (long) - 1))
sin
= (struct in_addr
*)(cp
+ cp
[2]);
ifp
= if_ifwithaddr(*sin
);
t
= ip
->ip_dst
; ip
->ip_dst
= *sin
; *sin
= t
;
if (cp
[2] > optlen
- (sizeof (long) - 1))
if (opt
== IPOPT_SSRR
&& if_ifonnetof(ip
->ip_dst
)==0)
ipt
= (struct ip_timestamp
*)cp
;
if (ipt
->ipt_ptr
> ipt
->ipt_len
- sizeof (long)) {
if (++ipt
->ipt_oflw
== 0)
sin
= (struct in_addr
*)(cp
+cp
[2]);
if (ipt
->ipt_ptr
+ 8 > ipt
->ipt_len
)
/* stamp with ``first'' interface address */
if (if_ifwithaddr(*sin
) == 0)
if (ipt
->ipt_ptr
+ 8 > ipt
->ipt_len
)
*(n_time
*)sin
= iptime();
/* SHOULD FORCE ICMP MESSAGE */
* Strip out IP options, at higher
* level protocol in the kernel.
* Second argument is buffer to which options
* will be moved, and return value is their length.
olen
= (ip
->ip_hl
<<2) - sizeof (struct ip
);
bcopy((caddr_t
)ip
, cp
, (unsigned)olen
);
i
= m
->m_len
- (sizeof (struct ip
) + olen
);
bcopy((caddr_t
)ip
+olen
, (caddr_t
)ip
, (unsigned)i
);