1 /* $NetBSD: clnp_input.c,v 1.36 2007/12/04 10:31:14 dyoung Exp $ */
4 * Copyright (c) 1991, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * @(#)clnp_input.c 8.1 (Berkeley) 6/10/93
34 /***********************************************************
35 Copyright IBM Corporation 1987
39 Permission to use, copy, modify, and distribute this software and its
40 documentation for any purpose and without fee is hereby granted,
41 provided that the above copyright notice appear in all copies and that
42 both that copyright notice and this permission notice appear in
43 supporting documentation, and that the name of IBM not be
44 used in advertising or publicity pertaining to distribution of the
45 software without specific, written prior permission.
47 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
48 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
49 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
50 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
51 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
52 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
55 ******************************************************************/
58 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
61 #include <sys/cdefs.h>
62 __KERNEL_RCSID(0, "$NetBSD: clnp_input.c,v 1.36 2007/12/04 10:31:14 dyoung Exp $");
66 #include <sys/param.h>
68 #include <sys/domain.h>
69 #include <sys/protosw.h>
70 #include <sys/socket.h>
71 #include <sys/socketvar.h>
72 #include <sys/errno.h>
74 #include <sys/systm.h>
77 #include <net/if_types.h>
78 #include <net/route.h>
80 #include <net/if_ether.h>
81 #include <net/if_fddi.h>
83 #include <net/if_llc.h>
85 #include <netiso/iso.h>
86 #include <netiso/iso_var.h>
87 #include <netiso/iso_snpac.h>
88 #include <netiso/clnp.h>
89 #include <netiso/clnl.h>
90 #include <netiso/esis.h>
91 #include <netinet/in_systm.h>
92 #include <netinet/ip.h>
93 #include <netiso/eonvar.h>
94 #include <netiso/clnp_stat.h>
95 #include <netiso/argo_debug.h>
97 #include <machine/stdarg.h>
100 u_char clnp_protox
[ISOPROTO_MAX
];
101 struct clnl_protosw clnl_protox
[256];
102 int clnpqmaxlen
= IFQ_MAXLEN
; /* RAH? why is this a
106 void x25esis_input();
108 #endif /* ISO_X25ESIS */
109 struct iso_ifaddrhead iso_ifaddr
= TAILQ_HEAD_INITIALIZER(iso_ifaddr
);
110 struct ifqueue clnlintrq
;
111 struct clnp_stat clnp_stat
;
114 * FUNCTION: clnp_init
116 * PURPOSE: clnp initialization. Fill in clnp switch tables.
120 * SIDE EFFECTS: fills in clnp_protox table with correct offsets into
128 const struct protosw
*pr
;
131 * CLNP protox initialization
133 if ((pr
= pffindproto(PF_ISO
, ISOPROTO_RAW
, SOCK_RAW
)) == 0)
134 printf("clnl_init: no raw CLNP\n");
136 clnp_protox
[ISOPROTO_RAW
] = pr
- isosw
;
138 if ((pr
= pffindproto(PF_ISO
, ISOPROTO_TP
, SOCK_SEQPACKET
)) == 0)
139 printf("clnl_init: no tp/clnp\n");
141 clnp_protox
[ISOPROTO_TP
] = pr
- isosw
;
144 * CLNL protox initialization
146 clnl_protox
[ISO8473_CLNP
].clnl_input
= clnp_input
;
148 clnlintrq
.ifq_maxlen
= clnpqmaxlen
;
154 * PURPOSE: Process a packet on the clnl input queue
165 struct mbuf
*m
;/* ptr to first mbuf of pkt */
166 struct clnl_fixed
*clnl
; /* ptr to fixed part of clnl
168 int s
; /* save and restore priority */
169 struct clnl_protosw
*clnlsw
; /* ptr to protocol switch */
170 struct snpa_hdr sh
; /* subnetwork hdr */
173 * Get next datagram off clnl input queue
177 /* IF_DEQUEUESNPAHDR(&clnlintrq, m, sh); */
178 IF_DEQUEUE(&clnlintrq
, m
);
182 if (m
== 0) /* nothing to do */
184 if ((m
->m_flags
& M_PKTHDR
) == 0 || m
->m_pkthdr
.rcvif
== 0) {
188 memset(&sh
, 0, sizeof(sh
));
189 sh
.snh_flags
= m
->m_flags
& (M_MCAST
| M_BCAST
);
190 switch ((sh
.snh_ifp
= m
->m_pkthdr
.rcvif
)->if_type
) {
192 (void)memcpy(sh
.snh_dhost
, mtod(m
, char *), sizeof(u_long
));
193 (void)memcpy(sh
.snh_shost
, sizeof(u_long
) + mtod(m
, char *),
195 sh
.snh_dhost
[4] = mtod(m
, u_char
*)[sizeof(struct ip
) +
196 offsetof(struct eon_hdr
, eonh_class
)];
200 (void)memcpy(sh
.snh_dhost
,
201 mtod(m
, struct ether_header
*)->ether_dhost
,
202 2 * sizeof(sh
.snh_dhost
));
203 m_adj(m
, sizeof(struct ether_header
) + LLC_UFRAMELEN
);
206 (void)memcpy(sh
.snh_dhost
,
207 mtod(m
, struct fddi_header
*)->fddi_dhost
,
208 2 * sizeof(sh
.snh_dhost
));
209 m_adj(m
, sizeof(struct fddi_header
) + LLC_UFRAMELEN
);
213 /* nothing extra to get from the mbuf */
214 memset(sh
.snh_dhost
, 0, sizeof(sh
.snh_dhost
));
215 memset(sh
.snh_shost
, 0, sizeof(sh
.snh_shost
));
221 if (argo_debug
[D_INPUT
]) {
223 printf("clnlintr: src:");
224 for (i
= 0; i
< 6; i
++)
225 printf("%x%c", sh
.snh_shost
[i
] & 0xff,
226 (i
< 5) ? ':' : ' ');
228 for (i
= 0; i
< 6; i
++)
229 printf("%x%c", sh
.snh_dhost
[i
] & 0xff,
230 (i
< 5) ? ':' : ' ');
236 * Get the fixed part of the clnl header into the first mbuf.
237 * Drop the packet if this fails.
238 * Do not call m_pullup if we have a cluster mbuf or the
241 if ((IS_CLUSTER(m
) || (m
->m_len
< sizeof(struct clnl_fixed
))) &&
242 ((m
= m_pullup(m
, sizeof(struct clnl_fixed
))) == 0)) {
243 INCSTAT(cns_toosmall
); /* TODO: use clnl stats */
244 goto next
; /* m_pullup discards mbuf */
246 clnl
= mtod(m
, struct clnl_fixed
*);
249 * Drop packet if the length of the header is not reasonable.
251 if ((clnl
->cnf_hdr_len
< CLNP_HDR_MIN
) ||
252 (clnl
->cnf_hdr_len
> CLNP_HDR_MAX
)) {
253 INCSTAT(cns_badhlen
); /* TODO: use clnl stats */
258 * If the header is not contained in this mbuf, make it so.
259 * Drop packet if this fails.
260 * Note: m_pullup will allocate a cluster mbuf if necessary
262 if (clnl
->cnf_hdr_len
> m
->m_len
) {
263 if ((m
= m_pullup(m
, (int) clnl
->cnf_hdr_len
)) == 0) {
264 INCSTAT(cns_badhlen
); /* TODO: use clnl stats */
265 goto next
; /* m_pullup discards mbuf */
267 clnl
= mtod(m
, struct clnl_fixed
*);
269 clnlsw
= &clnl_protox
[clnl
->cnf_proto_id
];
272 if (clnlsw
->clnl_input
)
273 (*clnlsw
->clnl_input
) (m
, &sh
);
281 * FUNCTION: clnp_input
283 * PURPOSE: process an incoming clnp packet
287 * SIDE EFFECTS: increments fields of clnp_stat structure.
290 * TODO: I would like to make seg_part a pointer into the mbuf, but
291 * will it be correctly aligned?
294 clnp_input(struct mbuf
*m
, ...)
296 struct snpa_hdr
*shp
; /* subnetwork header */
298 struct clnp_fixed
*clnp
; /* ptr to fixed part of
300 struct sockaddr_iso source
; /* source address of pkt */
301 struct sockaddr_iso target
; /* destination address of pkt */
302 #define src source.siso_addr
303 #define dst target.siso_addr
304 char *hoff
; /* current offset in packet */
305 char *hend
; /* address of end of header info */
306 struct clnp_segment seg_part
; /* segment part of hdr */
307 int seg_off
= 0; /* offset of segment part of hdr */
308 int seg_len
;/* length of packet data&hdr in bytes */
309 struct clnp_optidx oidx
, *oidxp
= NULL
; /* option index */
310 extern int iso_systype
; /* used by ESIS config resp */
311 extern struct sockaddr_iso blank_siso
; /* used for initializing */
313 /* true if congestion experienced */
314 /* which means you need afrin nose */
315 /* spray. How clever! */
319 shp
= va_arg(ap
, struct snpa_hdr
*);
323 * make sure this interface has a ISO address
325 IFADDR_FOREACH(ifa
, shp
->snh_ifp
)
326 if (ifa
->ifa_addr
->sa_family
== AF_ISO
)
329 clnp_discard(m
, ADDR_DESTUNREACH
);
334 if (argo_debug
[D_INPUT
]) {
336 "clnp_input: processing dg; First mbuf m_len %d, m_type x%x, %s\n",
337 m
->m_len
, m
->m_type
, IS_CLUSTER(m
) ? "cluster" : "normal");
343 * If no iso addresses have been set, there is nothing
344 * to do with the packet.
346 if (iso_ifaddr
.tqh_first
== 0) {
347 clnp_discard(m
, ADDR_DESTUNREACH
);
351 clnp
= mtod(m
, struct clnp_fixed
*);
354 if (argo_debug
[D_DUMPIN
]) {
357 printf("clnp_input: clnp header:\n");
358 dump_buf(mtod(m
, void *), clnp
->cnf_hdr_len
);
359 printf("clnp_input: mbuf chain:\n");
360 for (mhead
= m
; mhead
!= NULL
; mhead
= mhead
->m_next
) {
361 printf("m %p, len %d\n", mhead
, mhead
->m_len
);
362 total_len
+= mhead
->m_len
;
364 printf("clnp_input: total length of mbuf chain %d:\n",
370 * Compute checksum (if necessary) and drop packet if
371 * checksum does not match
373 if (CKSUM_REQUIRED(clnp
) &&
374 iso_check_csum(m
, (int) clnp
->cnf_hdr_len
)) {
375 INCSTAT(cns_badcsum
);
376 clnp_discard(m
, GEN_BADCSUM
);
379 if (clnp
->cnf_vers
!= ISO8473_V1
) {
380 INCSTAT(cns_badvers
);
381 clnp_discard(m
, DISC_UNSUPPVERS
);
384 /* check mbuf data length: clnp_data_ck will free mbuf upon error */
385 CTOH(clnp
->cnf_seglen_msb
, clnp
->cnf_seglen_lsb
, seg_len
);
386 if ((m
= clnp_data_ck(m
, seg_len
)) == 0)
389 clnp
= mtod(m
, struct clnp_fixed
*);
390 hend
= (char *) clnp
+ clnp
->cnf_hdr_len
;
393 * extract the source and destination address drop packet on failure
395 source
= target
= blank_siso
;
397 hoff
= (char *)clnp
+ sizeof(struct clnp_fixed
);
398 CLNP_EXTRACT_ADDR(dst
, hoff
, hend
);
400 INCSTAT(cns_badaddr
);
401 clnp_discard(m
, GEN_INCOMPLETE
);
404 CLNP_EXTRACT_ADDR(src
, hoff
, hend
);
406 INCSTAT(cns_badaddr
);
407 clnp_discard(m
, GEN_INCOMPLETE
);
411 if (argo_debug
[D_INPUT
]) {
412 printf("clnp_input: from %s", clnp_iso_addrp(&src
));
413 printf(" to %s\n", clnp_iso_addrp(&dst
));
418 * extract the segmentation information, if it is present.
419 * drop packet on failure
421 if (((clnp
->cnf_type
& CNF_TYPE
) != CLNP_ER
) &&
422 (clnp
->cnf_type
& CNF_SEG_OK
)) {
423 if (hoff
+ sizeof(struct clnp_segment
) > hend
) {
425 clnp_discard(m
, GEN_INCOMPLETE
);
428 (void)memcpy(&seg_part
, hoff
,
429 sizeof(struct clnp_segment
));
430 /* make sure segmentation fields are in host order */
431 seg_part
.cng_id
= ntohs(seg_part
.cng_id
);
432 seg_part
.cng_off
= ntohs(seg_part
.cng_off
);
433 seg_part
.cng_tot_len
= ntohs(seg_part
.cng_tot_len
);
434 seg_off
= hoff
- (char *)clnp
;
435 hoff
+= sizeof(struct clnp_segment
);
439 * process options if present. If clnp_opt_sanity returns
440 * false (indicating an error was found in the options) or
441 * an unsupported option was found
442 * then drop packet and emit an ER.
448 errcode
= clnp_opt_sanity(m
, hoff
, hend
- hoff
, oidxp
);
450 /* we do not support security */
451 if ((errcode
== 0) && (oidxp
->cni_securep
))
452 errcode
= DISC_UNSUPPSECURE
;
454 /* the er option is valid with ER pdus only */
455 if ((errcode
== 0) && (oidxp
->cni_er_reason
!= ER_INVALREAS
) &&
456 ((clnp
->cnf_type
& CNF_TYPE
) != CLNP_ER
))
457 errcode
= DISC_UNSUPPOPT
;
460 /* check if the congestion experienced bit is set */
461 if (oidxp
->cni_qos_formatp
) {
462 char * qosp
= CLNP_OFFTOOPT(m
, oidxp
->cni_qos_formatp
);
465 need_afrin
= ((qos
& (CLNPOVAL_GLOBAL
| CLNPOVAL_CONGESTED
)) ==
466 (CLNPOVAL_GLOBAL
| CLNPOVAL_CONGESTED
));
468 INCSTAT(cns_congest_rcvd
);
473 clnp_discard(m
, (char) errcode
);
475 if (argo_debug
[D_INPUT
]) {
477 "clnp_input: dropped (err x%x) due to bad options\n",
485 * check if this packet is for us. if not, then forward
487 if (clnp_ours(&dst
) == 0) {
489 if (argo_debug
[D_INPUT
]) {
490 printf("clnp_input: forwarding packet not for us\n");
493 clnp_forward(m
, seg_len
, &dst
, oidxp
, seg_off
, shp
);
497 * ESIS Configuration Response Function
499 * If the packet received was sent to the multicast address
500 * all end systems, then send an esh to the source
502 if ((shp
->snh_flags
& M_MCAST
) && (iso_systype
== SNPA_ES
)) {
503 extern short esis_holding_time
;
505 esis_shoutput(shp
->snh_ifp
, ESIS_ESH
, esis_holding_time
,
506 shp
->snh_shost
, 6, &dst
);
509 * If this is a fragment, then try to reassemble it. If clnp_reass
510 * returns non NULL, the packet has been reassembled, and should
511 * be give to TP. Otherwise the fragment has been delt with
512 * by the reassembly code (either stored or deleted). In either case
513 * we should have nothing more to do with it.
515 if (((clnp
->cnf_type
& CNF_TYPE
) != CLNP_ER
) &&
516 (clnp
->cnf_type
& CNF_SEG_OK
) &&
517 (seg_len
!= seg_part
.cng_tot_len
)) {
520 if ((m0
= clnp_reass(m
, &src
, &dst
, &seg_part
)) != NULL
) {
522 clnp
= mtod(m
, struct clnp_fixed
*);
523 INCSTAT(cns_reassembled
);
529 * give the packet to the higher layer
531 * Note: the total length of packet
532 * is the total length field of the segmentation part,
533 * or, if absent, the segment length field of the
536 INCSTAT(cns_delivered
);
537 switch (clnp
->cnf_type
& CNF_TYPE
) {
540 * This ER must have the er option.
541 * If the option is not present, discard datagram.
543 if (oidxp
== NULL
|| oidxp
->cni_er_reason
== ER_INVALREAS
) {
544 clnp_discard(m
, GEN_HDRSYNTAX
);
546 clnp_er_input(m
, &src
, oidxp
->cni_er_reason
);
550 (*isosw
[clnp_protox
[ISOPROTO_TP
]].pr_input
)(m
, &source
, &target
,
551 clnp
->cnf_hdr_len
, need_afrin
);
556 if (argo_debug
[D_INPUT
]) {
557 printf("clnp_input: raw input of %d bytes\n",
558 clnp
->cnf_type
& CNF_SEG_OK
?
559 seg_part
.cng_tot_len
: seg_len
);
562 (*isosw
[clnp_protox
[ISOPROTO_RAW
]].pr_input
)(m
, &source
,
569 if (argo_debug
[D_INPUT
]) {
570 printf("clnp_input: echoing packet\n");
573 (void) clnp_echoreply(m
, (clnp
->cnf_type
& CNF_SEG_OK
?
574 (int) seg_part
.cng_tot_len
: seg_len
),
575 &source
, &target
, oidxp
);
579 printf("clnp_input: unknown clnp pkt type %d\n",
580 clnp
->cnf_type
& CNF_TYPE
);
581 clnp_stat
.cns_delivered
--;
582 clnp_stat
.cns_noproto
++;
583 clnp_discard(m
, GEN_HDRSYNTAX
);