2 * Copyright (c) 1984, 1985, 1986, 1987, 1993
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * @(#)ns_input.c 8.1 (Berkeley) 6/10/93
34 * $FreeBSD: src/sys/netns/ns_input.c,v 1.13 2000/02/13 03:32:04 peter Exp $
35 * $DragonFly: src/sys/netproto/ns/ns_input.c,v 1.20 2007/05/23 08:57:08 dillon Exp $
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/malloc.h>
42 #include <sys/domain.h>
43 #include <sys/protosw.h>
44 #include <sys/socket.h>
45 #include <sys/socketvar.h>
46 #include <sys/errno.h>
48 #include <sys/kernel.h>
50 #include <sys/thread2.h>
51 #include <sys/msgport2.h>
54 #include <net/route.h>
55 #include <net/raw_cb.h>
56 #include <net/netisr.h>
65 extern void spp_input(struct mbuf
*, ...); /* spp_usrreq.c XXX */
70 union ns_host ns_thishost
;
71 union ns_host ns_zerohost
;
72 union ns_host ns_broadhost
;
73 union ns_net ns_zeronet
;
74 union ns_net ns_broadnet
;
75 struct sockaddr_ns ns_netmask
, ns_hostmask
;
77 static u_short allones
[] = {-1, -1, -1};
79 struct nspcb nsrawpcb
;
84 static void nsintr(struct netmsg
*msg
);
89 ns_broadhost
= * (union ns_host
*) allones
;
90 ns_broadnet
= * (union ns_net
*) allones
;
91 nspcb
.nsp_next
= nspcb
.nsp_prev
= &nspcb
;
92 nsrawpcb
.nsp_next
= nsrawpcb
.nsp_prev
= &nsrawpcb
;
94 ns_netmask
.sns_len
= 6;
95 ns_netmask
.sns_addr
.x_net
= ns_broadnet
;
96 ns_hostmask
.sns_len
= 12;
97 ns_hostmask
.sns_addr
.x_net
= ns_broadnet
;
98 ns_hostmask
.sns_addr
.x_host
= ns_broadhost
;
99 netisr_register(NETISR_NS
, cpu0_portfn
, nsintr
);
103 * Idp input routine. Pass to next level.
105 int nsintr_getpck
= 0;
106 int nsintr_swtch
= 0;
109 nsintr(struct netmsg
*msg
)
111 struct mbuf
*m
= ((struct netmsg_packet
*)msg
)->nm_packet
;
119 * Get IDP header in first mbuf.
122 if ((m
->m_flags
& M_EXT
|| m
->m_len
< sizeof (struct idp
)) &&
123 (m
= m_pullup(m
, sizeof (struct idp
))) == 0) {
124 idpstat
.idps_toosmall
++;
129 * Give any raw listeners a crack at the packet
131 for (nsp
= nsrawpcb
.nsp_next
; nsp
!= &nsrawpcb
; nsp
= nsp
->nsp_next
) {
132 struct mbuf
*m1
= m_copy(m
, 0, (int)M_COPYALL
);
133 if (m1
) idp_input(m1
, nsp
);
136 idp
= mtod(m
, struct idp
*);
137 len
= ntohs(idp
->idp_len
);
138 if ((oddpacketp
= (len
& 1))) {
139 len
++; /* If this packet is of odd length,
140 preserve garbage byte for checksum */
144 * Check that the amount of data in the buffers
145 * is as at least much as the IDP header would have us expect.
146 * Trim mbufs if longer than we expect.
147 * Drop packet if shorter than we expect.
149 if (m
->m_pkthdr
.len
< len
) {
150 idpstat
.idps_tooshort
++;
153 if (m
->m_pkthdr
.len
> len
) {
154 if (m
->m_len
== m
->m_pkthdr
.len
) {
156 m
->m_pkthdr
.len
= len
;
158 m_adj(m
, len
- m
->m_pkthdr
.len
);
160 if (idpcksum
&& ((i
= idp
->idp_sum
)!=0xffff)) {
162 if (i
!= (idp
->idp_sum
= ns_cksum(m
, len
))) {
163 idpstat
.idps_badsum
++;
165 if (ns_hosteqnh(ns_thishost
, idp
->idp_dna
.x_host
))
166 error
= NS_ERR_BADSUM
;
168 error
= NS_ERR_BADSUM_T
;
169 ns_error(m
, error
, 0);
174 * Is this a directed broadcast?
176 if (ns_hosteqnh(ns_broadhost
,idp
->idp_dna
.x_host
)) {
177 if ((!ns_neteq(idp
->idp_dna
, idp
->idp_sna
)) &&
178 (!ns_neteqnn(idp
->idp_dna
.x_net
, ns_broadnet
)) &&
179 (!ns_neteqnn(idp
->idp_sna
.x_net
, ns_zeronet
)) &&
180 (!ns_neteqnn(idp
->idp_dna
.x_net
, ns_zeronet
)) ) {
182 * Look to see if I need to eat this packet.
183 * Algorithm is to forward all young packets
184 * and prematurely age any packets which will
185 * by physically broadcasted.
186 * Any very old packets eaten without forwarding
189 * Suggestion of Bill Nesheim, Cornell U.
191 if (idp
->idp_tc
< NS_MAXHOPS
) {
197 * Is this our packet? If not, forward.
199 } else if (!ns_hosteqnh(ns_thishost
,idp
->idp_dna
.x_host
)) {
204 * Locate pcb for datagram.
206 nsp
= ns_pcblookup(&idp
->idp_sna
, idp
->idp_dna
.x_port
, NS_WILDCARD
);
208 * Switch out to protocol's input routine.
215 if ((nsp
->nsp_flags
& NSP_ALL_PACKETS
)==0)
216 switch (idp
->idp_pt
) {
228 ns_error(m
, NS_ERR_NOSOCK
, 0);
236 /* msg was embedded in the mbuf, do not reply! */
239 u_char nsctlerrmap
[PRC_NCMDS
] = {
240 ECONNABORTED
, ECONNABORTED
, 0, 0,
241 0, 0, EHOSTDOWN
, EHOSTUNREACH
,
242 ENETUNREACH
, EHOSTUNREACH
, ECONNREFUSED
, ECONNREFUSED
,
247 int idp_donosocks
= 1;
250 idp_ctlinput(int cmd
, caddr_t arg
)
254 struct ns_errp
*errp
= (struct ns_errp
*)arg
; /* XXX */
257 if (cmd
< 0 || cmd
> PRC_NCMDS
)
259 if (nsctlerrmap
[cmd
] == 0)
261 type
= NS_ERR_UNREACH_HOST
;
263 struct sockaddr_ns
*sns
;
267 case PRC_HOSTUNREACH
:
268 sns
= (struct sockaddr_ns
*)arg
;
269 if (sns
->sns_family
!= AF_NS
)
275 errp
= (struct ns_errp
*)arg
;
276 ns
= &errp
->ns_err_idp
.idp_dna
;
277 type
= errp
->ns_err_num
;
278 type
= ntohs((u_short
)type
);
282 case NS_ERR_UNREACH_HOST
:
283 ns_pcbnotify(ns
, (int)nsctlerrmap
[cmd
], idp_abort
, (long)0);
287 nsp
= ns_pcblookup(ns
, errp
->ns_err_idp
.idp_sna
.x_port
,
289 if(nsp
&& idp_donosocks
&& ! ns_nullhost(nsp
->nsp_faddr
))
290 idp_drop(nsp
, (int)nsctlerrmap
[cmd
]);
295 int idpforwarding
= 1;
297 * Forward a packet. If some error occurs return the sender
298 * an error packet. Note we can't always generate a meaningful
299 * error message because the NS errors don't have a large enough repetoire
300 * of codes and types.
302 struct route idp_droute
;
303 struct route idp_sroute
;
306 idp_forward(struct mbuf
*m
)
308 struct idp
*idp
= mtod(m
, struct idp
*);
309 int error
, type
, code
;
310 struct mbuf
*mcopy
= NULL
;
312 int flags
= NS_FORWARDING
;
317 kprintf("forward: src ");
318 ns_printhost(&idp
->idp_sna
);
320 ns_printhost(&idp
->idp_dna
);
321 kprintf("hop count %d\n", idp
->idp_tc
);
323 if (idpforwarding
== 0) {
324 /* can't tell difference between net and host */
325 type
= NS_ERR_UNREACH_HOST
, code
= 0;
329 if (idp
->idp_tc
> NS_MAXHOPS
) {
330 type
= NS_ERR_TOO_OLD
, code
= 0;
334 * Save at most 42 bytes of the packet in case
335 * we need to generate an NS error message to the src.
337 mcopy
= m_copy(m
, 0, imin((int)ntohs(idp
->idp_len
), 42));
339 if ((ok_there
= idp_do_route(&idp
->idp_dna
,&idp_droute
))==0) {
340 type
= NS_ERR_UNREACH_HOST
, code
= 0;
344 * Here we think about forwarding broadcast packets,
345 * so we try to insure that it doesn't go back out
346 * on the interface it came in on. Also, if we
347 * are going to physically broadcast this, let us
348 * age the packet so we can eat it safely the second time around.
350 if (idp
->idp_dna
.x_host
.c_host
[0] & 0x1) {
351 struct ns_ifaddr
*ia
= ns_iaonnetof(&idp
->idp_dna
);
354 /* I'm gonna hafta eat this packet */
355 agedelta
+= NS_MAXHOPS
- idp
->idp_tc
;
356 idp
->idp_tc
= NS_MAXHOPS
;
358 if ((ok_back
= idp_do_route(&idp
->idp_sna
,&idp_sroute
))==0) {
359 /* error = ENETUNREACH; He'll never get it! */
363 if (idp_droute
.ro_rt
&&
364 (ifp
=idp_droute
.ro_rt
->rt_ifp
) &&
366 (ifp
!=idp_sroute
.ro_rt
->rt_ifp
)) {
367 flags
|= NS_ALLOWBROADCAST
;
369 type
= NS_ERR_UNREACH_HOST
, code
= 0;
373 /* need to adjust checksum */
374 if (idp
->idp_sum
!=0xffff) {
381 x
.l
= 0; x
.c
[0] = agedelta
;
382 shift
= (((((int)ntohs(idp
->idp_len
))+1)>>1)-2) & 0xf;
383 x
.l
= idp
->idp_sum
+ (x
.s
[0] << shift
);
384 x
.l
= x
.s
[0] + x
.s
[1];
385 x
.l
= x
.s
[0] + x
.s
[1];
386 if (x
.l
==0xffff) idp
->idp_sum
= 0; else idp
->idp_sum
= x
.l
;
388 if ((error
= ns_output(m
, &idp_droute
, flags
)) &&
390 idp
= mtod(mcopy
, struct idp
*);
391 type
= NS_ERR_UNSPEC_T
, code
= 0;
399 type
= NS_ERR_UNREACH_HOST
;
403 type
= NS_ERR_TOO_BIG
;
404 code
= 576; /* too hard to figure out mtu here */
408 type
= NS_ERR_UNSPEC_T
;
413 ns_error(m
, type
, code
);
417 idp_undo_route(&idp_droute
);
419 idp_undo_route(&idp_sroute
);
425 idp_do_route(struct ns_addr
*src
, struct route
*ro
)
428 struct sockaddr_ns
*dst
;
430 bzero((caddr_t
)ro
, sizeof (*ro
));
431 dst
= (struct sockaddr_ns
*)&ro
->ro_dst
;
433 dst
->sns_len
= sizeof(*dst
);
434 dst
->sns_family
= AF_NS
;
435 dst
->sns_addr
= *src
;
436 dst
->sns_addr
.x_port
= 0;
438 if (ro
->ro_rt
== 0 || ro
->ro_rt
->rt_ifp
== 0) {
446 idp_undo_route(struct route
*ro
)
448 if (ro
->ro_rt
) {RTFREE(ro
->ro_rt
);}
452 ns_watch_output(struct mbuf
*m
, struct ifnet
*ifp
)
457 * Give any raw listeners a crack at the packet
459 for (nsp
= nsrawpcb
.nsp_next
; nsp
!= &nsrawpcb
; nsp
= nsp
->nsp_next
) {
460 struct mbuf
*m0
= m_copy(m
, 0, (int)M_COPYALL
);
464 M_PREPEND(m0
, sizeof (*idp
), MB_DONTWAIT
);
467 idp
= mtod(m0
, struct idp
*);
468 idp
->idp_sna
.x_net
= ns_zeronet
;
469 idp
->idp_sna
.x_host
= ns_thishost
;
470 if (ifp
&& (ifp
->if_flags
& IFF_POINTOPOINT
))
471 TAILQ_FOREACH(ifa
, &ifp
->if_addrhead
, ifa_link
)
472 if (ifa
->ifa_addr
->sa_family
==AF_NS
) {
473 idp
->idp_sna
= IA_SNS(ifa
)->sns_addr
;
476 idp
->idp_len
= ntohl(m0
->m_pkthdr
.len
);