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