]> git.saurik.com Git - apple/xnu.git/blob - bsd/netiso/clnp_input.c
7bf537d7b280ec8bc00e519bbfbf42eae96a6270
[apple/xnu.git] / bsd / netiso / clnp_input.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*-
23 * Copyright (c) 1991, 1993
24 * The Regents of the University of California. All rights reserved.
25 *
26 * Redistribution and use in source and binary forms, with or without
27 * modification, are permitted provided that the following conditions
28 * are met:
29 * 1. Redistributions of source code must retain the above copyright
30 * notice, this list of conditions and the following disclaimer.
31 * 2. Redistributions in binary form must reproduce the above copyright
32 * notice, this list of conditions and the following disclaimer in the
33 * documentation and/or other materials provided with the distribution.
34 * 3. All advertising materials mentioning features or use of this software
35 * must display the following acknowledgement:
36 * This product includes software developed by the University of
37 * California, Berkeley and its contributors.
38 * 4. Neither the name of the University nor the names of its contributors
39 * may be used to endorse or promote products derived from this software
40 * without specific prior written permission.
41 *
42 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
43 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
46 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
48 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
50 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
51 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52 * SUCH DAMAGE.
53 *
54 * @(#)clnp_input.c 8.1 (Berkeley) 6/10/93
55 */
56
57 /***********************************************************
58 Copyright IBM Corporation 1987
59
60 All Rights Reserved
61
62 Permission to use, copy, modify, and distribute this software and its
63 documentation for any purpose and without fee is hereby granted,
64 provided that the above copyright notice appear in all copies and that
65 both that copyright notice and this permission notice appear in
66 supporting documentation, and that the name of IBM not be
67 used in advertising or publicity pertaining to distribution of the
68 software without specific, written prior permission.
69
70 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
71 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
72 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
73 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
74 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
75 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
76 SOFTWARE.
77
78 ******************************************************************/
79
80 /*
81 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
82 */
83
84 #include <sys/param.h>
85 #include <sys/mbuf.h>
86 #include <sys/domain.h>
87 #include <sys/protosw.h>
88 #include <sys/socket.h>
89 #include <sys/socketvar.h>
90 #include <sys/errno.h>
91 #include <sys/time.h>
92
93 #include <net/if.h>
94 #include <net/if_types.h>
95 #include <net/route.h>
96
97 #include <netiso/iso.h>
98 #include <netiso/iso_var.h>
99 #include <netiso/iso_snpac.h>
100 #include <netiso/clnp.h>
101 #include <netiso/clnl.h>
102 #include <netiso/esis.h>
103 #include <netinet/in_systm.h>
104 #include <netinet/ip.h>
105 #include <netinet/if_ether.h>
106 #include <netiso/eonvar.h>
107 #include <netiso/clnp_stat.h>
108 #include <netiso/argo_debug.h>
109
110 #if ISO
111 u_char clnp_protox[ISOPROTO_MAX];
112 struct clnl_protosw clnl_protox[256];
113 int clnpqmaxlen = IFQ_MAXLEN; /* RAH? why is this a variable */
114 struct mbuf *clnp_data_ck();
115
116 int clnp_input();
117
118 int esis_input();
119
120 #ifdef ISO_X25ESIS
121 int x25esis_input();
122 #endif /* ISO_X25ESIS */
123
124 /*
125 * FUNCTION: clnp_init
126 *
127 * PURPOSE: clnp initialization. Fill in clnp switch tables.
128 *
129 * RETURNS: none
130 *
131 * SIDE EFFECTS: fills in clnp_protox table with correct offsets into
132 * the isosw table.
133 *
134 * NOTES:
135 */
136 clnp_init()
137 {
138 register struct protosw *pr;
139
140 /*
141 * CLNP protox initialization
142 */
143 if ((pr = pffindproto(PF_ISO, ISOPROTO_RAW, SOCK_RAW)) == 0)
144 printf("clnl_init: no raw CLNP\n");
145 else
146 clnp_protox[ISOPROTO_RAW] = pr - isosw;
147
148 if ((pr = pffindproto(PF_ISO, ISOPROTO_TP, SOCK_SEQPACKET)) == 0)
149 printf("clnl_init: no tp/clnp\n");
150 else
151 clnp_protox[ISOPROTO_TP] = pr - isosw;
152
153 /*
154 * CLNL protox initialization
155 */
156 clnl_protox[ISO8473_CLNP].clnl_input = clnp_input;
157
158 clnlintrq.ifq_maxlen = clnpqmaxlen;
159 }
160
161 /*
162 * FUNCTION: clnlintr
163 *
164 * PURPOSE: Process a packet on the clnl input queue
165 *
166 * RETURNS: nothing.
167 *
168 * SIDE EFFECTS:
169 *
170 * NOTES:
171 */
172 clnlintr()
173 {
174 register struct mbuf *m; /* ptr to first mbuf of pkt */
175 register struct clnl_fixed *clnl; /* ptr to fixed part of clnl hdr */
176 int s; /* save and restore priority */
177 struct clnl_protosw *clnlsw;/* ptr to protocol switch */
178 struct snpa_hdr sh; /* subnetwork hdr */
179
180 /*
181 * Get next datagram off clnl input queue
182 */
183 next:
184 s = splimp();
185 /* IF_DEQUEUESNPAHDR(&clnlintrq, m, sh);*/
186 IF_DEQUEUE(&clnlintrq, m);
187 splx(s);
188
189
190 if (m == 0) /* nothing to do */
191 return;
192 if ((m->m_flags & M_PKTHDR) == 0 || m->m_pkthdr.rcvif == 0) {
193 m_freem(m);
194 goto next;
195 } else {
196 register struct ifaddr *ifa;
197 for (ifa = m->m_pkthdr.rcvif->if_addrlist; ifa; ifa = ifa->ifa_next)
198 if (ifa->ifa_addr->sa_family == AF_ISO)
199 break;
200 if (ifa == 0) {
201 m_freem(m);
202 goto next;
203 }
204 }
205 bzero((caddr_t)&sh, sizeof(sh));
206 sh.snh_flags = m->m_flags & (M_MCAST|M_BCAST);
207 switch((sh.snh_ifp = m->m_pkthdr.rcvif)->if_type) {
208 extern int ether_output();
209 case IFT_EON:
210 bcopy(mtod(m, caddr_t), (caddr_t)sh.snh_dhost, sizeof(u_long));
211 bcopy(sizeof(u_long) + mtod(m, caddr_t),
212 (caddr_t)sh.snh_shost, sizeof(u_long));
213 sh.snh_dhost[4] = mtod(m, u_char *)[sizeof(struct ip) +
214 _offsetof(struct eon_hdr, eonh_class)];
215 m->m_data += EONIPLEN;
216 m->m_len -= EONIPLEN;
217 m->m_pkthdr.len -= EONIPLEN;
218 break;
219
220 default:
221 if (sh.snh_ifp->if_output == ether_output) {
222 bcopy((caddr_t)(mtod(m, struct ether_header *)->ether_dhost),
223 (caddr_t)sh.snh_dhost, 2*sizeof(sh.snh_dhost));
224 m->m_data += sizeof (struct ether_header);
225 m->m_len -= sizeof (struct ether_header);
226 m->m_pkthdr.len -= sizeof (struct ether_header);
227 }
228 }
229 IFDEBUG(D_INPUT)
230 int i;
231 printf("clnlintr: src:");
232 for (i=0; i<6; i++)
233 printf("%x%c", sh.snh_shost[i] & 0xff, (i<5) ? ':' : ' ');
234 printf(" dst:");
235 for (i=0; i<6; i++)
236 printf("%x%c", sh.snh_dhost[i] & 0xff, (i<5) ? ':' : ' ');
237 printf("\n");
238 ENDDEBUG
239
240 /*
241 * Get the fixed part of the clnl header into the first mbuf.
242 * Drop the packet if this fails.
243 * Do not call m_pullup if we have a cluster mbuf or the
244 * data is not there.
245 */
246 if ((IS_CLUSTER(m) || (m->m_len < sizeof(struct clnl_fixed))) &&
247 ((m = m_pullup(m, sizeof(struct clnl_fixed))) == 0)) {
248 INCSTAT(cns_toosmall); /* TODO: use clnl stats */
249 goto next; /* m_pullup discards mbuf */
250 }
251
252 clnl = mtod(m, struct clnl_fixed *);
253
254 /*
255 * Drop packet if the length of the header is not reasonable.
256 */
257 if ((clnl->cnf_hdr_len < CLNP_HDR_MIN) ||
258 (clnl->cnf_hdr_len > CLNP_HDR_MAX)) {
259 INCSTAT(cns_badhlen); /* TODO: use clnl stats */
260 m_freem(m);
261 goto next;
262 }
263
264 /*
265 * If the header is not contained in this mbuf, make it so.
266 * Drop packet if this fails.
267 * Note: m_pullup will allocate a cluster mbuf if necessary
268 */
269 if (clnl->cnf_hdr_len > m->m_len) {
270 if ((m = m_pullup(m, (int)clnl->cnf_hdr_len)) == 0) {
271 INCSTAT(cns_badhlen); /* TODO: use clnl stats */
272 goto next; /* m_pullup discards mbuf */
273 }
274 clnl = mtod(m, struct clnl_fixed *);
275 }
276
277 clnlsw = &clnl_protox[clnl->cnf_proto_id];
278
279
280 if (clnlsw->clnl_input)
281 (*clnlsw->clnl_input) (m, &sh);
282 else
283 m_freem(m);
284
285 goto next;
286 }
287
288 /*
289 * FUNCTION: clnp_input
290 *
291 * PURPOSE: process an incoming clnp packet
292 *
293 * RETURNS: nothing
294 *
295 * SIDE EFFECTS: increments fields of clnp_stat structure.
296 *
297 * NOTES:
298 * TODO: I would like to make seg_part a pointer into the mbuf, but
299 * will it be correctly aligned?
300 */
301 clnp_input(m, shp)
302 struct mbuf *m; /* ptr to first mbuf of pkt */
303 struct snpa_hdr *shp; /* subnetwork header */
304 {
305 register struct clnp_fixed *clnp; /* ptr to fixed part of header */
306 struct sockaddr_iso source; /* source address of pkt */
307 struct sockaddr_iso target; /* destination address of pkt */
308 #define src source.siso_addr
309 #define dst target.siso_addr
310 caddr_t hoff; /* current offset in packet */
311 caddr_t hend; /* address of end of header info */
312 struct clnp_segment seg_part; /* segment part of hdr */
313 int seg_off=0; /* offset of segment part of hdr */
314 int seg_len;/* length of packet data&hdr in bytes */
315 struct clnp_optidx oidx, *oidxp = NULL; /* option index */
316 extern int iso_systype; /* used by ESIS config resp */
317 extern struct sockaddr_iso blank_siso; /* used for initializing */
318 int need_afrin = 0;
319 /* true if congestion experienced */
320 /* which means you need afrin nose */
321 /* spray. How clever! */
322
323 IFDEBUG(D_INPUT)
324 printf(
325 "clnp_input: proccessing dg; First mbuf m_len %d, m_type x%x, %s\n",
326 m->m_len, m->m_type, IS_CLUSTER(m) ? "cluster" : "normal");
327 ENDDEBUG
328 need_afrin = 0;
329
330 /*
331 * If no iso addresses have been set, there is nothing
332 * to do with the packet.
333 */
334 if (iso_ifaddr == NULL) {
335 clnp_discard(m, ADDR_DESTUNREACH);
336 return;
337 }
338
339 INCSTAT(cns_total);
340 clnp = mtod(m, struct clnp_fixed *);
341
342 IFDEBUG(D_DUMPIN)
343 struct mbuf *mhead;
344 int total_len = 0;
345 printf("clnp_input: clnp header:\n");
346 dump_buf(mtod(m, caddr_t), clnp->cnf_hdr_len);
347 printf("clnp_input: mbuf chain:\n");
348 for (mhead = m; mhead != NULL; mhead=mhead->m_next) {
349 printf("m x%x, len %d\n", mhead, mhead->m_len);
350 total_len += mhead->m_len;
351 }
352 printf("clnp_input: total length of mbuf chain %d:\n", total_len);
353 ENDDEBUG
354
355 /*
356 * Compute checksum (if necessary) and drop packet if
357 * checksum does not match
358 */
359 if (CKSUM_REQUIRED(clnp) && iso_check_csum(m, (int)clnp->cnf_hdr_len)) {
360 INCSTAT(cns_badcsum);
361 clnp_discard(m, GEN_BADCSUM);
362 return;
363 }
364
365 if (clnp->cnf_vers != ISO8473_V1) {
366 INCSTAT(cns_badvers);
367 clnp_discard(m, DISC_UNSUPPVERS);
368 return;
369 }
370
371
372 /* check mbuf data length: clnp_data_ck will free mbuf upon error */
373 CTOH(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, seg_len);
374 if ((m = clnp_data_ck(m, seg_len)) == 0)
375 return;
376
377 clnp = mtod(m, struct clnp_fixed *);
378 hend = (caddr_t)clnp + clnp->cnf_hdr_len;
379
380 /*
381 * extract the source and destination address
382 * drop packet on failure
383 */
384 source = target = blank_siso;
385
386 hoff = (caddr_t)clnp + sizeof(struct clnp_fixed);
387 CLNP_EXTRACT_ADDR(dst, hoff, hend);
388 if (hoff == (caddr_t)0) {
389 INCSTAT(cns_badaddr);
390 clnp_discard(m, GEN_INCOMPLETE);
391 return;
392 }
393 CLNP_EXTRACT_ADDR(src, hoff, hend);
394 if (hoff == (caddr_t)0) {
395 INCSTAT(cns_badaddr);
396 clnp_discard(m, GEN_INCOMPLETE);
397 return;
398 }
399
400 IFDEBUG(D_INPUT)
401 printf("clnp_input: from %s", clnp_iso_addrp(&src));
402 printf(" to %s\n", clnp_iso_addrp(&dst));
403 ENDDEBUG
404
405 /*
406 * extract the segmentation information, if it is present.
407 * drop packet on failure
408 */
409 if (((clnp->cnf_type & CNF_TYPE) != CLNP_ER) &&
410 (clnp->cnf_type & CNF_SEG_OK)) {
411 if (hoff + sizeof(struct clnp_segment) > hend) {
412 INCSTAT(cns_noseg);
413 clnp_discard(m, GEN_INCOMPLETE);
414 return;
415 } else {
416 (void) bcopy(hoff, (caddr_t)&seg_part, sizeof(struct clnp_segment));
417 /* make sure segmentation fields are in host order */
418 seg_part.cng_id = ntohs(seg_part.cng_id);
419 seg_part.cng_off = ntohs(seg_part.cng_off);
420 seg_part.cng_tot_len = ntohs(seg_part.cng_tot_len);
421 seg_off = hoff - (caddr_t)clnp;
422 hoff += sizeof(struct clnp_segment);
423 }
424 }
425
426 /*
427 * process options if present. If clnp_opt_sanity returns
428 * false (indicating an error was found in the options) or
429 * an unsupported option was found
430 * then drop packet and emit an ER.
431 */
432 if (hoff < hend) {
433 int errcode;
434
435 oidxp = &oidx;
436 errcode = clnp_opt_sanity(m, hoff, hend-hoff, oidxp);
437
438 /* we do not support security */
439 if ((errcode == 0) && (oidxp->cni_securep))
440 errcode = DISC_UNSUPPSECURE;
441
442 /* the er option is valid with ER pdus only */
443 if ((errcode == 0) && (oidxp->cni_er_reason != ER_INVALREAS) &&
444 ((clnp->cnf_type & CNF_TYPE) != CLNP_ER))
445 errcode = DISC_UNSUPPOPT;
446
447 #ifdef DECBIT
448 /* check if the congestion experienced bit is set */
449 if (oidxp->cni_qos_formatp) {
450 caddr_t qosp = CLNP_OFFTOOPT(m, oidxp->cni_qos_formatp);
451 u_char qos = *qosp;
452
453 need_afrin = ((qos & (CLNPOVAL_GLOBAL|CLNPOVAL_CONGESTED)) ==
454 (CLNPOVAL_GLOBAL|CLNPOVAL_CONGESTED));
455 if (need_afrin)
456 INCSTAT(cns_congest_rcvd);
457 }
458 #endif /* DECBIT */
459
460 if (errcode != 0) {
461 clnp_discard(m, (char)errcode);
462 IFDEBUG(D_INPUT)
463 printf("clnp_input: dropped (err x%x) due to bad options\n",
464 errcode);
465 ENDDEBUG
466 return;
467 }
468 }
469
470 /*
471 * check if this packet is for us. if not, then forward
472 */
473 if (clnp_ours(&dst) == 0) {
474 IFDEBUG(D_INPUT)
475 printf("clnp_input: forwarding packet not for us\n");
476 ENDDEBUG
477 clnp_forward(m, seg_len, &dst, oidxp, seg_off, shp);
478 return;
479 }
480
481 /*
482 * ESIS Configuration Response Function
483 *
484 * If the packet received was sent to the multicast address
485 * all end systems, then send an esh to the source
486 */
487 if ((shp->snh_flags & M_MCAST) && (iso_systype == SNPA_ES)) {
488 extern short esis_holding_time;
489
490 esis_shoutput(shp->snh_ifp, ESIS_ESH, esis_holding_time,
491 shp->snh_shost, 6, &dst);
492 }
493
494 /*
495 * If this is a fragment, then try to reassemble it. If clnp_reass
496 * returns non NULL, the packet has been reassembled, and should
497 * be give to TP. Otherwise the fragment has been delt with
498 * by the reassembly code (either stored or deleted). In either case
499 * we should have nothing more to do with it.
500 */
501 if (((clnp->cnf_type & CNF_TYPE) != CLNP_ER) &&
502 (clnp->cnf_type & CNF_SEG_OK) &&
503 (seg_len != seg_part.cng_tot_len)) {
504 struct mbuf *m0;
505
506 if ((m0 = clnp_reass(m, &src, &dst, &seg_part)) != NULL) {
507 m = m0;
508 clnp = mtod(m, struct clnp_fixed *);
509 INCSTAT(cns_reassembled);
510 } else {
511 return;
512 }
513 }
514
515 /*
516 * give the packet to the higher layer
517 *
518 * Note: the total length of packet
519 * is the total length field of the segmentation part,
520 * or, if absent, the segment length field of the
521 * header.
522 */
523 INCSTAT(cns_delivered);
524 switch (clnp->cnf_type & CNF_TYPE) {
525 case CLNP_ER:
526 /*
527 * This ER must have the er option.
528 * If the option is not present, discard datagram.
529 */
530 if (oidxp == NULL || oidxp->cni_er_reason == ER_INVALREAS) {
531 clnp_discard(m, GEN_HDRSYNTAX);
532 } else {
533 clnp_er_input(m, &src, oidxp->cni_er_reason);
534 }
535 break;
536
537 case CLNP_DT:
538 (*isosw[clnp_protox[ISOPROTO_TP]].pr_input)(m, &source, &target,
539 clnp->cnf_hdr_len, need_afrin);
540 break;
541
542 case CLNP_RAW:
543 case CLNP_ECR:
544 IFDEBUG(D_INPUT)
545 printf("clnp_input: raw input of %d bytes\n",
546 clnp->cnf_type & CNF_SEG_OK ? seg_part.cng_tot_len : seg_len);
547 ENDDEBUG
548 (*isosw[clnp_protox[ISOPROTO_RAW]].pr_input)(m, &source, &target,
549 clnp->cnf_hdr_len);
550 break;
551
552 case CLNP_EC:
553 IFDEBUG(D_INPUT)
554 printf("clnp_input: echoing packet\n");
555 ENDDEBUG
556 (void)clnp_echoreply(m,
557 (clnp->cnf_type & CNF_SEG_OK ? (int)seg_part.cng_tot_len : seg_len),
558 &source, &target, oidxp);
559 break;
560
561 default:
562 printf("clnp_input: unknown clnp pkt type %d\n",
563 clnp->cnf_type & CNF_TYPE);
564 clnp_stat.cns_delivered--;
565 clnp_stat.cns_noproto++;
566 clnp_discard(m, GEN_HDRSYNTAX);
567 break;
568 }
569 }
570 #endif /* ISO */