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