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.10 (Berkeley) 01/16/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) { 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 sockaddr_iso source; /* source address of pkt */ 250 struct sockaddr_iso target; /* destination address of pkt */ 251 #define src source.siso_addr 252 #define dst target.siso_addr 253 caddr_t hoff; /* current offset in packet */ 254 caddr_t hend; /* address of end of header info */ 255 struct clnp_segment seg_part; /* segment part of hdr */ 256 int seg_off=0; /* offset of segment part of hdr */ 257 int seg_len;/* length of packet data&hdr in bytes */ 258 struct clnp_optidx oidx, *oidxp = NULL; /* option index */ 259 extern int iso_systype; /* used by ESIS config resp */ 260 extern struct sockaddr_iso blank_siso; /* used for initializing */ 261 int need_afrin = 0; 262 /* true if congestion experienced */ 263 /* which means you need afrin nose */ 264 /* spray. How clever! */ 265 266 IFDEBUG(D_INPUT) 267 printf( 268 "clnp_input: proccessing dg; First mbuf m_len %d, m_type x%x, %s\n", 269 m->m_len, m->m_type, IS_CLUSTER(m) ? "cluster" : "normal"); 270 ENDDEBUG 271 need_afrin = 0; 272 273 /* 274 * If no iso addresses have been set, there is nothing 275 * to do with the packet. 276 */ 277 if (iso_ifaddr == NULL) { 278 clnp_discard(m, ADDR_DESTUNREACH); 279 return; 280 } 281 282 INCSTAT(cns_total); 283 clnp = mtod(m, struct clnp_fixed *); 284 285 IFDEBUG(D_DUMPIN) 286 struct mbuf *mhead; 287 int total_len = 0; 288 printf("clnp_input: clnp header:\n"); 289 dump_buf(mtod(m, caddr_t), clnp->cnf_hdr_len); 290 printf("clnp_input: mbuf chain:\n"); 291 for (mhead = m; mhead != NULL; mhead=mhead->m_next) { 292 printf("m x%x, len %d\n", mhead, mhead->m_len); 293 total_len += mhead->m_len; 294 } 295 printf("clnp_input: total length of mbuf chain %d:\n", total_len); 296 ENDDEBUG 297 298 /* 299 * Compute checksum (if necessary) and drop packet if 300 * checksum does not match 301 */ 302 if (CKSUM_REQUIRED(clnp) && iso_check_csum(m, (int)clnp->cnf_hdr_len)) { 303 INCSTAT(cns_badcsum); 304 clnp_discard(m, GEN_BADCSUM); 305 return; 306 } 307 308 if (clnp->cnf_vers != ISO8473_V1) { 309 INCSTAT(cns_badvers); 310 clnp_discard(m, DISC_UNSUPPVERS); 311 return; 312 } 313 314 315 /* check mbuf data length: clnp_data_ck will free mbuf upon error */ 316 CTOH(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, seg_len); 317 if ((m = clnp_data_ck(m, seg_len)) == 0) 318 return; 319 320 clnp = mtod(m, struct clnp_fixed *); 321 hend = (caddr_t)clnp + clnp->cnf_hdr_len; 322 323 /* 324 * extract the source and destination address 325 * drop packet on failure 326 */ 327 source = target = blank_siso; 328 329 hoff = (caddr_t)clnp + sizeof(struct clnp_fixed); 330 CLNP_EXTRACT_ADDR(dst, hoff, hend); 331 if (hoff == (caddr_t)0) { 332 INCSTAT(cns_badaddr); 333 clnp_discard(m, GEN_INCOMPLETE); 334 return; 335 } 336 CLNP_EXTRACT_ADDR(src, hoff, hend); 337 if (hoff == (caddr_t)0) { 338 INCSTAT(cns_badaddr); 339 clnp_discard(m, GEN_INCOMPLETE); 340 return; 341 } 342 343 IFDEBUG(D_INPUT) 344 printf("clnp_input: from %s", clnp_iso_addrp(&src)); 345 printf(" to %s\n", clnp_iso_addrp(&dst)); 346 ENDDEBUG 347 348 /* 349 * extract the segmentation information, if it is present. 350 * drop packet on failure 351 */ 352 if (((clnp->cnf_type & CNF_TYPE) != CLNP_ER) && 353 (clnp->cnf_type & CNF_SEG_OK)) { 354 if (hoff + sizeof(struct clnp_segment) > hend) { 355 INCSTAT(cns_noseg); 356 clnp_discard(m, GEN_INCOMPLETE); 357 return; 358 } else { 359 (void) bcopy(hoff, (caddr_t)&seg_part, sizeof(struct clnp_segment)); 360 /* make sure segmentation fields are in host order */ 361 seg_part.cng_id = ntohs(seg_part.cng_id); 362 seg_part.cng_off = ntohs(seg_part.cng_off); 363 seg_part.cng_tot_len = ntohs(seg_part.cng_tot_len); 364 seg_off = hoff - (caddr_t)clnp; 365 hoff += sizeof(struct clnp_segment); 366 } 367 } 368 369 /* 370 * process options if present. If clnp_opt_sanity returns 371 * false (indicating an error was found in the options) or 372 * an unsupported option was found 373 * then drop packet and emit an ER. 374 */ 375 if (hoff < hend) { 376 int errcode; 377 378 oidxp = &oidx; 379 errcode = clnp_opt_sanity(m, hoff, hend-hoff, oidxp); 380 381 /* we do not support security */ 382 if ((errcode == 0) && (oidxp->cni_securep)) 383 errcode = DISC_UNSUPPSECURE; 384 385 /* the er option is valid with ER pdus only */ 386 if ((errcode == 0) && (oidxp->cni_er_reason != ER_INVALREAS) && 387 ((clnp->cnf_type & CNF_TYPE) != CLNP_ER)) 388 errcode = DISC_UNSUPPOPT; 389 390 #ifdef DECBIT 391 /* check if the congestion experienced bit is set */ 392 if (oidxp->cni_qos_formatp) { 393 caddr_t qosp = CLNP_OFFTOOPT(m, oidxp->cni_qos_formatp); 394 u_char qos = *qosp; 395 396 need_afrin = ((qos & (CLNPOVAL_GLOBAL|CLNPOVAL_CONGESTED)) == 397 (CLNPOVAL_GLOBAL|CLNPOVAL_CONGESTED)); 398 if (need_afrin) 399 INCSTAT(cns_congest_rcvd); 400 } 401 #endif DECBIT 402 403 if (errcode != 0) { 404 clnp_discard(m, (char)errcode); 405 IFDEBUG(D_INPUT) 406 printf("clnp_input: dropped (err x%x) due to bad options\n", 407 errcode); 408 ENDDEBUG 409 return; 410 } 411 } 412 413 /* 414 * check if this packet is for us. if not, then forward 415 */ 416 if (clnp_ours(&dst) == 0) { 417 IFDEBUG(D_INPUT) 418 printf("clnp_input: forwarding packet not for us\n"); 419 ENDDEBUG 420 clnp_forward(m, seg_len, &dst, oidxp, seg_off, shp); 421 return; 422 } 423 424 /* 425 * ESIS Configuration Response Function 426 * 427 * If the packet received was sent to the multicast address 428 * all end systems, then send an esh to the source 429 */ 430 if ((shp->snh_flags & M_MCAST) && (iso_systype == SNPA_ES)) { 431 extern short esis_holding_time; 432 433 esis_shoutput(shp->snh_ifp, ESIS_ESH, esis_holding_time, 434 shp->snh_shost, 6); 435 } 436 437 /* 438 * If this is a fragment, then try to reassemble it. If clnp_reass 439 * returns non NULL, the packet has been reassembled, and should 440 * be give to TP. Otherwise the fragment has been delt with 441 * by the reassembly code (either stored or deleted). In either case 442 * we should have nothing more to do with it. 443 */ 444 if (((clnp->cnf_type & CNF_TYPE) != CLNP_ER) && 445 (clnp->cnf_type & CNF_SEG_OK) && 446 (seg_len != seg_part.cng_tot_len)) { 447 struct mbuf *m0; 448 449 if ((m0 = clnp_reass(m, &src, &dst, &seg_part)) != NULL) { 450 m = m0; 451 clnp = mtod(m, struct clnp_fixed *); 452 INCSTAT(cns_reassembled); 453 } else { 454 return; 455 } 456 } 457 458 /* 459 * give the packet to the higher layer 460 * 461 * Note: the total length of packet 462 * is the total length field of the segmentation part, 463 * or, if absent, the segment length field of the 464 * header. 465 */ 466 INCSTAT(cns_delivered); 467 switch (clnp->cnf_type & CNF_TYPE) { 468 case CLNP_ER: 469 /* 470 * This ER must have the er option. 471 * If the option is not present, discard datagram. 472 */ 473 if (oidxp == NULL || oidxp->cni_er_reason == ER_INVALREAS) { 474 clnp_discard(m, GEN_HDRSYNTAX); 475 } else { 476 clnp_er_input(m, &src, oidxp->cni_er_reason); 477 } 478 break; 479 480 case CLNP_DT: 481 (*isosw[clnp_protox[ISOPROTO_TP]].pr_input)(m, &source, &target, 482 clnp->cnf_hdr_len, need_afrin); 483 break; 484 485 case CLNP_RAW: 486 case CLNP_ECR: 487 IFDEBUG(D_INPUT) 488 printf("clnp_input: raw input of %d bytes\n", 489 clnp->cnf_type & CNF_SEG_OK ? seg_part.cng_tot_len : seg_len); 490 ENDDEBUG 491 (*isosw[clnp_protox[ISOPROTO_RAW]].pr_input)(m, &src, &dst, 492 clnp->cnf_hdr_len); 493 break; 494 495 case CLNP_EC: 496 IFDEBUG(D_INPUT) 497 printf("clnp_input: echoing packet\n"); 498 ENDDEBUG 499 /* 500 * Switch the source and destination address, 501 */ 502 hoff = (caddr_t)clnp + sizeof(struct clnp_fixed); 503 CLNP_INSERT_ADDR(hoff, src); 504 CLNP_INSERT_ADDR(hoff, dst); 505 clnp->cnf_type &= ~CNF_TYPE; 506 clnp->cnf_type |= CLNP_ECR; 507 508 /* 509 * Forward back to sender 510 */ 511 clnp_forward(m, (int) 512 (clnp->cnf_type & CNF_SEG_OK ? seg_part.cng_tot_len : seg_len), 513 &src, oidxp, seg_off, 0); 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