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