/* ip_input.c 1.9 81/10/29 */
#include "../inet/inet.h"
#include "../inet/inet_systm.h"
#include "../inet/ip.h" /* belongs before inet.h */
#include "../inet/ip_icmp.h"
* 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.
register struct ip
*ip
, *q
;
register struct mbuf
*m
= m0
;
* Check header and byteswap.
ip
= mtod(m
, struct ip
*);
if ((hlen
= ip
->ip_hl
<< 2) > m
->m_len
) {
printf("ip hdr ovflo\n");
if (hlen
== sizeof (struct ip
)) {
asm("movl r10,r0; movl (r0)+,r1; addl2 (r0)+,r1");
asm("adwc (r0)+,r1; adwc (r0)+,r1; adwc (r0)+,r1");
asm("adwc $0,r1; ashl $-16,r1,r0; addw2 r0,r1");
asm("adwc $0,r1"); /* ### */
asm("mcoml r1,r1; movzwl r1,r1; subl2 r1,r11");
ip
->ip_len
= ntohs(ip
->ip_len
);
ip
->ip_id
= ntohs(ip
->ip_id
);
ip
->ip_off
= ntohs(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 (; m
!= NULL
; m
= m
->m_next
)
printf("ip_input: short packet\n");
m_adj(m
, ip
->ip_len
- i
);
* Process options and, if not destined for us,
if (hlen
> sizeof (struct ip
))
if (ip
->ip_dst
.s_addr
!= n_lhost
.s_addr
) {
icmp_error(ip
, ICMP_TIMXCEED
);
* 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.
* If datagram marked as having more fragments
* or if this is not the first fragment,
* attempt reassembly; if it succeeds, proceed.
if (ip
->ip_mff
|| ip
->ip_off
) {
* Switch out to protocol specific routine.
* SHOULD GO THROUGH PROTOCOL SWITCH TABLE
if (hlen
> sizeof (struct ip
))
ip_stripoptions(ip
, hlen
);
if (hlen
> sizeof (struct ip
))
ip_stripoptions(ip
, hlen
);
* Take incoming datagram fragment and try to
* reassamble 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 mbuf
*m
= dtom(ip
);
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 ip
*)fp
;
fp
->ipq_src
= ip
->ip_src
;
fp
->ipq_dst
= ip
->ip_dst
;
* Find a segment which begins after this one does.
for (q
= fp
->ipq_next
; q
!= (struct ip
*)fp
; q
= q
->ip_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
->ip_prev
!= (struct ip
*)fp
) {
i
= q
->ip_prev
->ip_off
+ q
->ip_prev
->ip_len
- ip
->ip_off
;
* While we overlap succeeding segments trim them or,
* if they are completely covered, dequeue them.
while (q
!= (struct ip
*)fp
&& ip
->ip_off
+ ip
->ip_len
> q
->ip_off
) {
i
= (ip
->ip_off
+ ip
->ip_len
) - q
->ip_off
;
m_freem(dtom(q
->ip_prev
));
* Stick new segment in its place;
* check for complete reassembly.
for (q
= fp
->ipq_next
; q
!= (struct ip
*)fp
; q
= q
->ip_next
) {
* Reassembly is complete; concatenate fragments.
while ((q
= q
->ip_next
) != (struct ip
*)fp
)
* Create header for new ip packet by
* modifying header of first packet;
* dequeue and discard fragment reassembly header.
ip
->ip_src
= fp
->ipq_src
;
ip
->ip_dst
= fp
->ipq_dst
;
m
->m_len
+= sizeof (struct ip
);
m
->m_off
-= sizeof (struct ip
);
* Free a fragment reassembly header and all
for (q
= fp
->ipq_next
; q
!= (struct ip
*)fp
; q
= q
->ip_next
)
* Put an ip fragment on a reassembly chain.
* Like insque, but pointers in middle of structure.
register struct ip
*prev
;
p
->ip_next
= prev
->ip_next
;
prev
->ip_next
->ip_prev
= p
;
* To ip_enq as remque is to insque.
p
->ip_prev
->ip_next
= p
->ip_next
;
p
->ip_next
->ip_prev
= p
->ip_prev
;
* if a timer expires on a reassembly
for (fp
= ipq
.next
; fp
!= &ipq
; )
timeout(ip_timeo
, 0, hz
);
* Do option processing on a datagram,
* possibly discarding it if bad options
cnt
= (ip
->ip_hl
<< 2) - sizeof (struct ip
);
for (; cnt
> 0; cnt
-= optlen
, cp
+= optlen
) {
if (cp
[2] < 4 || cp
[2] > optlen
- 3)
sp
= (struct socket
*)(cp
+cp
[2]);
if (n_lhost
.s_addr
== *(u_long
*)sp
) {
/* make sure *sp directly accessible*/
if ((cp
[3] & 0xf0) == 0xf0)
sp
= (struct socket
*)(cp
+cp
[2]);
if (*(u_long
*)sp
!= n_lhost
.s_addr
)
*(int *)sp
= (time
% SECDAY
) * 1000 + (lbolt
*1000/hz
);
/* SHOULD FORCE ICMP MESSAGE */
* Strip out IP options, e.g. before passing
* to higher level protocol in the kernel.
olen
= (ip
->ip_hl
<<2) - sizeof (struct ip
);
i
= m
->m_len
- (sizeof (struct ip
) + olen
);
bcopy((caddr_t
)ip
+olen
, (caddr_t
)ip
, i
);
printf("icmp_input %x\n", m
);
printf("udp_input %x\n", m
);
printf("raw_input %x\n", m
);