1 /* 2 * Copyright (c) 1984, 1988, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)ns_error.c 8.2 (Berkeley) 02/09/95 8 */ 9 10 #include <sys/param.h> 11 #include <sys/systm.h> 12 #include <sys/malloc.h> 13 #include <sys/mbuf.h> 14 #include <sys/protosw.h> 15 #include <sys/socket.h> 16 #include <sys/socketvar.h> 17 #include <sys/time.h> 18 #include <sys/kernel.h> 19 20 #include <net/route.h> 21 22 #include <netns/ns.h> 23 #include <netns/ns_pcb.h> 24 #include <netns/idp.h> 25 #include <netns/ns_error.h> 26 27 #ifdef lint 28 #define NS_ERRPRINTFS 1 29 #endif 30 31 #ifdef NS_ERRPRINTFS 32 /* 33 * NS_ERR routines: error generation, receive packet processing, and 34 * routines to turnaround packets back to the originator. 35 */ 36 int ns_errprintfs = 0; 37 #endif 38 39 ns_err_x(c) 40 { 41 register u_short *w, *lim, *base = ns_errstat.ns_es_codes; 42 u_short x = c; 43 44 /* 45 * zero is a legit error code, handle specially 46 */ 47 if (x == 0) 48 return (0); 49 lim = base + NS_ERR_MAX - 1; 50 for (w = base + 1; w < lim; w++) { 51 if (*w == 0) 52 *w = x; 53 if (*w == x) 54 break; 55 } 56 return (w - base); 57 } 58 59 /* 60 * Generate an error packet of type error 61 * in response to bad packet. 62 */ 63 64 ns_error(om, type, param) 65 struct mbuf *om; 66 int type; 67 { 68 register struct ns_epidp *ep; 69 struct mbuf *m; 70 struct idp *nip; 71 register struct idp *oip = mtod(om, struct idp *); 72 extern int idpcksum; 73 74 /* 75 * If this packet was sent to the echo port, 76 * and nobody was there, just echo it. 77 * (Yes, this is a wart!) 78 */ 79 if (type == NS_ERR_NOSOCK && 80 oip->idp_dna.x_port == htons(2) && 81 (type = ns_echo(om))==0) 82 return; 83 84 #ifdef NS_ERRPRINTFS 85 if (ns_errprintfs) 86 printf("ns_err_error(%x, %d, %d)\n", oip, type, param); 87 #endif 88 /* 89 * Don't Generate error packets in response to multicasts. 90 */ 91 if (oip->idp_dna.x_host.c_host[0] & 1) 92 goto freeit; 93 94 ns_errstat.ns_es_error++; 95 /* 96 * Make sure that the old IDP packet had 30 bytes of data to return; 97 * if not, don't bother. Also don't EVER error if the old 98 * packet protocol was NS_ERR. 99 */ 100 if (oip->idp_len < sizeof(struct idp)) { 101 ns_errstat.ns_es_oldshort++; 102 goto freeit; 103 } 104 if (oip->idp_pt == NSPROTO_ERROR) { 105 ns_errstat.ns_es_oldns_err++; 106 goto freeit; 107 } 108 109 /* 110 * First, formulate ns_err message 111 */ 112 m = m_gethdr(M_DONTWAIT, MT_HEADER); 113 if (m == NULL) 114 goto freeit; 115 m->m_len = sizeof(*ep); 116 MH_ALIGN(m, m->m_len); 117 ep = mtod(m, struct ns_epidp *); 118 if ((u_int)type > NS_ERR_TOO_BIG) 119 panic("ns_err_error"); 120 ns_errstat.ns_es_outhist[ns_err_x(type)]++; 121 ep->ns_ep_errp.ns_err_num = htons((u_short)type); 122 ep->ns_ep_errp.ns_err_param = htons((u_short)param); 123 bcopy((caddr_t)oip, (caddr_t)&ep->ns_ep_errp.ns_err_idp, 42); 124 nip = &ep->ns_ep_idp; 125 nip->idp_len = sizeof(*ep); 126 nip->idp_len = htons((u_short)nip->idp_len); 127 nip->idp_pt = NSPROTO_ERROR; 128 nip->idp_tc = 0; 129 nip->idp_dna = oip->idp_sna; 130 nip->idp_sna = oip->idp_dna; 131 if (idpcksum) { 132 nip->idp_sum = 0; 133 nip->idp_sum = ns_cksum(m, sizeof(*ep)); 134 } else 135 nip->idp_sum = 0xffff; 136 (void) ns_output(m, (struct route *)0, 0); 137 138 freeit: 139 m_freem(om); 140 } 141 142 ns_printhost(p) 143 register struct ns_addr *p; 144 { 145 146 printf("<net:%x%x,host:%x%x%x,port:%x>", 147 p->x_net.s_net[0], 148 p->x_net.s_net[1], 149 p->x_host.s_host[0], 150 p->x_host.s_host[1], 151 p->x_host.s_host[2], 152 p->x_port); 153 154 } 155 156 /* 157 * Process a received NS_ERR message. 158 */ 159 ns_err_input(m) 160 struct mbuf *m; 161 { 162 register struct ns_errp *ep; 163 register struct ns_epidp *epidp = mtod(m, struct ns_epidp *); 164 register int i; 165 int type, code, param; 166 167 /* 168 * Locate ns_err structure in mbuf, and check 169 * that not corrupted and of at least minimum length. 170 */ 171 #ifdef NS_ERRPRINTFS 172 if (ns_errprintfs) { 173 printf("ns_err_input from "); 174 ns_printhost(&epidp->ns_ep_idp.idp_sna); 175 printf("len %d\n", ntohs(epidp->ns_ep_idp.idp_len)); 176 } 177 #endif 178 i = sizeof (struct ns_epidp); 179 if (((m->m_flags & M_EXT) || m->m_len < i) && 180 (m = m_pullup(m, i)) == 0) { 181 ns_errstat.ns_es_tooshort++; 182 return; 183 } 184 ep = &(mtod(m, struct ns_epidp *)->ns_ep_errp); 185 type = ntohs(ep->ns_err_num); 186 param = ntohs(ep->ns_err_param); 187 ns_errstat.ns_es_inhist[ns_err_x(type)]++; 188 189 #ifdef NS_ERRPRINTFS 190 /* 191 * Message type specific processing. 192 */ 193 if (ns_errprintfs) 194 printf("ns_err_input, type %d param %d\n", type, param); 195 #endif 196 if (type >= NS_ERR_TOO_BIG) { 197 goto badcode; 198 } 199 ns_errstat.ns_es_outhist[ns_err_x(type)]++; 200 switch (type) { 201 202 case NS_ERR_UNREACH_HOST: 203 code = PRC_UNREACH_NET; 204 goto deliver; 205 206 case NS_ERR_TOO_OLD: 207 code = PRC_TIMXCEED_INTRANS; 208 goto deliver; 209 210 case NS_ERR_TOO_BIG: 211 code = PRC_MSGSIZE; 212 goto deliver; 213 214 case NS_ERR_FULLUP: 215 code = PRC_QUENCH; 216 goto deliver; 217 218 case NS_ERR_NOSOCK: 219 code = PRC_UNREACH_PORT; 220 goto deliver; 221 222 case NS_ERR_UNSPEC_T: 223 case NS_ERR_BADSUM_T: 224 case NS_ERR_BADSUM: 225 case NS_ERR_UNSPEC: 226 code = PRC_PARAMPROB; 227 goto deliver; 228 229 deliver: 230 /* 231 * Problem with datagram; advise higher level routines. 232 */ 233 #ifdef NS_ERRPRINTFS 234 if (ns_errprintfs) 235 printf("deliver to protocol %d\n", 236 ep->ns_err_idp.idp_pt); 237 #endif 238 switch(ep->ns_err_idp.idp_pt) { 239 case NSPROTO_SPP: 240 spp_ctlinput(code, (caddr_t)ep); 241 break; 242 243 default: 244 idp_ctlinput(code, (caddr_t)ep); 245 } 246 247 goto freeit; 248 249 default: 250 badcode: 251 ns_errstat.ns_es_badcode++; 252 goto freeit; 253 254 } 255 freeit: 256 m_freem(m); 257 } 258 259 #ifdef notdef 260 u_long 261 nstime() 262 { 263 int s = splclock(); 264 u_long t; 265 266 t = (time.tv_sec % (24*60*60)) * 1000 + time.tv_usec / 1000; 267 splx(s); 268 return (htonl(t)); 269 } 270 #endif 271 272 ns_echo(m) 273 struct mbuf *m; 274 { 275 register struct idp *idp = mtod(m, struct idp *); 276 register struct echo { 277 struct idp ec_idp; 278 u_short ec_op; /* Operation, 1 = request, 2 = reply */ 279 } *ec = (struct echo *)idp; 280 struct ns_addr temp; 281 282 if (idp->idp_pt!=NSPROTO_ECHO) return(NS_ERR_NOSOCK); 283 if (ec->ec_op!=htons(1)) return(NS_ERR_UNSPEC); 284 285 ec->ec_op = htons(2); 286 287 temp = idp->idp_dna; 288 idp->idp_dna = idp->idp_sna; 289 idp->idp_sna = temp; 290 291 if (idp->idp_sum != 0xffff) { 292 idp->idp_sum = 0; 293 idp->idp_sum = ns_cksum(m, 294 (int)(((ntohs(idp->idp_len) - 1)|1)+1)); 295 } 296 (void) ns_output(m, (struct route *)0, NS_FORWARDING); 297 return(0); 298 } 299