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 */ 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 */ 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