* Copyright (c) 1984, 1985, 1986, 1987 Regents of the University of California.
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
* @(#)ns_input.c 7.4 (Berkeley) 6/29/88
#include "../net/route.h"
#include "../net/raw_cb.h"
union ns_host ns_thishost
;
union ns_host ns_zerohost
;
union ns_host ns_broadhost
;
union ns_net ns_broadnet
;
static u_short allones
[] = {-1, -1, -1};
int nsqmaxlen
= IFQ_MAXLEN
;
extern struct timeval time
;
ns_broadhost
= * (union ns_host
*) allones
;
ns_broadnet
= * (union ns_net
*) allones
;
nspcb
.nsp_next
= nspcb
.nsp_prev
= &nspcb
;
nsrawpcb
.nsp_next
= nsrawpcb
.nsp_prev
= &nsrawpcb
;
nsintrq
.ifq_maxlen
= nsqmaxlen
;
ns_pexseq
= time
.tv_usec
;
* Idp input routine. Pass to next level.
register struct idp
*idp
;
register struct nspcb
*nsp
;
* Get next datagram off input queue and get IDP header
IF_DEQUEUEIF(&nsintrq
, m
, ifp
);
if ((m
->m_off
> MMAXOFF
|| m
->m_len
< sizeof (struct idp
)) &&
(m
= m_pullup(m
, sizeof (struct idp
))) == 0) {
* Give any raw listeners a crack at the packet
for (nsp
= nsrawpcb
.nsp_next
; nsp
!= &nsrawpcb
; nsp
= nsp
->nsp_next
) {
struct mbuf
*m1
= m_copy(m
, 0, (int)M_COPYALL
);
if (m1
) idp_input(m1
, nsp
, ifp
);
idp
= mtod(m
, struct idp
*);
len
= ntohs(idp
->idp_len
);
if (oddpacketp
= len
& 1) {
len
++; /* If this packet is of odd length,
preserve garbage byte for checksum */
* Check that the amount of data in the buffers
* is as at least much as the IDP header would have us expect.
* Trim mbufs if longer than we expect.
* Drop packet if shorter than we expect.
if (idpcksum
&& ((i
= idp
->idp_sum
)!=0xffff)) {
if (i
!= (idp
->idp_sum
= ns_cksum(m
,len
))) {
if (ns_hosteqnh(ns_thishost
, idp
->idp_dna
.x_host
))
* Is this a directed broadcast?
if (ns_hosteqnh(ns_broadhost
,idp
->idp_dna
.x_host
)) {
if ((!ns_neteq(idp
->idp_dna
, idp
->idp_sna
)) &&
(!ns_neteqnn(idp
->idp_dna
.x_net
, ns_broadnet
)) &&
(!ns_neteqnn(idp
->idp_sna
.x_net
, ns_zeronet
)) &&
(!ns_neteqnn(idp
->idp_dna
.x_net
, ns_zeronet
)) ) {
* Look to see if I need to eat this packet.
* Algorithm is to forward all young packets
* and prematurely age any packets which will
* by physically broadcasted.
* Any very old packets eaten without forwarding
* Suggestion of Bill Nesheim, Cornell U.
if (idp
->idp_tc
< NS_MAXHOPS
) {
* Is this our packet? If not, forward.
} else if (!ns_hosteqnh(ns_thishost
,idp
->idp_dna
.x_host
)) {
* Locate pcb for datagram.
nsp
= ns_pcblookup(&idp
->idp_sna
, idp
->idp_dna
.x_port
, NS_WILDCARD
);
* Switch out to protocol's input routine.
if ((nsp
->nsp_flags
& NSP_ALL_PACKETS
)==0)
ns_error(m
, NS_ERR_NOSOCK
, 0);
u_char nsctlerrmap
[PRC_NCMDS
] = {
ECONNABORTED
, ECONNABORTED
, 0, 0,
0, 0, EHOSTDOWN
, EHOSTUNREACH
,
ENETUNREACH
, EHOSTUNREACH
, ECONNREFUSED
, ECONNREFUSED
,
extern struct nspcb
*idp_drop();
if (cmd
< 0 || cmd
> PRC_NCMDS
)
if (nsctlerrmap
[cmd
] == 0)
type
= NS_ERR_UNREACH_HOST
;
sns
= (struct sockaddr_ns
*)arg
;
if (sns
->sns_family
!= AF_INET
)
errp
= (struct ns_errp
*)arg
;
ns
= &errp
->ns_err_idp
.idp_dna
;
type
= ntohs((u_short
)type
);
case NS_ERR_UNREACH_HOST
:
ns_pcbnotify(ns
, (int)nsctlerrmap
[cmd
], idp_abort
, (long)0);
nsp
= ns_pcblookup(ns
, errp
->ns_err_idp
.idp_sna
.x_port
,
if(nsp
&& idp_donosocks
&& ! ns_nullhost(nsp
->nsp_faddr
))
(void) idp_drop(nsp
, (int)nsctlerrmap
[cmd
]);
* Forward a packet. If some error occurs return the sender
* an error packet. Note we can't always generate a meaningful
* error message because the NS errors don't have a large enough repetoire
register struct idp
*idp
;
register int error
, type
, code
;
struct mbuf
*mcopy
= NULL
;
int flags
= NS_FORWARDING
;
ns_printhost(&idp
->idp_sna
);
ns_printhost(&idp
->idp_dna
);
printf("hop count %d\n", idp
->idp_tc
);
if (idpforwarding
== 0) {
/* can't tell difference between net and host */
type
= NS_ERR_UNREACH_HOST
, code
= 0;
if (idp
->idp_tc
> NS_MAXHOPS
) {
type
= NS_ERR_TOO_OLD
, code
= 0;
* Save at most 42 bytes of the packet in case
* we need to generate an NS error message to the src.
mcopy
= m_copy(dtom(idp
), 0, imin((int)ntohs(idp
->idp_len
), 42));
if ((ok_there
= idp_do_route(&idp
->idp_dna
,&idp_droute
))==0) {
type
= NS_ERR_UNREACH_HOST
, code
= 0;
* Here we think about forwarding broadcast packets,
* so we try to insure that it doesn't go back out
* on the interface it came in on. Also, if we
* are going to physically broadcast this, let us
* age the packet so we can eat it safely the second time around.
if (idp
->idp_dna
.x_host
.c_host
[0] & 0x1) {
struct ns_ifaddr
*ia
= ns_iaonnetof(&idp
->idp_dna
);
/* I'm gonna hafta eat this packet */
agedelta
+= NS_MAXHOPS
- idp
->idp_tc
;
idp
->idp_tc
= NS_MAXHOPS
;
if ((ok_back
= idp_do_route(&idp
->idp_sna
,&idp_sroute
))==0) {
/* error = ENETUNREACH; He'll never get it! */
(ifp
=idp_droute
.ro_rt
->rt_ifp
) &&
(ifp
!=idp_sroute
.ro_rt
->rt_ifp
)) {
flags
|= NS_ALLOWBROADCAST
;
type
= NS_ERR_UNREACH_HOST
, code
= 0;
/* need to adjust checksum */
if (idp
->idp_sum
!=0xffff) {
x
.l
= 0; x
.c
[0] = agedelta
;
shift
= (((((int)ntohs(idp
->idp_len
))+1)>>1)-2) & 0xf;
x
.l
= idp
->idp_sum
+ (x
.s
[0] << shift
);
if (x
.l
==0xffff) idp
->idp_sum
= 0; else idp
->idp_sum
= x
.l
;
if ((error
= ns_output(dtom(idp
), &idp_droute
, flags
)) &&
idp
= mtod(mcopy
, struct idp
*);
type
= NS_ERR_UNSPEC_T
, code
= 0;
type
= NS_ERR_UNREACH_HOST
;
code
= 576; /* too hard to figure out mtu here */
ns_error(dtom(idp
), type
, code
);
idp_undo_route(&idp_droute
);
idp_undo_route(&idp_sroute
);
bzero((caddr_t
)ro
, sizeof (*ro
));
dst
= (struct sockaddr_ns
*)&ro
->ro_dst
;
dst
->sns_addr
.x_port
= 0;
if (ro
->ro_rt
== 0 || ro
->ro_rt
->rt_ifp
== 0) {
register struct route
*ro
;
if (ro
->ro_rt
) {RTFREE(ro
->ro_rt
);}
register struct nspcb
*nsp
;
register struct ifaddr
*ia
;
* Give any raw listeners a crack at the packet
for (nsp
= nsrawpcb
.nsp_next
; nsp
!= &nsrawpcb
; nsp
= nsp
->nsp_next
) {
struct mbuf
*m0
= m_copy(m
, 0, (int)M_COPYALL
);
struct mbuf
*m1
= m_get(M_DONTWAIT
, MT_DATA
);
register struct idp
*idp
;
m1
->m_len
= sizeof (*idp
);
idp
= mtod(m1
, struct idp
*);
idp
->idp_sna
.x_net
= ns_zeronet
;
idp
->idp_sna
.x_host
= ns_thishost
;
if (ifp
&& (ifp
->if_flags
& IFF_POINTOPOINT
))
for(ia
= ifp
->if_addrlist
; ia
;
if (ia
->ifa_addr
.sa_family
==AF_NS
) {
satons_addr(ia
->ifa_dstaddr
);