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