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