Add copyright
[unix-history] / usr / src / sys / netns / ns_input.c
CommitLineData
c7ea7bd3 1/* ns_input.c 6.2 85/06/01 */
bbcda6f4
KS
2
3#include "param.h"
4#include "systm.h"
5#include "mbuf.h"
6#include "domain.h"
7#include "protosw.h"
8#include "socket.h"
9#include "socketvar.h"
10#include "errno.h"
11#include "time.h"
12#include "kernel.h"
13
14#include "../net/if.h"
15#include "../net/route.h"
16#include "../net/raw_cb.h"
17
18#include "ns.h"
19#include "ns_if.h"
20#include "ns_pcb.h"
21#include "idp.h"
22#include "idp_var.h"
23#include "ns_error.h"
24
25/*
26 * NS initialization.
27 */
28union ns_host ns_thishost;
29union ns_host ns_zerohost;
30union ns_host ns_broadhost;
31
32static char allones[] = {-1, -1, -1, -1, -1, -1};
33
34struct nspcb nspcb;
35struct nspcb nsrawpcb;
36
37struct ifqueue nsintrq;
38int nsqmaxlen = IFQ_MAXLEN;
39
40int idpcksum = 0;
41
42ns_init()
43{
44 ns_broadhost = * (union ns_host *) allones;
45 nspcb.nsp_next = nspcb.nsp_prev = &nspcb;
46 nsrawpcb.nsp_next = nsrawpcb.nsp_prev = &nsrawpcb;
47 nsintrq.ifq_maxlen = nsqmaxlen;
48}
49
50/*
51 * Idp input routine. Pass to next level.
52 */
53int nsintr_getpck = 0;
54int nsintr_swtch = 0;
55nsintr()
56{
57 register struct idp *idp;
58 register struct mbuf *m;
59 struct nspcb *nsp;
60 struct mbuf *m0;
61 register int i;
62 int len, s, error;
63 char oddpacketp;
64
65next:
66 /*
67 * Get next datagram off input queue and get IDP header
68 * in first mbuf.
69 */
70 s = splimp();
71 IF_DEQUEUE(&nsintrq, m);
72 splx(s);
73 nsintr_getpck++;
74 if (m == 0)
75 return;
76 if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct idp)) &&
77 (m = m_pullup(m, sizeof (struct idp))) == 0) {
78 idpstat.idps_toosmall++;
79 goto next;
80 }
81
82 /*
83 * Give any raw listeners a crack at the packet
84 */
85 for (nsp = nsrawpcb.nsp_next; nsp != &nsrawpcb; nsp = nsp->nsp_next) {
86 struct mbuf *m1 = m_copy(m, 0, M_COPYALL);
87 if (m1) idp_input(m1, nsp);
88 }
89
90 idp = mtod(m, struct idp *);
91 len = ntohs(idp->idp_len);
92 if (oddpacketp = len & 1) {
93 len++; /* If this packet is of odd length,
94 preserve garbage byte for checksum */
95 }
96
97 /*
98 * Check that the amount of data in the buffers
99 * is as at least much as the IDP header would have us expect.
100 * Trim mbufs if longer than we expect.
101 * Drop packet if shorter than we expect.
102 */
103 i = -len;
104 m0 = m;
105 for (;;) {
106 i += m->m_len;
107 if (m->m_next == 0)
108 break;
109 m = m->m_next;
110 }
111 if (i != 0) {
112 if (i < 0) {
113 idpstat.idps_tooshort++;
114 m = m0;
115 goto bad;
116 }
117 if (i <= m->m_len)
118 m->m_len -= i;
119 else
120 m_adj(m0, -i);
121 }
122 m = m0;
123 if (idpcksum && ((i = idp->idp_sum)!=0xffff)) {
124 idp->idp_sum = 0;
125 if (i != (idp->idp_sum = ns_cksum(m,len))) {
126 idpstat.idps_badsum++;
127 if (ns_hosteqnh(ns_thishost, idp->idp_dna.x_host))
128 error = NS_ERR_BADSUM;
129 else
130 error = NS_ERR_BADSUM_T;
131 ns_error(m, error, 0);
132 goto next;
133 }
134 }
135 /*
136 * Is this a directed broadcast?
137 */
138 if (ns_hosteqnh(ns_broadhost,idp->idp_dna.x_host)) {
139 if ((ns_netof(idp->idp_dna)!=ns_netof(idp->idp_sna)) &&
140 (ns_netof(idp->idp_dna)!=-1) && (ns_netof(idp->idp_sna)!=0)
141 && (ns_netof(idp->idp_dna)!=0)) {
142 /*
c7ea7bd3
KS
143 * Look to see if I need to eat this packet.
144 * Algorithm is to forward all young packets
145 * and prematurely age any packets which will
146 * by physically broadcasted.
147 * Any very old packets eaten without forwarding
148 * would die anyway.
149 *
150 * Suggestion of Bill Nesheim, Cornell U.
bbcda6f4 151 */
c7ea7bd3
KS
152 if(idp->idp_tc < NS_MAXHOPS) {
153 idp_forward(idp);
bbcda6f4 154 goto next;
c7ea7bd3 155 }
bbcda6f4
KS
156 }
157 /*
158 * Is this our packet? If not, forward.
159 */
160 } else if (!ns_hosteqnh(ns_thishost,idp->idp_dna.x_host)) {
161 idp_forward(idp);
162 goto next;
163 }
164
165 /*
166 * Locate pcb for datagram.
167 */
168 nsp = ns_pcblookup(&idp->idp_sna, idp->idp_dna.x_port, NS_WILDCARD);
169
170
171 /*
172 * Switch out to protocol's input routine.
173 */
174
175 nsintr_swtch++;
176 if (nsp) {
177 if (oddpacketp) {
178 m_adj(m0, -1);
179 }
180 switch (idp->idp_pt) {
181 case NSPROTO_SPP:
182 spp_input(m,nsp);
183 break;
184 case NSPROTO_ERROR:
185 ns_err_input(m);
186 break;
187 default:
188 idp_input(m,nsp);
189 }
190 } else {
191 /* don't send ERROR response for multicast packet */
192 if (idp->idp_dna.x_host.c_host[0] & 1)
193 goto bad;
194 ns_error(m, NS_ERR_NOSOCK, 0);
195 }
196 goto next;
197
198bad:
199 m_freem(m);
200 goto next;
201}
202
203u_char nsctlerrmap[PRC_NCMDS] = {
204 ECONNABORTED, ECONNABORTED, 0, 0,
205 0, 0, EHOSTDOWN, EHOSTUNREACH,
206 ENETUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED,
207 EMSGSIZE, 0, 0, 0,
208 0, 0, 0, 0
209};
210
211idp_ctlinput(cmd, arg)
212 int cmd;
213 caddr_t arg;
214{
215 struct ns_addr *ns;
216 int idp_abort();
217 int type;
218
219 if (cmd < 0 || cmd > PRC_NCMDS)
220 return;
221 if (nsctlerrmap[cmd] == 0)
222 return; /* XXX */
223 type = NS_ERR_UNREACH_HOST;
224 if (cmd == PRC_IFDOWN)
225 ns = &((struct sockaddr_ns *)arg)->sns_addr;
226 else if (cmd == PRC_HOSTDEAD || cmd == PRC_HOSTUNREACH)
227 ns = (struct ns_addr *)arg;
228 else {
229 ns = &((struct ns_errp *)arg)->ns_err_idp.idp_dna;
230 type = ((struct ns_errp *)arg)->ns_err_num;
231 type = ntohs(type);
232 }
233 switch (type) {
234 case NS_ERR_UNREACH_HOST:
235 case NS_ERR_NOSOCK:
236 ns_pcbnotify(ns, (int)nsctlerrmap[cmd], idp_abort, 0);
237 }
238}
239
240int idpprintfs = 0;
241int idpforwarding = 1;
242/*
243 * Forward a packet. If some error occurs return the sender
244 * an error packet. Note we can't always generate a meaningful
245 * error message because the NS errors don't have a large enough repetoire
246 * of codes and types.
247 */
248struct route idp_droute;
249struct route idp_sroute;
250
251idp_forward(idp)
252 register struct idp *idp;
253{
254 register int error, type, code;
c7ea7bd3
KS
255 struct mbuf *mcopy = NULL;
256 int agedelta = 1;
257 int flags = NS_FORWARDING;
258 int ok_there = 0;
259 int ok_back = 0;
bbcda6f4
KS
260
261 if (idpprintfs) {
262 printf("forward: src ");
263 ns_printhost(&idp->idp_sna);
264 printf(", dst ");
265 ns_printhost(&idp->idp_dna);
266 printf("hop count %d\n", idp->idp_tc);
267 }
268 if (idpforwarding == 0) {
269 /* can't tell difference between net and host */
270 type = NS_ERR_UNREACH_HOST, code = 0;
271 goto senderror;
272 }
273 idp->idp_tc++;
274 if (idp->idp_tc > NS_MAXHOPS) {
275 type = NS_ERR_TOO_OLD, code = 0;
276 goto senderror;
277 }
c7ea7bd3
KS
278 /*
279 * Save at most 42 bytes of the packet in case
280 * we need to generate an NS error message to the src.
281 */
282 mcopy = m_copy(dtom(idp), 0, imin(ntohs(idp->idp_len), 42));
283
284 if((ok_there = idp_do_route(&idp->idp_dna,&idp_droute))==0) {
285 type = NS_ERR_UNREACH_HOST, code = 0;
286 goto senderror;
287 }
288 /*
289 * Here we think about forwarding broadcast packets,
290 * so we try to insure that it doesn't go back out
291 * on the interface it came in on. Also, if we
292 * are going to physically broadcast this, let us
293 * age the packet so we can eat it safely the second time around.
294 */
295 if (idp->idp_dna.x_host.c_host[0] & 0x1) {
296 struct ns_ifaddr *ia = ns_iaonnetof(idp->idp_dna.x_net);
297 struct ifnet *ifp;
298 if (ia) {
299 /* I'm gonna hafta eat this packet */
300 agedelta += NS_MAXHOPS - idp->idp_tc;
301 idp->idp_tc = NS_MAXHOPS;
302 }
303 if ((ok_back = idp_do_route(&idp->idp_sna,&idp_sroute))==0) {
304 /* error = ENETUNREACH; He'll never get it! */
305 m_freem(dtom(idp));
306 goto cleanup;
307 }
308 if (idp_droute.ro_rt &&
309 (ifp=idp_droute.ro_rt->rt_ifp) &&
310 idp_sroute.ro_rt &&
311 (ifp!=idp_sroute.ro_rt->rt_ifp)) {
312 flags |= NS_ALLOWBROADCAST;
313 } else {
314 type = NS_ERR_UNREACH_HOST, code = 0;
315 goto senderror;
316 }
317 }
bbcda6f4
KS
318 /* need to adjust checksum */
319 if (idp->idp_sum!=0xffff) {
320 union bytes {
321 u_char c[4];
322 u_short s[2];
323 long l;
324 } x;
325 register int shift;
c7ea7bd3 326 x.l = 0; x.c[0] = agedelta;
bbcda6f4
KS
327 shift = (((((int)ntohs(idp->idp_len))+1)>>1)-2) & 0xf;
328 x.l = idp->idp_sum + (x.l << shift);
329 x.l = x.s[0] + x.s[1];
330 x.l = x.s[0] + x.s[1];
331 if (x.l==0xffff) idp->idp_sum = 0; else idp->idp_sum = x.l;
332 }
c7ea7bd3
KS
333 if ((error = ns_output(dtom(idp), &idp_droute, flags)) &&
334 (mcopy!=NULL)) {
335 idp = mtod(mcopy, struct idp *);
336 type = NS_ERR_UNSPEC_T, code = 0;
337 switch (error) {
338
339 case ENETUNREACH:
340 case EHOSTDOWN:
341 case EHOSTUNREACH:
342 case ENETDOWN:
343 case EPERM:
344 type = NS_ERR_UNREACH_HOST;
345 break;
bbcda6f4 346
c7ea7bd3
KS
347 case EMSGSIZE:
348 type = NS_ERR_TOO_BIG;
349 code = 576; /* too hard to figure out mtu here */
350 break;
bbcda6f4 351
c7ea7bd3
KS
352 case ENOBUFS:
353 type = NS_ERR_UNSPEC_T;
354 break;
bbcda6f4 355 }
bbcda6f4
KS
356 }
357senderror:
358 ns_error(dtom(idp), type, code);
c7ea7bd3
KS
359 mcopy = NULL;
360cleanup:
361 if (ok_there)
362 idp_undo_route(&idp_droute);
363 if (ok_back)
364 idp_undo_route(&idp_sroute);
365 if (mcopy != NULL)
366 m_freem(mcopy);
bbcda6f4
KS
367}
368
369idp_do_route(src, ro)
370struct ns_addr *src;
371struct route *ro;
372{
373
374 struct sockaddr_ns *dst;
375
376 bzero((caddr_t)ro, sizeof (*ro));
377 dst = (struct sockaddr_ns *)&ro->ro_dst;
378
379 dst->sns_family = AF_NS;
380 dst->sns_addr = *src;
381 rtalloc(ro);
382 if (ro->ro_rt == 0 || ro->ro_rt->rt_ifp == 0) {
383 return(0);
384 }
385 ro->ro_rt->rt_use++;
386 return(1);
387}
388
389idp_undo_route(ro)
390register struct route *ro;
391{
392 if (ro->ro_rt) {RTFREE(ro->ro_rt);}
393}
394ns_watch_output(m)
395struct mbuf *m;
396{
397 register struct nspcb *nsp;
398 /*
399 * Give any raw listeners a crack at the packet
400 */
401 for (nsp = nsrawpcb.nsp_next; nsp != &nsrawpcb; nsp = nsp->nsp_next) {
402 struct mbuf *m1 = m_copy(m, 0, M_COPYALL);
403 if (m1) idp_input(m1, nsp);
404 }
405}