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: /var/src/sys/netiso/RCS/clnp_er.c,v 5.1 89/02/09 16:20:18 hagens Exp $ */ 28 /* $Source: /var/src/sys/netiso/RCS/clnp_er.c,v $ */ 29 30 #ifndef lint 31 static char *rcsid = "$Header: /var/src/sys/netiso/RCS/clnp_er.c,v 5.1 89/02/09 16:20:18 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 /* 167 * tpclnp_ctlinput1 is called directly so that we don't 168 * have to build an iso_sockaddr out of src. 169 */ 170 if (cmd >= 0) 171 tpclnp_ctlinput1(cmd, src); 172 173 m_freem(m); 174 } 175 176 /* 177 * FUNCTION: clnp_discard 178 * 179 * PURPOSE: Discard a clnp datagram 180 * 181 * RETURNS: nothing 182 * 183 * SIDE EFFECTS: Will emit an ER pdu if possible 184 * 185 * NOTES: This code assumes that we have previously tried to pull 186 * up the header of the datagram into one mbuf. 187 */ 188 clnp_discard(m, reason) 189 struct mbuf *m; /* header of packet to discard */ 190 char reason; /* reason for discard */ 191 { 192 IFDEBUG(D_DISCARD) 193 printf("clnp_discard: m x%x, reason x%x\n", m, reason); 194 ENDDEBUG 195 196 if (m != NULL) { 197 if (m->m_len >= sizeof(struct clnp_fixed)) { 198 register struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *); 199 200 if ((clnp->cnf_type != CLNP_ER) && (clnp->cnf_err_ok)) { 201 clnp_emit_er(m, reason); 202 return; 203 } 204 } 205 m_freem(m); 206 } 207 } 208 209 /* 210 * FUNCTION: clnp_emit_er 211 * 212 * PURPOSE: Send an ER pdu. 213 * The src of the of the ER pdu is the host that is sending 214 * the ER (ie. us), *not* the original destination of the 215 * packet. 216 * 217 * RETURNS: nothing 218 * 219 * SIDE EFFECTS: 220 * 221 * NOTES: Takes responsibility for freeing mbuf passed 222 * This function may be called with a packet that 223 * was created by us; in this case, do not send 224 * an ER. 225 */ 226 clnp_emit_er(m, reason) 227 struct mbuf *m; /* header of packet to discard */ 228 char reason; /* reason for discard */ 229 { 230 register struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *); 231 register struct clnp_fixed *er; 232 struct route route; 233 struct ifnet *ifp; 234 struct sockaddr *first_hop; 235 struct iso_addr src, dst, *our_addr; 236 caddr_t hoff, hend; 237 int total_len; /* total len of dg */ 238 struct mbuf *m0; /* contains er pdu hdr */ 239 240 IFDEBUG(D_DISCARD) 241 printf("clnp_emit_er: m x%x, hdr len %d\n", m, clnp->cnf_hdr_len); 242 ENDDEBUG 243 244 bzero((caddr_t)&route, sizeof(route)); 245 246 /* 247 * If header length is incorrect, or entire header is not contained 248 * in this mbuf, we punt 249 */ 250 if ((clnp->cnf_hdr_len < CLNP_HDR_MIN) || 251 (clnp->cnf_hdr_len > CLNP_HDR_MAX) || 252 (clnp->cnf_hdr_len > m->m_len)) 253 goto bad; 254 255 /* extract src, dest address */ 256 hend = (caddr_t)clnp + clnp->cnf_hdr_len; 257 hoff = (caddr_t)clnp + sizeof(struct clnp_fixed); 258 CLNP_EXTRACT_ADDR(dst, hoff, hend); 259 if (hoff == (caddr_t)0) { 260 goto bad; 261 } 262 CLNP_EXTRACT_ADDR(src, hoff, hend); 263 if (hoff == (caddr_t)0) { 264 goto bad; 265 } 266 267 /* 268 * Do not send ER if we generated the packet. 269 */ 270 if (clnp_ours(&src)) 271 goto bad; 272 273 /* 274 * Trim mbuf to hold only the header. 275 * This mbuf will be the 'data' of the er pdu 276 */ 277 if (m->m_next != NULL) { 278 m_freem(m->m_next); 279 m->m_next = NULL; 280 } 281 282 if (m->m_len > clnp->cnf_hdr_len) 283 m_adj(m, -(m->m_len - clnp->cnf_hdr_len)); 284 285 /* route er pdu: note we send pkt to src of original packet */ 286 if (clnp_route(&src, &route, /* flags */0, &first_hop, &ifp) != 0) 287 goto bad; 288 289 /* compute our address based upon firsthop/ifp */ 290 our_addr = 291 clnp_srcaddr(ifp, &((struct sockaddr_iso *)first_hop)->siso_addr); 292 if (our_addr == NULL) 293 goto bad; 294 295 IFDEBUG(D_DISCARD) 296 printf("clnp_emit_er: to %s", clnp_iso_addrp(&src)); 297 printf(" from %s\n", clnp_iso_addrp(our_addr)); 298 ENDDEBUG 299 300 IFDEBUG(D_DISCARD) 301 printf("clnp_emit_er: packet routed to %s\n", 302 clnp_iso_addrp(&((struct sockaddr_iso *)first_hop)->siso_addr)); 303 ENDDEBUG 304 305 /* allocate mbuf for er pdu header: punt on no space */ 306 MGET(m0, M_DONTWAIT, MT_HEADER); 307 if (m0 == 0) 308 goto bad; 309 310 m0->m_next = m; 311 er = mtod(m0, struct clnp_fixed *); 312 *er = er_template; 313 314 /* setup src/dst on er pdu */ 315 /* NOTE REVERSAL OF SRC/DST */ 316 hoff = (caddr_t)er + sizeof(struct clnp_fixed); 317 CLNP_INSERT_ADDR(hoff, &src); 318 CLNP_INSERT_ADDR(hoff, our_addr); 319 320 /* 321 * TODO: if complete src rt was specified, then reverse path, and 322 * copy into er as option. 323 */ 324 325 /* add er option */ 326 *hoff++ = CLNPOVAL_ERREAS; /* code */ 327 *hoff++ = 2; /* length */ 328 *hoff++ = reason; /* discard reason */ 329 *hoff++ = 0; /* error localization = not specified */ 330 331 /* set length */ 332 er->cnf_hdr_len = m0->m_len = (u_char)(hoff - (caddr_t)er); 333 total_len = m0->m_len + m->m_len; 334 HTOC(er->cnf_seglen_msb, er->cnf_seglen_lsb, total_len); 335 336 /* compute checksum (on header only) */ 337 iso_gen_csum(m0, CLNP_CKSUM_OFF, (int)er->cnf_hdr_len); 338 339 /* trim packet if too large for interface */ 340 if (total_len > ifp->if_mtu) 341 m_adj(m0, -(total_len - ifp->if_mtu)); 342 343 /* send packet */ 344 (void) (*ifp->if_output)(ifp, m0, first_hop); 345 goto done; 346 347 bad: 348 m_freem(m); 349 350 done: 351 /* free route if it is a temp */ 352 if (route.ro_rt != NULL) 353 RTFREE(route.ro_rt); 354 } 355 #endif ISO 356