xref: /original-bsd/sys/netns/ns_error.c (revision 3705696b)
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