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