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