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