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.23 2008/09/24 14:26:39 sephe 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
, pktinfo_portfn_cpu0
,
100 nsintr
, NETISR_FLAG_NOTMPSAFE
);
104 * Idp input routine. Pass to next level.
106 int nsintr_getpck
= 0;
107 int nsintr_swtch
= 0;
110 nsintr(struct netmsg
*msg
)
112 struct mbuf
*m
= ((struct netmsg_packet
*)msg
)->nm_packet
;
120 * Get IDP header in first mbuf.
123 if ((m
->m_flags
& M_EXT
|| m
->m_len
< sizeof (struct idp
)) &&
124 (m
= m_pullup(m
, sizeof (struct idp
))) == 0) {
125 idpstat
.idps_toosmall
++;
130 * Give any raw listeners a crack at the packet
132 for (nsp
= nsrawpcb
.nsp_next
; nsp
!= &nsrawpcb
; nsp
= nsp
->nsp_next
) {
133 struct mbuf
*m1
= m_copy(m
, 0, (int)M_COPYALL
);
134 if (m1
) idp_input(m1
, nsp
);
137 idp
= mtod(m
, struct idp
*);
138 len
= ntohs(idp
->idp_len
);
139 if ((oddpacketp
= (len
& 1))) {
140 len
++; /* If this packet is of odd length,
141 preserve garbage byte for checksum */
145 * Check that the amount of data in the buffers
146 * is as at least much as the IDP header would have us expect.
147 * Trim mbufs if longer than we expect.
148 * Drop packet if shorter than we expect.
150 if (m
->m_pkthdr
.len
< len
) {
151 idpstat
.idps_tooshort
++;
154 if (m
->m_pkthdr
.len
> len
) {
155 if (m
->m_len
== m
->m_pkthdr
.len
) {
157 m
->m_pkthdr
.len
= len
;
159 m_adj(m
, len
- m
->m_pkthdr
.len
);
161 if (idpcksum
&& ((i
= idp
->idp_sum
)!=0xffff)) {
163 if (i
!= (idp
->idp_sum
= ns_cksum(m
, len
))) {
164 idpstat
.idps_badsum
++;
166 if (ns_hosteqnh(ns_thishost
, idp
->idp_dna
.x_host
))
167 error
= NS_ERR_BADSUM
;
169 error
= NS_ERR_BADSUM_T
;
170 ns_error(m
, error
, 0);
175 * Is this a directed broadcast?
177 if (ns_hosteqnh(ns_broadhost
,idp
->idp_dna
.x_host
)) {
178 if ((!ns_neteq(idp
->idp_dna
, idp
->idp_sna
)) &&
179 (!ns_neteqnn(idp
->idp_dna
.x_net
, ns_broadnet
)) &&
180 (!ns_neteqnn(idp
->idp_sna
.x_net
, ns_zeronet
)) &&
181 (!ns_neteqnn(idp
->idp_dna
.x_net
, ns_zeronet
)) ) {
183 * Look to see if I need to eat this packet.
184 * Algorithm is to forward all young packets
185 * and prematurely age any packets which will
186 * by physically broadcasted.
187 * Any very old packets eaten without forwarding
190 * Suggestion of Bill Nesheim, Cornell U.
192 if (idp
->idp_tc
< NS_MAXHOPS
) {
198 * Is this our packet? If not, forward.
200 } else if (!ns_hosteqnh(ns_thishost
,idp
->idp_dna
.x_host
)) {
205 * Locate pcb for datagram.
207 nsp
= ns_pcblookup(&idp
->idp_sna
, idp
->idp_dna
.x_port
, NS_WILDCARD
);
209 * Switch out to protocol's input routine.
216 if ((nsp
->nsp_flags
& NSP_ALL_PACKETS
)==0)
217 switch (idp
->idp_pt
) {
229 ns_error(m
, NS_ERR_NOSOCK
, 0);
237 /* msg was embedded in the mbuf, do not reply! */
240 u_char nsctlerrmap
[PRC_NCMDS
] = {
241 ECONNABORTED
, ECONNABORTED
, 0, 0,
242 0, 0, EHOSTDOWN
, EHOSTUNREACH
,
243 ENETUNREACH
, EHOSTUNREACH
, ECONNREFUSED
, ECONNREFUSED
,
248 int idp_donosocks
= 1;
251 idp_ctlinput(int cmd
, caddr_t arg
)
255 struct ns_errp
*errp
= (struct ns_errp
*)arg
; /* XXX */
258 if (cmd
< 0 || cmd
> PRC_NCMDS
)
260 if (nsctlerrmap
[cmd
] == 0)
262 type
= NS_ERR_UNREACH_HOST
;
264 struct sockaddr_ns
*sns
;
268 case PRC_HOSTUNREACH
:
269 sns
= (struct sockaddr_ns
*)arg
;
270 if (sns
->sns_family
!= AF_NS
)
276 errp
= (struct ns_errp
*)arg
;
277 ns
= &errp
->ns_err_idp
.idp_dna
;
278 type
= errp
->ns_err_num
;
279 type
= ntohs((u_short
)type
);
283 case NS_ERR_UNREACH_HOST
:
284 ns_pcbnotify(ns
, (int)nsctlerrmap
[cmd
], idp_abort
, (long)0);
288 nsp
= ns_pcblookup(ns
, errp
->ns_err_idp
.idp_sna
.x_port
,
290 if(nsp
&& idp_donosocks
&& ! ns_nullhost(nsp
->nsp_faddr
))
291 idp_drop(nsp
, (int)nsctlerrmap
[cmd
]);
296 int idpforwarding
= 1;
298 * Forward a packet. If some error occurs return the sender
299 * an error packet. Note we can't always generate a meaningful
300 * error message because the NS errors don't have a large enough repetoire
301 * of codes and types.
303 struct route idp_droute
;
304 struct route idp_sroute
;
307 idp_forward(struct mbuf
*m
)
309 struct idp
*idp
= mtod(m
, struct idp
*);
310 int error
, type
, code
;
311 struct mbuf
*mcopy
= NULL
;
313 int flags
= NS_FORWARDING
;
318 kprintf("forward: src ");
319 ns_printhost(&idp
->idp_sna
);
321 ns_printhost(&idp
->idp_dna
);
322 kprintf("hop count %d\n", idp
->idp_tc
);
324 if (idpforwarding
== 0) {
325 /* can't tell difference between net and host */
326 type
= NS_ERR_UNREACH_HOST
, code
= 0;
330 if (idp
->idp_tc
> NS_MAXHOPS
) {
331 type
= NS_ERR_TOO_OLD
, code
= 0;
335 * Save at most 42 bytes of the packet in case
336 * we need to generate an NS error message to the src.
338 mcopy
= m_copy(m
, 0, imin((int)ntohs(idp
->idp_len
), 42));
340 if ((ok_there
= idp_do_route(&idp
->idp_dna
,&idp_droute
))==0) {
341 type
= NS_ERR_UNREACH_HOST
, code
= 0;
345 * Here we think about forwarding broadcast packets,
346 * so we try to insure that it doesn't go back out
347 * on the interface it came in on. Also, if we
348 * are going to physically broadcast this, let us
349 * age the packet so we can eat it safely the second time around.
351 if (idp
->idp_dna
.x_host
.c_host
[0] & 0x1) {
352 struct ns_ifaddr
*ia
= ns_iaonnetof(&idp
->idp_dna
);
355 /* I'm gonna hafta eat this packet */
356 agedelta
+= NS_MAXHOPS
- idp
->idp_tc
;
357 idp
->idp_tc
= NS_MAXHOPS
;
359 if ((ok_back
= idp_do_route(&idp
->idp_sna
,&idp_sroute
))==0) {
360 /* error = ENETUNREACH; He'll never get it! */
364 if (idp_droute
.ro_rt
&&
365 (ifp
=idp_droute
.ro_rt
->rt_ifp
) &&
367 (ifp
!=idp_sroute
.ro_rt
->rt_ifp
)) {
368 flags
|= NS_ALLOWBROADCAST
;
370 type
= NS_ERR_UNREACH_HOST
, code
= 0;
374 /* need to adjust checksum */
375 if (idp
->idp_sum
!=0xffff) {
382 x
.l
= 0; x
.c
[0] = agedelta
;
383 shift
= (((((int)ntohs(idp
->idp_len
))+1)>>1)-2) & 0xf;
384 x
.l
= idp
->idp_sum
+ (x
.s
[0] << shift
);
385 x
.l
= x
.s
[0] + x
.s
[1];
386 x
.l
= x
.s
[0] + x
.s
[1];
387 if (x
.l
==0xffff) idp
->idp_sum
= 0; else idp
->idp_sum
= x
.l
;
389 if ((error
= ns_output(m
, &idp_droute
, flags
)) &&
391 idp
= mtod(mcopy
, struct idp
*);
392 type
= NS_ERR_UNSPEC_T
, code
= 0;
400 type
= NS_ERR_UNREACH_HOST
;
404 type
= NS_ERR_TOO_BIG
;
405 code
= 576; /* too hard to figure out mtu here */
409 type
= NS_ERR_UNSPEC_T
;
414 ns_error(m
, type
, code
);
418 idp_undo_route(&idp_droute
);
420 idp_undo_route(&idp_sroute
);
426 idp_do_route(struct ns_addr
*src
, struct route
*ro
)
429 struct sockaddr_ns
*dst
;
431 bzero((caddr_t
)ro
, sizeof (*ro
));
432 dst
= (struct sockaddr_ns
*)&ro
->ro_dst
;
434 dst
->sns_len
= sizeof(*dst
);
435 dst
->sns_family
= AF_NS
;
436 dst
->sns_addr
= *src
;
437 dst
->sns_addr
.x_port
= 0;
439 if (ro
->ro_rt
== 0 || ro
->ro_rt
->rt_ifp
== 0) {
447 idp_undo_route(struct route
*ro
)
449 if (ro
->ro_rt
) {RTFREE(ro
->ro_rt
);}
453 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 struct ifaddr_container
*ifac
;
474 &ifp
->if_addrheads
[mycpuid
], ifa_link
) {
475 struct ifaddr
*ifa
= ifac
->ifa
;
477 if (ifa
->ifa_addr
->sa_family
==AF_NS
) {
478 idp
->idp_sna
= IA_SNS(ifa
)->sns_addr
;
483 idp
->idp_len
= ntohl(m0
->m_pkthdr
.len
);