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