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