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: clnp_input.c,v 4.4 88/09/08 08:38:15 hagens Exp $ */ 28 /* $Source: /usr/argo/sys/netiso/RCS/clnp_input.c,v $ */ 29 /* @(#)clnp_input.c 7.2 (Berkeley) 02/14/89 */ 30 31 #ifndef lint 32 static char *rcsid = "$Header: clnp_input.c,v 4.4 88/09/08 08:38:15 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 238 IFDEBUG(D_INPUT) 239 printf( 240 "clnp_input: proccessing dg; First mbuf m_len %d, m_type x%x, data:\n", 241 m->m_len, m->m_type); 242 ENDDEBUG 243 IFDEBUG(D_DUMPIN) 244 printf("clnp_input: first mbuf:\n"); 245 dump_buf(mtod(m, caddr_t), m->m_len); 246 ENDDEBUG 247 248 /* 249 * If no iso addresses have been set, there is nothing 250 * to do with the packet. 251 */ 252 if (iso_ifaddr == NULL) { 253 clnp_discard(m, ADDR_DESTUNREACH); 254 return; 255 } 256 257 INCSTAT(cns_total); 258 clnp = mtod(m, struct clnp_fixed *); 259 260 /* 261 * Compute checksum (if necessary) and drop packet if 262 * checksum does not match 263 */ 264 if (CKSUM_REQUIRED(clnp) && iso_check_csum(m, clnp->cnf_hdr_len)) { 265 INCSTAT(cns_badcsum); 266 clnp_discard(m, GEN_BADCSUM); 267 return; 268 } 269 270 if (clnp->cnf_vers != ISO8473_V1) { 271 INCSTAT(cns_badvers); 272 clnp_discard(m, DISC_UNSUPPVERS); 273 return; 274 } 275 276 277 /* check mbuf data length: clnp_data_ck will free mbuf upon error */ 278 CTOH(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, seg_len); 279 if ((m = clnp_data_ck(m, seg_len)) == 0) 280 return; 281 282 clnp = mtod(m, struct clnp_fixed *); 283 hend = (caddr_t)clnp + clnp->cnf_hdr_len; 284 285 /* 286 * extract the source and destination address 287 * drop packet on failure 288 */ 289 bzero((caddr_t)&src, sizeof(src)); 290 bzero((caddr_t)&dst, sizeof(dst)); 291 292 hoff = (caddr_t)clnp + sizeof(struct clnp_fixed); 293 CLNP_EXTRACT_ADDR(dst, hoff, hend); 294 if (hoff == (caddr_t)0) { 295 INCSTAT(cns_badaddr); 296 clnp_discard(m, GEN_INCOMPLETE); 297 return; 298 } 299 CLNP_EXTRACT_ADDR(src, hoff, hend); 300 if (hoff == (caddr_t)0) { 301 INCSTAT(cns_badaddr); 302 clnp_discard(m, GEN_INCOMPLETE); 303 return; 304 } 305 306 IFDEBUG(D_INPUT) 307 printf("clnp_input: from %s", clnp_iso_addrp(&src)); 308 printf(" to %s\n", clnp_iso_addrp(&dst)); 309 ENDDEBUG 310 311 /* 312 * extract the segmentation information, if it is present. 313 * drop packet on failure 314 */ 315 if ((clnp->cnf_type != CLNP_ER) && (clnp->cnf_seg_ok)) { 316 if (hoff + sizeof(struct clnp_segment) > hend) { 317 INCSTAT(cns_noseg); 318 clnp_discard(m, GEN_INCOMPLETE); 319 return; 320 } else { 321 (void) bcopy(hoff, (caddr_t)&seg_part, sizeof(struct clnp_segment)); 322 /* make sure segmentation fields are in host order */ 323 seg_part.cng_id = ntohs(seg_part.cng_id); 324 seg_part.cng_off = ntohs(seg_part.cng_off); 325 seg_part.cng_tot_len = ntohs(seg_part.cng_tot_len); 326 seg_off = hoff - (caddr_t)clnp; 327 hoff += sizeof(struct clnp_segment); 328 } 329 } 330 331 /* 332 * process options if present. If clnp_opt_sanity returns 333 * false (indicating an error was found in the options) or 334 * an unsupported option was found 335 * then drop packet and emit an ER. 336 */ 337 if (hoff < hend) { 338 int errcode; 339 340 oidxp = &oidx; 341 errcode = clnp_opt_sanity(m, hoff, hend-hoff, oidxp); 342 343 /* we do not support security */ 344 if ((errcode == 0) && (oidxp->cni_securep)) 345 errcode = DISC_UNSUPPSECURE; 346 347 /* the er option is valid with ER pdus only */ 348 if ((errcode == 0) && (oidxp->cni_er_reason != ER_INVALREAS) && 349 (clnp->cnf_type != CLNP_ER)) 350 errcode = DISC_UNSUPPOPT; 351 352 if (errcode != 0) { 353 clnp_discard(m, (char)errcode); 354 IFDEBUG(D_INPUT) 355 printf("clnp_input: dropped (err x%x) due to bad options\n", 356 errcode); 357 ENDDEBUG 358 return; 359 } 360 } 361 362 /* 363 * check if this packet is for us. if not, then forward 364 */ 365 if (clnp_ours(&dst) == 0) { 366 IFDEBUG(D_INPUT) 367 printf("clnp_input: forwarding packet not for us\n"); 368 ENDDEBUG 369 clnp_forward(m, seg_len, &dst, oidxp, seg_off, shp); 370 return; 371 } 372 373 /* 374 * ESIS Configuration Response Function 375 * 376 * If the packet received was sent to the multicast address 377 * all end systems, then send an esh to the source 378 */ 379 if ((IS_MULTICAST(shp->snh_dhost)) && (iso_systype == SNPA_ES)) { 380 extern short esis_holding_time; 381 382 esis_shoutput(shp->snh_ifp, ESIS_ESH, esis_holding_time, 383 shp->snh_shost, 6); 384 } 385 386 /* 387 * If this is a fragment, then try to reassemble it. If clnp_reass 388 * returns non NULL, the packet has been reassembled, and should 389 * be give to TP. Otherwise the fragment has been delt with 390 * by the reassembly code (either stored or deleted). In either case 391 * we should have nothing more to do with it. 392 */ 393 if ((clnp->cnf_type != CLNP_ER) && (clnp->cnf_seg_ok) && 394 (seg_len != seg_part.cng_tot_len)) { 395 struct mbuf *m0; 396 397 if ((m0 = clnp_reass(m, &src, &dst, &seg_part)) != NULL) { 398 m = m0; 399 clnp = mtod(m, struct clnp_fixed *); 400 } else { 401 return; 402 } 403 } 404 405 /* 406 * give the packet to the higher layer 407 * TODO: how do we tell TP that congestion bit is on in QOS option? 408 * 409 * Note: the total length of packet 410 * is the total length field of the segmentation part, 411 * or, if absent, the segment length field of the 412 * header. 413 */ 414 switch (clnp->cnf_type) { 415 case CLNP_ER: 416 /* 417 * This ER must have the er option. 418 * If the option is not present, discard datagram. 419 */ 420 if (oidxp == NULL || oidxp->cni_er_reason == ER_INVALREAS) { 421 clnp_discard(m, GEN_HDRSYNTAX); 422 } else { 423 clnp_er_input(m, &src, oidxp->cni_er_reason); 424 } 425 break; 426 427 case CLNP_DT: 428 (*isosw[clnp_protox[ISOPROTO_TP]].pr_input)(m, &src, &dst, 429 clnp->cnf_hdr_len); 430 break; 431 432 case CLNP_RAW: 433 case CLNP_ECR: 434 IFDEBUG(D_INPUT) 435 printf("clnp_input: raw input of %d bytes\n", 436 clnp->cnf_seg_ok ? seg_part.cng_tot_len : seg_len); 437 ENDDEBUG 438 (*isosw[clnp_protox[ISOPROTO_RAW]].pr_input)(m, &src, &dst, 439 clnp->cnf_hdr_len); 440 break; 441 442 case CLNP_EC: 443 IFDEBUG(D_INPUT) 444 printf("clnp_input: echoing packet\n"); 445 ENDDEBUG 446 /* 447 * Switch the source and destination address, 448 */ 449 hoff = (caddr_t)clnp + sizeof(struct clnp_fixed); 450 CLNP_INSERT_ADDR(hoff, &src); 451 CLNP_INSERT_ADDR(hoff, &dst); 452 clnp->cnf_type = CLNP_ECR; 453 454 /* 455 * Forward back to sender 456 */ 457 clnp_forward(m, clnp->cnf_seg_ok ? seg_part.cng_tot_len : seg_len, 458 &src, oidxp, seg_off, shp); 459 break; 460 461 default: 462 printf("clnp_input: unknown clnp pkt type %d\n", clnp->cnf_type); 463 clnp_discard(m, GEN_HDRSYNTAX); 464 break; 465 } 466 } 467 468 int clnp_ctlinput() 469 { 470 } 471 472 #endif ISO 473