Remove unused static variable
[dragonfly.git] / sys / netproto / ipx / ipx_input.c
1 /*
2  * Copyright (c) 1995, Mike Mitchell
3  * Copyright (c) 1984, 1985, 1986, 1987, 1993
4  *      The Regents of the University of California.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *      This product includes software developed by the University of
17  *      California, Berkeley and its contributors.
18  * 4. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  *      @(#)ipx_input.c
35  *
36  * $FreeBSD: src/sys/netipx/ipx_input.c,v 1.22.2.2 2001/02/22 09:44:18 bp Exp $
37  * $DragonFly: src/sys/netproto/ipx/ipx_input.c,v 1.7 2004/02/24 19:17:08 joerg Exp $
38  */
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/mbuf.h>
43 #include <sys/protosw.h>
44 #include <sys/socket.h>
45 #include <sys/kernel.h>
46 #include <sys/random.h>
47 #include <sys/sysctl.h>
48
49 #include <net/if.h>
50 #include <net/route.h>
51 #include <net/netisr.h>
52 #include <net/intrq.h>
53
54 #include "ipx.h"
55 #include "spx.h"
56 #include "ipx_if.h"
57 #include "ipx_pcb.h"
58 #include "ipx_var.h"
59
60 int     ipxcksum = 0;
61 SYSCTL_INT(_net_ipx_ipx, OID_AUTO, checksum, CTLFLAG_RW,
62            &ipxcksum, 0, "");
63
64 static int      ipxprintfs = 0;         /* printing forwarding information */
65 SYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxprintfs, CTLFLAG_RW,
66            &ipxprintfs, 0, "");
67
68 static int      ipxforwarding = 0;
69 SYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxforwarding, CTLFLAG_RW,
70             &ipxforwarding, 0, "");
71
72 static int      ipxnetbios = 0;
73 SYSCTL_INT(_net_ipx, OID_AUTO, ipxnetbios, CTLFLAG_RW,
74            &ipxnetbios, 0, "");
75
76 union   ipx_net ipx_zeronet;
77 union   ipx_host ipx_zerohost;
78
79 union   ipx_net ipx_broadnet;
80 union   ipx_host ipx_broadhost;
81
82 struct  ipxstat ipxstat;
83 struct  sockaddr_ipx ipx_netmask, ipx_hostmask;
84
85 static  u_short allones[] = {-1, -1, -1};
86
87 struct  ipxpcb ipxpcb;
88 struct  ipxpcb ipxrawpcb;
89
90 long    ipx_pexseq;
91
92 static  void ipxintr(struct mbuf *);
93 static  int ipx_do_route(struct ipx_addr *src, struct route *ro);
94 static  void ipx_undo_route(struct route *ro);
95 static  void ipx_forward(struct mbuf *m);
96
97 /*
98  * IPX initialization.
99  */
100
101 void
102 ipx_init()
103 {
104         ipx_broadnet = *(union ipx_net *)allones;
105         ipx_broadhost = *(union ipx_host *)allones;
106
107         read_random(&ipx_pexseq, sizeof ipx_pexseq);
108         ipxpcb.ipxp_next = ipxpcb.ipxp_prev = &ipxpcb;
109         ipxrawpcb.ipxp_next = ipxrawpcb.ipxp_prev = &ipxrawpcb;
110
111         ipx_netmask.sipx_len = 6;
112         ipx_netmask.sipx_addr.x_net = ipx_broadnet;
113
114         ipx_hostmask.sipx_len = 12;
115         ipx_hostmask.sipx_addr.x_net = ipx_broadnet;
116         ipx_hostmask.sipx_addr.x_host = ipx_broadhost;
117
118         netisr_register(NETISR_IPX, cpu0_portfn, ipxintr);
119 }
120
121 /*
122  * IPX input routine.  Pass to next level.
123  */
124 static void
125 ipxintr(struct mbuf *m)
126 {
127         struct ipx *ipx;
128         struct ipxpcb *ipxp;
129         struct ipx_ifaddr *ia;
130         int len;
131
132         /*
133          * If no IPX addresses have been set yet but the interfaces
134          * are receiving, can't do anything with incoming packets yet.
135          */
136         if (ipx_ifaddr == NULL)
137                 goto bad;
138
139         ipxstat.ipxs_total++;
140
141         if ((m->m_flags & M_EXT || m->m_len < sizeof(struct ipx)) &&
142             (m = m_pullup(m, sizeof(struct ipx))) == 0) {
143                 ipxstat.ipxs_toosmall++;
144                 return;
145         }
146
147         /*
148          * Give any raw listeners a crack at the packet
149          */
150         for (ipxp = ipxrawpcb.ipxp_next; ipxp != &ipxrawpcb;
151              ipxp = ipxp->ipxp_next) {
152                 struct mbuf *m1 = m_copy(m, 0, (int)M_COPYALL);
153                 if (m1 != NULL)
154                         ipx_input(m1, ipxp);
155         }
156
157         ipx = mtod(m, struct ipx *);
158         len = ntohs(ipx->ipx_len);
159         /*
160          * Check that the amount of data in the buffers
161          * is as at least much as the IPX header would have us expect.
162          * Trim mbufs if longer than we expect.
163          * Drop packet if shorter than we expect.
164          */
165         if (m->m_pkthdr.len < len) {
166                 ipxstat.ipxs_tooshort++;
167                 goto bad;
168         }
169         if (m->m_pkthdr.len > len) {
170                 if (m->m_len == m->m_pkthdr.len) {
171                         m->m_len = len;
172                         m->m_pkthdr.len = len;
173                 } else
174                         m_adj(m, len - m->m_pkthdr.len);
175         }
176         if (ipxcksum && ipx->ipx_sum != 0xffff) {
177                 if (ipx->ipx_sum != ipx_cksum(m, len)) {
178                         ipxstat.ipxs_badsum++;
179                         goto bad;
180                 }
181         }
182
183         /*
184          * Propagated (Netbios) packets (type 20) has to be handled
185          * different. :-(
186          */
187         if (ipx->ipx_pt == IPXPROTO_NETBIOS) {
188                 if (ipxnetbios) {
189                         ipx_output_type20(m);
190                         return;
191                 } else
192                         goto bad;
193         }
194
195         /*
196          * Is this a directed broadcast?
197          */
198         if (ipx_hosteqnh(ipx_broadhost,ipx->ipx_dna.x_host)) {
199                 if ((!ipx_neteq(ipx->ipx_dna, ipx->ipx_sna)) &&
200                     (!ipx_neteqnn(ipx->ipx_dna.x_net, ipx_broadnet)) &&
201                     (!ipx_neteqnn(ipx->ipx_sna.x_net, ipx_zeronet)) &&
202                     (!ipx_neteqnn(ipx->ipx_dna.x_net, ipx_zeronet)) ) {
203                         /*
204                          * If it is a broadcast to the net where it was
205                          * received from, treat it as ours.
206                          */
207                         for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next)
208                                 if((ia->ia_ifa.ifa_ifp == m->m_pkthdr.rcvif) &&
209                                    ipx_neteq(ia->ia_addr.sipx_addr, 
210                                              ipx->ipx_dna))
211                                         goto ours;
212
213                         /*
214                          * Look to see if I need to eat this packet.
215                          * Algorithm is to forward all young packets
216                          * and prematurely age any packets which will
217                          * by physically broadcasted.
218                          * Any very old packets eaten without forwarding
219                          * would die anyway.
220                          *
221                          * Suggestion of Bill Nesheim, Cornell U.
222                          */
223                         if (ipx->ipx_tc < IPX_MAXHOPS) {
224                                 ipx_forward(m);
225                                 return;
226                         }
227                 }
228         /*
229          * Is this our packet? If not, forward.
230          */
231         } else {
232                 for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next)
233                         if (ipx_hosteq(ipx->ipx_dna, ia->ia_addr.sipx_addr) &&
234                             (ipx_neteq(ipx->ipx_dna, ia->ia_addr.sipx_addr) ||
235                              ipx_neteqnn(ipx->ipx_dna.x_net, ipx_zeronet)))
236                                 break;
237
238                 if (ia == NULL) {
239                         ipx_forward(m);
240                         return;
241                 }
242         }
243 ours:
244         /*
245          * Locate pcb for datagram.
246          */
247         ipxp = ipx_pcblookup(&ipx->ipx_sna, ipx->ipx_dna.x_port, IPX_WILDCARD);
248         /*
249          * Switch out to protocol's input routine.
250          */
251         if (ipxp != NULL) {
252                 ipxstat.ipxs_delivered++;
253                 if ((ipxp->ipxp_flags & IPXP_ALL_PACKETS) == 0)
254                         switch (ipx->ipx_pt) {
255                         case IPXPROTO_SPX:
256                                 spx_input(m, ipxp);
257                                 return;
258                         }
259                 ipx_input(m, ipxp);
260         } else
261                 goto bad;
262
263         return;
264
265 bad:
266         m_freem(m);
267 }
268
269 void
270 ipx_ctlinput(cmd, arg_as_sa, dummy)
271         int cmd;
272         struct sockaddr *arg_as_sa;     /* XXX should be swapped with dummy */
273         void *dummy;
274 {
275         caddr_t arg = (/* XXX */ caddr_t)arg_as_sa;
276         struct ipx_addr *ipx;
277
278         if (cmd < 0 || cmd > PRC_NCMDS)
279                 return;
280         switch (cmd) {
281                 struct sockaddr_ipx *sipx;
282
283         case PRC_IFDOWN:
284         case PRC_HOSTDEAD:
285         case PRC_HOSTUNREACH:
286                 sipx = (struct sockaddr_ipx *)arg;
287                 if (sipx->sipx_family != AF_IPX)
288                         return;
289                 ipx = &sipx->sipx_addr;
290                 break;
291
292         default:
293                 if (ipxprintfs)
294                         printf("ipx_ctlinput: cmd %d.\n", cmd);
295                 break;
296         }
297 }
298
299 /*
300  * Forward a packet. If some error occurs drop the packet. IPX don't
301  * have a way to return errors to the sender.
302  */
303
304 static struct route ipx_droute;
305 static struct route ipx_sroute;
306
307 static void
308 ipx_forward(m)
309 struct mbuf *m;
310 {
311         struct ipx *ipx = mtod(m, struct ipx *);
312         int error;
313         struct mbuf *mcopy = NULL;
314         int agedelta = 1;
315         int flags = IPX_FORWARDING;
316         int ok_there = 0;
317         int ok_back = 0;
318
319         if (ipxforwarding == 0) {
320                 /* can't tell difference between net and host */
321                 ipxstat.ipxs_cantforward++;
322                 m_freem(m);
323                 goto cleanup;
324         }
325         ipx->ipx_tc++;
326         if (ipx->ipx_tc > IPX_MAXHOPS) {
327                 ipxstat.ipxs_cantforward++;
328                 m_freem(m);
329                 goto cleanup;
330         }
331
332         if ((ok_there = ipx_do_route(&ipx->ipx_dna,&ipx_droute)) == 0) {
333                 ipxstat.ipxs_noroute++;
334                 m_freem(m);
335                 goto cleanup;
336         }
337         /*
338          * Here we think about  forwarding  broadcast packets,
339          * so we try to insure that it doesn't go back out
340          * on the interface it came in on.  Also, if we
341          * are going to physically broadcast this, let us
342          * age the packet so we can eat it safely the second time around.
343          */
344         if (ipx->ipx_dna.x_host.c_host[0] & 0x1) {
345                 struct ipx_ifaddr *ia = ipx_iaonnetof(&ipx->ipx_dna);
346                 struct ifnet *ifp;
347                 if (ia != NULL) {
348                         /* I'm gonna hafta eat this packet */
349                         agedelta += IPX_MAXHOPS - ipx->ipx_tc;
350                         ipx->ipx_tc = IPX_MAXHOPS;
351                 }
352                 if ((ok_back = ipx_do_route(&ipx->ipx_sna,&ipx_sroute)) == 0) {
353                         /* error = ENETUNREACH; He'll never get it! */
354                         ipxstat.ipxs_noroute++;
355                         m_freem(m);
356                         goto cleanup;
357                 }
358                 if (ipx_droute.ro_rt &&
359                     (ifp = ipx_droute.ro_rt->rt_ifp) &&
360                     ipx_sroute.ro_rt &&
361                     (ifp != ipx_sroute.ro_rt->rt_ifp)) {
362                         flags |= IPX_ALLOWBROADCAST;
363                 } else {
364                         ipxstat.ipxs_noroute++;
365                         m_freem(m);
366                         goto cleanup;
367                 }
368         }
369         /*
370          * We don't need to recompute checksum because ipx_tc field
371          * is ignored by checksum calculation routine, however
372          * it may be desirable to reset checksum if ipxcksum == 0
373          */
374 #if 0
375         if (!ipxcksum)
376                 ipx->ipx_sum = 0xffff;
377 #endif
378
379         error = ipx_outputfl(m, &ipx_droute, flags);
380         if (error == 0) {
381                 ipxstat.ipxs_forward++;
382
383                 if (ipxprintfs) {
384                         printf("forward: ");
385                         ipx_printhost(&ipx->ipx_sna);
386                         printf(" to ");
387                         ipx_printhost(&ipx->ipx_dna);
388                         printf(" hops %d\n", ipx->ipx_tc);
389                 }
390         } else if (mcopy != NULL) {
391                 ipx = mtod(mcopy, struct ipx *);
392                 switch (error) {
393
394                 case ENETUNREACH:
395                 case EHOSTDOWN:
396                 case EHOSTUNREACH:
397                 case ENETDOWN:
398                 case EPERM:
399                         ipxstat.ipxs_noroute++;
400                         break;
401
402                 case EMSGSIZE:
403                         ipxstat.ipxs_mtutoosmall++;
404                         break;
405
406                 case ENOBUFS:
407                         ipxstat.ipxs_odropped++;
408                         break;
409                 }
410                 mcopy = NULL;
411                 m_freem(m);
412         }
413 cleanup:
414         if (ok_there)
415                 ipx_undo_route(&ipx_droute);
416         if (ok_back)
417                 ipx_undo_route(&ipx_sroute);
418         if (mcopy != NULL)
419                 m_freem(mcopy);
420 }
421
422 static int
423 ipx_do_route(src, ro)
424 struct ipx_addr *src;
425 struct route *ro;
426 {
427         struct sockaddr_ipx *dst;
428
429         bzero((caddr_t)ro, sizeof(*ro));
430         dst = (struct sockaddr_ipx *)&ro->ro_dst;
431
432         dst->sipx_len = sizeof(*dst);
433         dst->sipx_family = AF_IPX;
434         dst->sipx_addr = *src;
435         dst->sipx_addr.x_port = 0;
436         rtalloc(ro);
437         if (ro->ro_rt == NULL || ro->ro_rt->rt_ifp == NULL) {
438                 return (0);
439         }
440         ro->ro_rt->rt_use++;
441         return (1);
442 }
443
444 static void
445 ipx_undo_route(ro)
446 struct route *ro;
447 {
448         if (ro->ro_rt != NULL) {
449                 RTFREE(ro->ro_rt);
450         }
451 }
452
453 void
454 ipx_watch_output(m, ifp)
455 struct mbuf *m;
456 struct ifnet *ifp;
457 {
458         struct ipxpcb *ipxp;
459         struct ifaddr *ifa;
460         struct ipx_ifaddr *ia;
461         /*
462          * Give any raw listeners a crack at the packet
463          */
464         for (ipxp = ipxrawpcb.ipxp_next; ipxp != &ipxrawpcb;
465              ipxp = ipxp->ipxp_next) {
466                 struct mbuf *m0 = m_copy(m, 0, (int)M_COPYALL);
467                 if (m0 != NULL) {
468                         struct ipx *ipx;
469
470                         M_PREPEND(m0, sizeof(*ipx), M_DONTWAIT);
471                         if (m0 == NULL)
472                                 continue;
473                         ipx = mtod(m0, struct ipx *);
474                         ipx->ipx_sna.x_net = ipx_zeronet;
475                         for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next)
476                                 if (ifp == ia->ia_ifp)
477                                         break;
478                         if (ia == NULL)
479                                 ipx->ipx_sna.x_host = ipx_zerohost;  
480                         else 
481                                 ipx->ipx_sna.x_host =
482                                     ia->ia_addr.sipx_addr.x_host;
483
484                         if (ifp != NULL && (ifp->if_flags & IFF_POINTOPOINT))
485                             TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
486                                 if (ifa->ifa_addr->sa_family == AF_IPX) {
487                                     ipx->ipx_sna = IA_SIPX(ifa)->sipx_addr;
488                                     break;
489                                 }
490                             }
491                         ipx->ipx_len = ntohl(m0->m_pkthdr.len);
492                         ipx_input(m0, ipxp);
493                 }
494         }
495 }