Correct BSD License clause numbering from 1-2-4 to 1-2-3.
[dragonfly.git] / sys / netproto / ipx / ipx_outputfl.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. Neither the name of the University nor the names of its contributors
15  *    may be used to endorse or promote products derived from this software
16  *    without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  *
30  *      @(#)ipx_outputfl.c
31  *
32  * $FreeBSD: src/sys/netipx/ipx_outputfl.c,v 1.14.2.1 2000/05/01 01:10:24 bp Exp $
33  * $DragonFly: src/sys/netproto/ipx/ipx_outputfl.c,v 1.9 2008/05/14 11:59:24 sephe Exp $
34  */
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/mbuf.h>
39 #include <sys/socket.h>
40
41 #include <net/if.h>
42 #include <net/route.h>
43
44 #include "ipx.h"
45 #include "ipx_if.h"
46 #include "ipx_var.h"
47
48 static int ipx_copy_output = 0;
49
50 int
51 ipx_outputfl(struct mbuf *m0, struct route *ro, int flags)
52 {
53         struct ipx *ipx = mtod(m0, struct ipx *);
54         struct ifnet *ifp = NULL;
55         int error = 0;
56         struct sockaddr_ipx *dst;
57         struct route ipxroute;
58
59         /*
60          * Route packet.
61          */
62         if (ro == NULL) {
63                 ro = &ipxroute;
64                 bzero((caddr_t)ro, sizeof(*ro));
65         }
66         dst = (struct sockaddr_ipx *)&ro->ro_dst;
67         if (ro->ro_rt == NULL) {
68                 dst->sipx_family = AF_IPX;
69                 dst->sipx_len = sizeof(*dst);
70                 dst->sipx_addr = ipx->ipx_dna;
71                 dst->sipx_addr.x_port = 0;
72                 /*
73                  * If routing to interface only,
74                  * short circuit routing lookup.
75                  */
76                 if (flags & IPX_ROUTETOIF) {
77                         struct ipx_ifaddr *ia = ipx_iaonnetof(&ipx->ipx_dna);
78
79                         if (ia == NULL) {
80                                 ipxstat.ipxs_noroute++;
81                                 error = ENETUNREACH;
82                                 goto bad;
83                         }
84                         ifp = ia->ia_ifp;
85                         goto gotif;
86                 }
87                 rtalloc(ro);
88         } else if ((ro->ro_rt->rt_flags & RTF_UP) == 0) {
89                 /*
90                  * The old route has gone away; try for a new one.
91                  */
92                 rtfree(ro->ro_rt);
93                 ro->ro_rt = NULL;
94                 rtalloc(ro);
95         }
96         if (ro->ro_rt == NULL || (ifp = ro->ro_rt->rt_ifp) == NULL) {
97                 ipxstat.ipxs_noroute++;
98                 error = ENETUNREACH;
99                 goto bad;
100         }
101         ro->ro_rt->rt_use++;
102         if (ro->ro_rt->rt_flags & (RTF_GATEWAY|RTF_HOST))
103                 dst = (struct sockaddr_ipx *)ro->ro_rt->rt_gateway;
104 gotif:
105         /*
106          * Look for multicast addresses and
107          * and verify user is allowed to send
108          * such a packet.
109          */
110         if (dst->sipx_addr.x_host.c_host[0]&1) {
111                 if ((ifp->if_flags & (IFF_BROADCAST | IFF_LOOPBACK)) == 0) {
112                         error = EADDRNOTAVAIL;
113                         goto bad;
114                 }
115                 if ((flags & IPX_ALLOWBROADCAST) == 0) {
116                         error = EACCES;
117                         goto bad;
118                 }
119                 m0->m_flags |= M_BCAST;
120         }
121
122         if (htons(ipx->ipx_len) <= ifp->if_mtu) {
123                 ipxstat.ipxs_localout++;
124                 if (ipx_copy_output) {
125                         ipx_watch_output(m0, ifp);
126                 }
127                 error = ifp->if_output(ifp, m0, (struct sockaddr *)dst,
128                                        ro->ro_rt);
129                 goto done;
130         } else {
131                 ipxstat.ipxs_mtutoosmall++;
132                 error = EMSGSIZE;
133         }
134 bad:
135         if (ipx_copy_output) {
136                 ipx_watch_output(m0, ifp);
137         }
138         m_freem(m0);
139 done:
140         if (ro == &ipxroute && (flags & IPX_ROUTETOIF) == 0 &&
141             ro->ro_rt != NULL) {
142                 RTFREE(ro->ro_rt);
143                 ro->ro_rt = NULL;
144         }
145         return (error);
146 }
147
148 /*
149  * This will broadcast the type 20 (Netbios) packet to all the interfaces
150  * that have ipx configured and isn't in the list yet.
151  */
152 int
153 ipx_output_type20(struct mbuf *m)
154 {
155         struct ipx *ipx;
156         union ipx_net *nbnet;
157         struct ipx_ifaddr *ia, *tia = NULL;
158         int error = 0;
159         struct mbuf *m1;
160         int i;
161         struct ifnet *ifp;
162         struct sockaddr_ipx dst;
163
164         /*
165          * We have to get to the 32 bytes after the ipx header also, so
166          * that we can fill in the network address of the receiving
167          * interface.
168          */
169         if ((m->m_flags & M_EXT || m->m_len < (sizeof(struct ipx) + 32)) &&
170             (m = m_pullup(m, sizeof(struct ipx) + 32)) == NULL) {
171                 ipxstat.ipxs_toosmall++;
172                 return (0);
173         }
174         ipx = mtod(m, struct ipx *);
175         nbnet = (union ipx_net *)(ipx + 1);
176
177         if (ipx->ipx_tc >= 8)
178                 goto bad;
179         /*
180          * Now see if we have already seen this.
181          */
182         for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next)
183                 if(ia->ia_ifa.ifa_ifp == m->m_pkthdr.rcvif) {
184                         if(tia == NULL)
185                                 tia = ia;
186
187                         for (i=0;i<ipx->ipx_tc;i++,nbnet++)
188                                 if(ipx_neteqnn(ia->ia_addr.sipx_addr.x_net,
189                                                         *nbnet))
190                                         goto bad;
191                 }
192         /*
193          * Don't route the packet if the interface where it come from
194          * does not have an IPX address.
195          */
196         if(tia == NULL)
197                 goto bad;
198
199         /*
200          * Add our receiving interface to the list.
201          */
202         nbnet = (union ipx_net *)(ipx + 1);
203         nbnet += ipx->ipx_tc;
204         *nbnet = tia->ia_addr.sipx_addr.x_net;
205
206         /*
207          * Increment the hop count.
208          */
209         ipx->ipx_tc++;
210         ipxstat.ipxs_forward++;
211
212         /*
213          * Send to all directly connected ifaces not in list and
214          * not to the one it came from.
215          */
216         m->m_flags &= ~M_BCAST;
217         bzero(&dst, sizeof(dst));
218         dst.sipx_family = AF_IPX;
219         dst.sipx_len = 12;
220         dst.sipx_addr.x_host = ipx_broadhost;
221
222         for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next)
223                 if(ia->ia_ifa.ifa_ifp != m->m_pkthdr.rcvif) {
224                         nbnet = (union ipx_net *)(ipx + 1);
225                         for (i=0;i<ipx->ipx_tc;i++,nbnet++)
226                                 if(ipx_neteqnn(ia->ia_addr.sipx_addr.x_net,
227                                                         *nbnet))
228                                         goto skip_this;
229
230                         /*
231                          * Insert the net address of the dest net and
232                          * calculate the new checksum if needed.
233                          */
234                         ifp = ia->ia_ifa.ifa_ifp;
235                         dst.sipx_addr.x_net = ia->ia_addr.sipx_addr.x_net;
236                         ipx->ipx_dna.x_net = dst.sipx_addr.x_net;
237                         if(ipx->ipx_sum != 0xffff)
238                                 ipx->ipx_sum = ipx_cksum(m, ntohs(ipx->ipx_len));
239
240                         m1 = m_copym(m, 0, M_COPYALL, MB_DONTWAIT);
241                         if(m1) {
242                                 error = ifp->if_output(ifp, m1,
243                                         (struct sockaddr *)&dst, NULL);
244                                 /* XXX ipxstat.ipxs_localout++; */
245                         }
246 skip_this: ;
247                 }
248
249 bad:
250         m_freem(m);
251         return (error);
252 }