1*36368Ssklower /*********************************************************** 2*36368Ssklower Copyright IBM Corporation 1987 3*36368Ssklower 4*36368Ssklower All Rights Reserved 5*36368Ssklower 6*36368Ssklower Permission to use, copy, modify, and distribute this software and its 7*36368Ssklower documentation for any purpose and without fee is hereby granted, 8*36368Ssklower provided that the above copyright notice appear in all copies and that 9*36368Ssklower both that copyright notice and this permission notice appear in 10*36368Ssklower supporting documentation, and that the name of IBM not be 11*36368Ssklower used in advertising or publicity pertaining to distribution of the 12*36368Ssklower software without specific, written prior permission. 13*36368Ssklower 14*36368Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 15*36368Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 16*36368Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 17*36368Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 18*36368Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 19*36368Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 20*36368Ssklower SOFTWARE. 21*36368Ssklower 22*36368Ssklower ******************************************************************/ 23*36368Ssklower 24*36368Ssklower /* 25*36368Ssklower * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison 26*36368Ssklower */ 27*36368Ssklower /* $Header: clnp_er.c,v 4.4 88/09/10 18:31:10 hagens Exp $ */ 28*36368Ssklower /* $Source: /usr/argo/sys/netiso/RCS/clnp_er.c,v $ */ 29*36368Ssklower 30*36368Ssklower #ifndef lint 31*36368Ssklower static char *rcsid = "$Header: clnp_er.c,v 4.4 88/09/10 18:31:10 hagens Exp $"; 32*36368Ssklower #endif lint 33*36368Ssklower 34*36368Ssklower #ifdef ISO 35*36368Ssklower 36*36368Ssklower #include "../h/types.h" 37*36368Ssklower #include "../h/param.h" 38*36368Ssklower #include "../h/mbuf.h" 39*36368Ssklower #include "../h/domain.h" 40*36368Ssklower #include "../h/protosw.h" 41*36368Ssklower #include "../h/socket.h" 42*36368Ssklower #include "../h/socketvar.h" 43*36368Ssklower #include "../h/errno.h" 44*36368Ssklower 45*36368Ssklower #include "../net/if.h" 46*36368Ssklower #include "../net/route.h" 47*36368Ssklower 48*36368Ssklower #include "../netiso/iso.h" 49*36368Ssklower #include "../netiso/clnp.h" 50*36368Ssklower #include "../netiso/clnp_stat.h" 51*36368Ssklower #include "../netiso/argo_debug.h" 52*36368Ssklower 53*36368Ssklower static struct clnp_fixed er_template = { 54*36368Ssklower ISO8473_CLNP, /* network identifier */ 55*36368Ssklower 0, /* length */ 56*36368Ssklower ISO8473_V1, /* version */ 57*36368Ssklower CLNP_TTL, /* ttl */ 58*36368Ssklower #if BYTE_ORDER == LITTLE_ENDIAN 59*36368Ssklower CLNP_ER, /* type */ 60*36368Ssklower 0, /* error report */ 61*36368Ssklower 0, /* more segments */ 62*36368Ssklower 0, /* segmentation permitted */ 63*36368Ssklower #endif 64*36368Ssklower #if BYTE_ORDER == BIG_ENDIAN 65*36368Ssklower 0, /* segmentation permitted */ 66*36368Ssklower 0, /* more segments */ 67*36368Ssklower 0, /* error report */ 68*36368Ssklower CLNP_ER, /* type */ 69*36368Ssklower #endif 70*36368Ssklower 0, /* segment length */ 71*36368Ssklower 0 /* checksum */ 72*36368Ssklower }; 73*36368Ssklower 74*36368Ssklower /* 75*36368Ssklower * FUNCTION: clnp_er_input 76*36368Ssklower * 77*36368Ssklower * PURPOSE: Process an ER pdu. 78*36368Ssklower * 79*36368Ssklower * RETURNS: 80*36368Ssklower * 81*36368Ssklower * SIDE EFFECTS: 82*36368Ssklower * 83*36368Ssklower * NOTES: 84*36368Ssklower */ 85*36368Ssklower clnp_er_input(m, src, reason) 86*36368Ssklower struct mbuf *m; /* ptr to packet itself */ 87*36368Ssklower struct iso_addr *src; /* ptr to src of er */ 88*36368Ssklower char reason; /* reason code of er */ 89*36368Ssklower { 90*36368Ssklower int cmd = -1; 91*36368Ssklower extern u_char clnp_protox[]; 92*36368Ssklower 93*36368Ssklower IFDEBUG(D_CTLINPUT) 94*36368Ssklower printf("clnp_er_input: m x%x, src %s, reason x%x\n", m, 95*36368Ssklower clnp_iso_addrp(src), reason); 96*36368Ssklower ENDDEBUG 97*36368Ssklower 98*36368Ssklower INCSTAT(cns_errcvd); 99*36368Ssklower 100*36368Ssklower switch (reason) { 101*36368Ssklower case GEN_NOREAS: 102*36368Ssklower case GEN_PROTOERR: 103*36368Ssklower INCSTAT(er_protoerr); 104*36368Ssklower break; 105*36368Ssklower case GEN_BADCSUM: 106*36368Ssklower cmd = PRC_PARAMPROB; 107*36368Ssklower INCSTAT(er_badcsum); 108*36368Ssklower break; 109*36368Ssklower case GEN_CONGEST: 110*36368Ssklower cmd = PRC_QUENCH; 111*36368Ssklower INCSTAT(er_congest); 112*36368Ssklower break; 113*36368Ssklower case GEN_HDRSYNTAX: 114*36368Ssklower cmd = PRC_PARAMPROB; 115*36368Ssklower INCSTAT(er_protoerr); 116*36368Ssklower break; 117*36368Ssklower case GEN_SEGNEEDED: 118*36368Ssklower cmd = PRC_UNREACH_NEEDFRAG; 119*36368Ssklower INCSTAT(er_segneeded); 120*36368Ssklower break; 121*36368Ssklower case GEN_INCOMPLETE: 122*36368Ssklower cmd = PRC_PARAMPROB; 123*36368Ssklower INCSTAT(er_reassfail); 124*36368Ssklower break; 125*36368Ssklower case GEN_DUPOPT: 126*36368Ssklower cmd = PRC_PARAMPROB; 127*36368Ssklower INCSTAT(er_protoerr); 128*36368Ssklower break; 129*36368Ssklower case ADDR_DESTUNREACH: 130*36368Ssklower cmd = PRC_UNREACH_HOST; 131*36368Ssklower INCSTAT(er_dstunreach); 132*36368Ssklower break; 133*36368Ssklower case ADDR_DESTUNKNOWN: 134*36368Ssklower cmd = PRC_UNREACH_PROTOCOL; 135*36368Ssklower INCSTAT(er_dstunreach); 136*36368Ssklower break; 137*36368Ssklower case SRCRT_UNSPECERR: 138*36368Ssklower case SRCRT_SYNTAX: 139*36368Ssklower case SRCRT_UNKNOWNADDR: 140*36368Ssklower case SRCRT_BADPATH: 141*36368Ssklower cmd = PRC_UNREACH_SRCFAIL; 142*36368Ssklower INCSTAT(er_srcrterr); 143*36368Ssklower break; 144*36368Ssklower case TTL_EXPTRANSIT: 145*36368Ssklower cmd = PRC_TIMXCEED_INTRANS; 146*36368Ssklower INCSTAT(er_ttlexpired); 147*36368Ssklower break; 148*36368Ssklower case TTL_EXPREASS: 149*36368Ssklower cmd = PRC_TIMXCEED_REASS; 150*36368Ssklower INCSTAT(er_ttlexpired); 151*36368Ssklower break; 152*36368Ssklower case DISC_UNSUPPOPT: 153*36368Ssklower case DISC_UNSUPPVERS: 154*36368Ssklower case DISC_UNSUPPSECURE: 155*36368Ssklower case DISC_UNSUPPSRCRT: 156*36368Ssklower case DISC_UNSUPPRECRT: 157*36368Ssklower cmd = PRC_PARAMPROB; 158*36368Ssklower INCSTAT(er_unsupported); 159*36368Ssklower break; 160*36368Ssklower case REASS_INTERFERE: 161*36368Ssklower cmd = PRC_TIMXCEED_REASS; 162*36368Ssklower INCSTAT(er_reassfail); 163*36368Ssklower break; 164*36368Ssklower } 165*36368Ssklower 166*36368Ssklower if (cmd >= 0) 167*36368Ssklower (*isosw[clnp_protox[ISOPROTO_TP]].pr_ctlinput)(cmd, src); 168*36368Ssklower 169*36368Ssklower m_freem(m); 170*36368Ssklower } 171*36368Ssklower 172*36368Ssklower /* 173*36368Ssklower * FUNCTION: clnp_discard 174*36368Ssklower * 175*36368Ssklower * PURPOSE: Discard a clnp datagram 176*36368Ssklower * 177*36368Ssklower * RETURNS: nothing 178*36368Ssklower * 179*36368Ssklower * SIDE EFFECTS: Will emit an ER pdu if possible 180*36368Ssklower * 181*36368Ssklower * NOTES: This code assumes that we have previously tried to pull 182*36368Ssklower * up the header of the datagram into one mbuf. 183*36368Ssklower */ 184*36368Ssklower clnp_discard(m, reason) 185*36368Ssklower struct mbuf *m; /* header of packet to discard */ 186*36368Ssklower char reason; /* reason for discard */ 187*36368Ssklower { 188*36368Ssklower IFDEBUG(D_DISCARD) 189*36368Ssklower printf("clnp_discard: m x%x, reason x%x\n", m, reason); 190*36368Ssklower ENDDEBUG 191*36368Ssklower 192*36368Ssklower if (m != NULL) { 193*36368Ssklower if (m->m_len >= sizeof(struct clnp_fixed)) { 194*36368Ssklower register struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *); 195*36368Ssklower 196*36368Ssklower if ((clnp->cnf_type != CLNP_ER) && (clnp->cnf_err_ok)) { 197*36368Ssklower clnp_emit_er(m, reason); 198*36368Ssklower return; 199*36368Ssklower } 200*36368Ssklower } 201*36368Ssklower m_freem(m); 202*36368Ssklower } 203*36368Ssklower } 204*36368Ssklower 205*36368Ssklower /* 206*36368Ssklower * FUNCTION: clnp_emit_er 207*36368Ssklower * 208*36368Ssklower * PURPOSE: Send an ER pdu. 209*36368Ssklower * The src of the of the ER pdu is the host that is sending 210*36368Ssklower * the ER (ie. us), *not* the original destination of the 211*36368Ssklower * packet. 212*36368Ssklower * 213*36368Ssklower * RETURNS: nothing 214*36368Ssklower * 215*36368Ssklower * SIDE EFFECTS: 216*36368Ssklower * 217*36368Ssklower * NOTES: Takes responsibility for freeing mbuf passed 218*36368Ssklower * This function may be called with a packet that 219*36368Ssklower * was created by us; in this case, do not send 220*36368Ssklower * an ER. 221*36368Ssklower */ 222*36368Ssklower clnp_emit_er(m, reason) 223*36368Ssklower struct mbuf *m; /* header of packet to discard */ 224*36368Ssklower char reason; /* reason for discard */ 225*36368Ssklower { 226*36368Ssklower register struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *); 227*36368Ssklower register struct clnp_fixed *er; 228*36368Ssklower struct route route; 229*36368Ssklower struct ifnet *ifp; 230*36368Ssklower struct sockaddr *first_hop; 231*36368Ssklower struct iso_addr src, dst, *our_addr; 232*36368Ssklower caddr_t hoff, hend; 233*36368Ssklower int total_len; /* total len of dg */ 234*36368Ssklower struct mbuf *m0; /* contains er pdu hdr */ 235*36368Ssklower /* struct clnp_optidx *oidx; index for options on orig pkt */ 236*36368Ssklower 237*36368Ssklower IFDEBUG(D_DISCARD) 238*36368Ssklower printf("clnp_emit_er: m x%x, hdr len %d\n", m, clnp->cnf_hdr_len); 239*36368Ssklower ENDDEBUG 240*36368Ssklower 241*36368Ssklower bzero((caddr_t)&route, sizeof(route)); 242*36368Ssklower 243*36368Ssklower /* 244*36368Ssklower * If header length is incorrect, or entire header is not contained 245*36368Ssklower * in this mbuf, we punt 246*36368Ssklower */ 247*36368Ssklower if ((clnp->cnf_hdr_len < CLNP_HDR_MIN) || 248*36368Ssklower (clnp->cnf_hdr_len > CLNP_HDR_MAX) || 249*36368Ssklower (clnp->cnf_hdr_len > m->m_len)) 250*36368Ssklower goto bad; 251*36368Ssklower 252*36368Ssklower /* extract src, dest address */ 253*36368Ssklower hend = (caddr_t)clnp + clnp->cnf_hdr_len; 254*36368Ssklower hoff = (caddr_t)clnp + sizeof(struct clnp_fixed); 255*36368Ssklower CLNP_EXTRACT_ADDR(dst, hoff, hend); 256*36368Ssklower if (hoff == (caddr_t)0) { 257*36368Ssklower goto bad; 258*36368Ssklower } 259*36368Ssklower CLNP_EXTRACT_ADDR(src, hoff, hend); 260*36368Ssklower if (hoff == (caddr_t)0) { 261*36368Ssklower goto bad; 262*36368Ssklower } 263*36368Ssklower 264*36368Ssklower /* 265*36368Ssklower * Do not send ER if we generated the packet. 266*36368Ssklower */ 267*36368Ssklower if (clnp_ours(&src)) 268*36368Ssklower goto bad; 269*36368Ssklower 270*36368Ssklower /* 271*36368Ssklower * Trim mbuf to hold only the header. 272*36368Ssklower * This mbuf will be the 'data' of the er pdu 273*36368Ssklower */ 274*36368Ssklower if (m->m_next != NULL) { 275*36368Ssklower m_freem(m->m_next); 276*36368Ssklower m->m_next = NULL; 277*36368Ssklower } 278*36368Ssklower 279*36368Ssklower if (m->m_len > clnp->cnf_hdr_len) 280*36368Ssklower m_adj(m, -(m->m_len - clnp->cnf_hdr_len)); 281*36368Ssklower 282*36368Ssklower /* route er pdu: note we send pkt to src of original packet */ 283*36368Ssklower if (clnp_route(&src, &route, /* flags */0, &first_hop, &ifp) != 0) 284*36368Ssklower goto bad; 285*36368Ssklower 286*36368Ssklower /* compute our address based upon firsthop/ifp */ 287*36368Ssklower our_addr = 288*36368Ssklower clnp_srcaddr(ifp, &((struct sockaddr_iso *)first_hop)->siso_addr); 289*36368Ssklower if (our_addr == NULL) 290*36368Ssklower goto bad; 291*36368Ssklower 292*36368Ssklower IFDEBUG(D_DISCARD) 293*36368Ssklower printf("clnp_emit_er: to %s", clnp_iso_addrp(&src)); 294*36368Ssklower printf(" from %s\n", clnp_iso_addrp(our_addr)); 295*36368Ssklower ENDDEBUG 296*36368Ssklower 297*36368Ssklower IFDEBUG(D_DISCARD) 298*36368Ssklower printf("clnp_emit_er: packet routed to %s\n", 299*36368Ssklower clnp_iso_addrp(&((struct sockaddr_iso *)first_hop)->siso_addr)); 300*36368Ssklower ENDDEBUG 301*36368Ssklower 302*36368Ssklower /* allocate mbuf for er pdu header: punt on no space */ 303*36368Ssklower MGET(m0, M_DONTWAIT, MT_HEADER); 304*36368Ssklower if (m0 == 0) 305*36368Ssklower goto bad; 306*36368Ssklower 307*36368Ssklower m0->m_next = m; 308*36368Ssklower er = mtod(m0, struct clnp_fixed *); 309*36368Ssklower *er = er_template; 310*36368Ssklower 311*36368Ssklower /* setup src/dst on er pdu */ 312*36368Ssklower /* NOTE REVERSAL OF SRC/DST */ 313*36368Ssklower hoff = (caddr_t)er + sizeof(struct clnp_fixed); 314*36368Ssklower CLNP_INSERT_ADDR(hoff, &src); 315*36368Ssklower CLNP_INSERT_ADDR(hoff, our_addr); 316*36368Ssklower 317*36368Ssklower /* 318*36368Ssklower * TODO: if complete src rt was specified, then reverse path, and 319*36368Ssklower * copy into er as option. 320*36368Ssklower */ 321*36368Ssklower 322*36368Ssklower /* add er option */ 323*36368Ssklower *hoff++ = CLNPOVAL_ERREAS; /* code */ 324*36368Ssklower *hoff++ = 2; /* length */ 325*36368Ssklower *hoff++ = reason; /* discard reason */ 326*36368Ssklower *hoff++ = 0; /* error localization = not specified */ 327*36368Ssklower 328*36368Ssklower /* set length */ 329*36368Ssklower er->cnf_hdr_len = m0->m_len = (u_char)(hoff - (caddr_t)er); 330*36368Ssklower total_len = m0->m_len + m->m_len; 331*36368Ssklower HTOC(er->cnf_seglen_msb, er->cnf_seglen_lsb, total_len); 332*36368Ssklower 333*36368Ssklower /* compute checksum (on header only) */ 334*36368Ssklower iso_gen_csum(m0, CLNP_CKSUM_OFF, (int)er->cnf_hdr_len); 335*36368Ssklower 336*36368Ssklower /* trim packet if too large for interface */ 337*36368Ssklower if (total_len > ifp->if_mtu) 338*36368Ssklower m_adj(m0, -(total_len - ifp->if_mtu)); 339*36368Ssklower 340*36368Ssklower /* send packet */ 341*36368Ssklower (void) (*ifp->if_output)(ifp, m0, first_hop); 342*36368Ssklower goto done; 343*36368Ssklower 344*36368Ssklower bad: 345*36368Ssklower m_freem(m); 346*36368Ssklower 347*36368Ssklower done: 348*36368Ssklower /* free route if it is a temp */ 349*36368Ssklower if (route.ro_rt != NULL) 350*36368Ssklower RTFREE(route.ro_rt); 351*36368Ssklower } 352*36368Ssklower #endif ISO 353