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.6 (Berkeley) 08/29/89 */ 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/iftypes.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) { 145 m_freem(m); 146 goto next; 147 } 148 bzero((caddr_t)&sh, sizeof(sh)); 149 sh.snh_flags = m->m_flags & (M_MCAST|M_BCAST); 150 switch((sh.snh_ifp = m->m_pkthdr.rcvif)->if_type) { 151 extern int ether_output(); 152 case IFT_EON: 153 bcopy(mtod(m, caddr_t), (caddr_t)sh.snh_dhost, sizeof(u_long)); 154 bcopy(sizeof(u_long) + mtod(m, caddr_t), 155 (caddr_t)sh.snh_shost, sizeof(u_long)); 156 sh.snh_dhost[4] = mtod(m, u_char *)[sizeof(struct ip) + 157 _offsetof(struct eon_hdr, eonh_class)]; 158 m->m_data += EONIPLEN; 159 m->m_len -= EONIPLEN; 160 m->m_pkthdr.len -= EONIPLEN; 161 break; 162 163 default: 164 if (sh.snh_ifp->if_output == ether_output) { 165 bcopy((caddr_t)(mtod(m, struct ether_header *)->ether_dhost), 166 (caddr_t)sh.snh_dhost, 2*sizeof(sh.snh_dhost)); 167 m->m_data += sizeof (struct ether_header); 168 m->m_len -= sizeof (struct ether_header); 169 m->m_pkthdr.len -= sizeof (struct ether_header); 170 } 171 } 172 IFDEBUG(D_INPUT) 173 int i; 174 printf("clnlintr: src:"); 175 for (i=0; i<6; i++) 176 printf("%x%c", sh.snh_shost[i] & 0xff, (i<5) ? ':' : ' '); 177 printf(" dst:"); 178 for (i=0; i<6; i++) 179 printf("%x%c", sh.snh_dhost[i] & 0xff, (i<5) ? ':' : ' '); 180 printf("\n"); 181 ENDDEBUG 182 183 /* 184 * Get the fixed part of the clnl header into the first mbuf. 185 * Drop the packet if this fails. 186 * Do not call m_pullup if we have a cluster mbuf or the 187 * data is not there. 188 */ 189 if ((IS_CLUSTER(m) || (m->m_len < sizeof(struct clnl_fixed))) && 190 ((m = m_pullup(m, sizeof(struct clnl_fixed))) == 0)) { 191 INCSTAT(cns_toosmall); /* TODO: use clnl stats */ 192 goto next; /* m_pullup discards mbuf */ 193 } 194 195 clnl = mtod(m, struct clnl_fixed *); 196 197 /* 198 * Drop packet if the length of the header is not reasonable. 199 */ 200 if ((clnl->cnf_hdr_len < CLNP_HDR_MIN) || 201 (clnl->cnf_hdr_len > CLNP_HDR_MAX)) { 202 INCSTAT(cns_badhlen); /* TODO: use clnl stats */ 203 m_freem(m); 204 goto next; 205 } 206 207 /* 208 * If the header is not contained in this mbuf, make it so. 209 * Drop packet if this fails. 210 * Note: m_pullup will allocate a cluster mbuf if necessary 211 */ 212 if (clnl->cnf_hdr_len > m->m_len) { 213 if ((m = m_pullup(m, (int)clnl->cnf_hdr_len)) == 0) { 214 INCSTAT(cns_badhlen); /* TODO: use clnl stats */ 215 goto next; /* m_pullup discards mbuf */ 216 } 217 clnl = mtod(m, struct clnl_fixed *); 218 } 219 220 clnlsw = &clnl_protox[clnl->cnf_proto_id]; 221 222 223 if (clnlsw->clnl_input) 224 (*clnlsw->clnl_input) (m, &sh); 225 else 226 m_freem(m); 227 228 goto next; 229 } 230 231 /* 232 * FUNCTION: clnp_input 233 * 234 * PURPOSE: process an incoming clnp packet 235 * 236 * RETURNS: nothing 237 * 238 * SIDE EFFECTS: increments fields of clnp_stat structure. 239 * 240 * NOTES: 241 * TODO: I would like to make seg_part a pointer into the mbuf, but 242 * will it be correctly aligned? 243 */ 244 clnp_input(m, shp) 245 struct mbuf *m; /* ptr to first mbuf of pkt */ 246 struct snpa_hdr *shp; /* subnetwork header */ 247 { 248 register struct clnp_fixed *clnp; /* ptr to fixed part of header */ 249 struct iso_addr src; /* source address of pkt */ 250 struct iso_addr dst; /* destination address of pkt */ 251 caddr_t hoff; /* current offset in packet */ 252 caddr_t hend; /* address of end of header info */ 253 struct clnp_segment seg_part; /* segment part of hdr */ 254 int seg_off=0; /* offset of segment part of hdr */ 255 int seg_len;/* length of packet data&hdr in bytes */ 256 struct clnp_optidx oidx, *oidxp = NULL; /* option index */ 257 extern int iso_systype; /* used by ESIS config resp */ 258 int need_afrin = 0; 259 /* true if congestion experienced */ 260 /* which means you need afrin nose */ 261 /* spray. How clever! */ 262 263 IFDEBUG(D_INPUT) 264 printf( 265 "clnp_input: proccessing dg; First mbuf m_len %d, m_type x%x, %s\n", 266 m->m_len, m->m_type, IS_CLUSTER(m) ? "cluster" : "normal"); 267 ENDDEBUG 268 need_afrin = 0; 269 270 /* 271 * If no iso addresses have been set, there is nothing 272 * to do with the packet. 273 */ 274 if (iso_ifaddr == NULL) { 275 clnp_discard(m, ADDR_DESTUNREACH); 276 return; 277 } 278 279 INCSTAT(cns_total); 280 clnp = mtod(m, struct clnp_fixed *); 281 282 IFDEBUG(D_DUMPIN) 283 struct mbuf *mhead; 284 int total_len = 0; 285 printf("clnp_input: clnp header:\n"); 286 dump_buf(mtod(m, caddr_t), clnp->cnf_hdr_len); 287 printf("clnp_input: mbuf chain:\n"); 288 for (mhead = m; mhead != NULL; mhead=mhead->m_next) { 289 printf("m x%x, len %d\n", mhead, mhead->m_len); 290 total_len += mhead->m_len; 291 } 292 printf("clnp_input: total length of mbuf chain %d:\n", total_len); 293 ENDDEBUG 294 295 /* 296 * Compute checksum (if necessary) and drop packet if 297 * checksum does not match 298 */ 299 if (CKSUM_REQUIRED(clnp) && iso_check_csum(m, (int)clnp->cnf_hdr_len)) { 300 INCSTAT(cns_badcsum); 301 clnp_discard(m, GEN_BADCSUM); 302 return; 303 } 304 305 if (clnp->cnf_vers != ISO8473_V1) { 306 INCSTAT(cns_badvers); 307 clnp_discard(m, DISC_UNSUPPVERS); 308 return; 309 } 310 311 312 /* check mbuf data length: clnp_data_ck will free mbuf upon error */ 313 CTOH(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, seg_len); 314 if ((m = clnp_data_ck(m, seg_len)) == 0) 315 return; 316 317 clnp = mtod(m, struct clnp_fixed *); 318 hend = (caddr_t)clnp + clnp->cnf_hdr_len; 319 320 /* 321 * extract the source and destination address 322 * drop packet on failure 323 */ 324 bzero((caddr_t)&src, sizeof(src)); 325 bzero((caddr_t)&dst, sizeof(dst)); 326 327 hoff = (caddr_t)clnp + sizeof(struct clnp_fixed); 328 CLNP_EXTRACT_ADDR(dst, hoff, hend); 329 if (hoff == (caddr_t)0) { 330 INCSTAT(cns_badaddr); 331 clnp_discard(m, GEN_INCOMPLETE); 332 return; 333 } 334 CLNP_EXTRACT_ADDR(src, hoff, hend); 335 if (hoff == (caddr_t)0) { 336 INCSTAT(cns_badaddr); 337 clnp_discard(m, GEN_INCOMPLETE); 338 return; 339 } 340 341 IFDEBUG(D_INPUT) 342 printf("clnp_input: from %s", clnp_iso_addrp(&src)); 343 printf(" to %s\n", clnp_iso_addrp(&dst)); 344 ENDDEBUG 345 346 /* 347 * extract the segmentation information, if it is present. 348 * drop packet on failure 349 */ 350 if (((clnp->cnf_type & CNF_TYPE) != CLNP_ER) && 351 (clnp->cnf_type & CNF_SEG_OK)) { 352 if (hoff + sizeof(struct clnp_segment) > hend) { 353 INCSTAT(cns_noseg); 354 clnp_discard(m, GEN_INCOMPLETE); 355 return; 356 } else { 357 (void) bcopy(hoff, (caddr_t)&seg_part, sizeof(struct clnp_segment)); 358 /* make sure segmentation fields are in host order */ 359 seg_part.cng_id = ntohs(seg_part.cng_id); 360 seg_part.cng_off = ntohs(seg_part.cng_off); 361 seg_part.cng_tot_len = ntohs(seg_part.cng_tot_len); 362 seg_off = hoff - (caddr_t)clnp; 363 hoff += sizeof(struct clnp_segment); 364 } 365 } 366 367 /* 368 * process options if present. If clnp_opt_sanity returns 369 * false (indicating an error was found in the options) or 370 * an unsupported option was found 371 * then drop packet and emit an ER. 372 */ 373 if (hoff < hend) { 374 int errcode; 375 376 oidxp = &oidx; 377 errcode = clnp_opt_sanity(m, hoff, hend-hoff, oidxp); 378 379 /* we do not support security */ 380 if ((errcode == 0) && (oidxp->cni_securep)) 381 errcode = DISC_UNSUPPSECURE; 382 383 /* the er option is valid with ER pdus only */ 384 if ((errcode == 0) && (oidxp->cni_er_reason != ER_INVALREAS) && 385 ((clnp->cnf_type & CNF_TYPE) != CLNP_ER)) 386 errcode = DISC_UNSUPPOPT; 387 388 #ifdef DECBIT 389 /* check if the congestion experienced bit is set */ 390 if (oidxp->cni_qos_formatp) { 391 caddr_t qosp = CLNP_OFFTOOPT(m, oidxp->cni_qos_formatp); 392 u_char qos = *qosp; 393 394 need_afrin = ((qos & (CLNPOVAL_GLOBAL|CLNPOVAL_CONGESTED)) == 395 (CLNPOVAL_GLOBAL|CLNPOVAL_CONGESTED)); 396 if (need_afrin) 397 INCSTAT(cns_congest_rcvd); 398 } 399 #endif DECBIT 400 401 if (errcode != 0) { 402 clnp_discard(m, (char)errcode); 403 IFDEBUG(D_INPUT) 404 printf("clnp_input: dropped (err x%x) due to bad options\n", 405 errcode); 406 ENDDEBUG 407 return; 408 } 409 } 410 411 /* 412 * check if this packet is for us. if not, then forward 413 */ 414 if (clnp_ours(&dst) == 0) { 415 IFDEBUG(D_INPUT) 416 printf("clnp_input: forwarding packet not for us\n"); 417 ENDDEBUG 418 clnp_forward(m, seg_len, &dst, oidxp, seg_off, shp); 419 return; 420 } 421 422 /* 423 * ESIS Configuration Response Function 424 * 425 * If the packet received was sent to the multicast address 426 * all end systems, then send an esh to the source 427 */ 428 if ((shp->snh_flags & M_MCAST) && (iso_systype == SNPA_ES)) { 429 extern short esis_holding_time; 430 431 esis_shoutput(shp->snh_ifp, ESIS_ESH, esis_holding_time, 432 shp->snh_shost, 6); 433 } 434 435 /* 436 * If this is a fragment, then try to reassemble it. If clnp_reass 437 * returns non NULL, the packet has been reassembled, and should 438 * be give to TP. Otherwise the fragment has been delt with 439 * by the reassembly code (either stored or deleted). In either case 440 * we should have nothing more to do with it. 441 */ 442 if (((clnp->cnf_type & CNF_TYPE) != CLNP_ER) && 443 (clnp->cnf_type & CNF_SEG_OK) && 444 (seg_len != seg_part.cng_tot_len)) { 445 struct mbuf *m0; 446 447 if ((m0 = clnp_reass(m, &src, &dst, &seg_part)) != NULL) { 448 m = m0; 449 clnp = mtod(m, struct clnp_fixed *); 450 } else { 451 return; 452 } 453 } 454 455 /* 456 * give the packet to the higher layer 457 * 458 * Note: the total length of packet 459 * is the total length field of the segmentation part, 460 * or, if absent, the segment length field of the 461 * header. 462 */ 463 switch (clnp->cnf_type & CNF_TYPE) { 464 case CLNP_ER: 465 /* 466 * This ER must have the er option. 467 * If the option is not present, discard datagram. 468 */ 469 if (oidxp == NULL || oidxp->cni_er_reason == ER_INVALREAS) { 470 clnp_discard(m, GEN_HDRSYNTAX); 471 } else { 472 clnp_er_input(m, &src, oidxp->cni_er_reason); 473 } 474 break; 475 476 case CLNP_DT: 477 if (need_afrin) { 478 /* NOTE: do this before TP gets the packet so tp ack can use info*/ 479 IFDEBUG(D_INPUT) 480 printf("clnp_input: Calling tpclnp_ctlinput(%s)\n", 481 clnp_iso_addrp(&src)); 482 ENDDEBUG 483 tpclnp_ctlinput1(PRC_QUENCH2, &src); 484 } 485 (*isosw[clnp_protox[ISOPROTO_TP]].pr_input)(m, &src, &dst, 486 clnp->cnf_hdr_len); 487 break; 488 489 case CLNP_RAW: 490 case CLNP_ECR: 491 IFDEBUG(D_INPUT) 492 printf("clnp_input: raw input of %d bytes\n", 493 clnp->cnf_type & CNF_SEG_OK ? seg_part.cng_tot_len : seg_len); 494 ENDDEBUG 495 (*isosw[clnp_protox[ISOPROTO_RAW]].pr_input)(m, &src, &dst, 496 clnp->cnf_hdr_len); 497 break; 498 499 case CLNP_EC: 500 IFDEBUG(D_INPUT) 501 printf("clnp_input: echoing packet\n"); 502 ENDDEBUG 503 /* 504 * Switch the source and destination address, 505 */ 506 hoff = (caddr_t)clnp + sizeof(struct clnp_fixed); 507 CLNP_INSERT_ADDR(hoff, src); 508 CLNP_INSERT_ADDR(hoff, dst); 509 clnp->cnf_type &= ~CNF_TYPE; 510 clnp->cnf_type |= CLNP_ECR; 511 512 /* 513 * Forward back to sender 514 */ 515 clnp_forward(m, (int)(clnp->cnf_type & CNF_SEG_OK?seg_part.cng_tot_len : seg_len), 516 &src, oidxp, seg_off, shp); 517 break; 518 519 default: 520 printf("clnp_input: unknown clnp pkt type %d\n", 521 clnp->cnf_type & CNF_TYPE); 522 clnp_discard(m, GEN_HDRSYNTAX); 523 break; 524 } 525 } 526 #endif ISO 527