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