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