* Copyright (c) 1984, 1985, 1986, 1987 Regents of the University of California.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* @(#)ns_input.c 7.8 (Berkeley) 6/27/91
#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
;
struct sockaddr_ns ns_netmask
, ns_hostmask
;
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
;
ns_netmask
.sns_addr
.x_net
= ns_broadnet
;
ns_hostmask
.sns_len
= 12;
ns_hostmask
.sns_addr
.x_net
= ns_broadnet
;
ns_hostmask
.sns_addr
.x_host
= ns_broadhost
;
* 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 ((m
->m_flags
& M_EXT
|| 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
);
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 (m
->m_pkthdr
.len
< len
) {
if (m
->m_pkthdr
.len
> len
) {
if (m
->m_len
== m
->m_pkthdr
.len
) {
m_adj(m
, len
- m
->m_pkthdr
.len
);
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_NS
)
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
= mtod(m
, struct 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(m
, 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(m
, &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 */
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_len
= sizeof(*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
*ifa
;
* 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
);
register struct idp
*idp
;
M_PREPEND(m0
, sizeof (*idp
), M_DONTWAIT
);
idp
= mtod(m0
, struct idp
*);
idp
->idp_sna
.x_net
= ns_zeronet
;
idp
->idp_sna
.x_host
= ns_thishost
;
if (ifp
&& (ifp
->if_flags
& IFF_POINTOPOINT
))
for(ifa
= ifp
->if_addrlist
; ifa
;
if (ifa
->ifa_addr
->sa_family
==AF_NS
) {
idp
->idp_sna
= IA_SNS(ifa
)->sns_addr
;
idp
->idp_len
= ntohl(m0
->m_pkthdr
.len
);