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