]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netipx/ipx.c
add -n option to suppress clearing the build tree and add -DNO_CLEAN
[FreeBSD/FreeBSD.git] / sys / netipx / ipx.c
1 /*-
2  * Copyright (c) 1984, 1985, 1986, 1987, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 4. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * Copyright (c) 1995, Mike Mitchell
30  *
31  * Redistribution and use in source and binary forms, with or without
32  * modification, are permitted provided that the following conditions
33  * are met:
34  * 1. Redistributions of source code must retain the above copyright
35  *    notice, this list of conditions and the following disclaimer.
36  * 2. Redistributions in binary form must reproduce the above copyright
37  *    notice, this list of conditions and the following disclaimer in the
38  *    documentation and/or other materials provided with the distribution.
39  * 3. All advertising materials mentioning features or use of this software
40  *    must display the following acknowledgement:
41  *      This product includes software developed by the University of
42  *      California, Berkeley and its contributors.
43  * 4. Neither the name of the University nor the names of its contributors
44  *    may be used to endorse or promote products derived from this software
45  *    without specific prior written permission.
46  *
47  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
48  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
51  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57  * SUCH DAMAGE.
58  *
59  *      @(#)ipx.c
60  */
61
62 #include <sys/cdefs.h>
63 __FBSDID("$FreeBSD$");
64
65 #include <sys/param.h>
66 #include <sys/kernel.h>
67 #include <sys/systm.h>
68 #include <sys/malloc.h>
69 #include <sys/priv.h>
70 #include <sys/sockio.h>
71 #include <sys/socket.h>
72
73 #include <net/if.h>
74 #include <net/route.h>
75
76 #include <netipx/ipx.h>
77 #include <netipx/ipx_if.h>
78 #include <netipx/ipx_var.h>
79
80 /*
81  * XXXRW: Requires synchronization.
82  */
83 struct ipx_ifaddr *ipx_ifaddr;
84
85 static  void ipx_ifscrub(struct ifnet *ifp, struct ipx_ifaddr *ia);
86 static  int ipx_ifinit(struct ifnet *ifp, struct ipx_ifaddr *ia,
87                        struct sockaddr_ipx *sipx, int scrub);
88
89 /*
90  * Generic internet control operations (ioctl's).
91  */
92 int
93 ipx_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp,
94     struct thread *td)
95 {
96         struct ifreq *ifr = (struct ifreq *)data;
97         struct ipx_aliasreq *ifra = (struct ipx_aliasreq *)data;
98         struct ipx_ifaddr *ia;
99         struct ifaddr *ifa;
100         struct ipx_ifaddr *oia;
101         int dstIsNew, hostIsNew;
102         int error = 0, priv;
103
104         /*
105          * Find address for this interface, if it exists.
106          */
107         if (ifp == NULL)
108                 return (EADDRNOTAVAIL);
109         for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next)
110                 if (ia->ia_ifp == ifp)
111                         break;
112
113         switch (cmd) {
114
115         case SIOCGIFADDR:
116                 if (ia == NULL)
117                         return (EADDRNOTAVAIL);
118                 *(struct sockaddr_ipx *)&ifr->ifr_addr = ia->ia_addr;
119                 return (0);
120
121         case SIOCGIFBRDADDR:
122                 if (ia == NULL)
123                         return (EADDRNOTAVAIL);
124                 if ((ifp->if_flags & IFF_BROADCAST) == 0)
125                         return (EINVAL);
126                 *(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_broadaddr;
127                 return (0);
128
129         case SIOCGIFDSTADDR:
130                 if (ia == NULL)
131                         return (EADDRNOTAVAIL);
132                 if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
133                         return (EINVAL);
134                 *(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_dstaddr;
135                 return (0);
136         }
137
138         switch (cmd) {
139         case SIOCAIFADDR:
140         case SIOCDIFADDR:
141                 priv = (cmd == SIOCAIFADDR) ? PRIV_NET_ADDIFADDR :
142                     PRIV_NET_DELIFADDR;
143                 if (td && (error = priv_check(td, priv)) != 0)
144                         return (error);
145                 if (ifra->ifra_addr.sipx_family == AF_IPX)
146                     for (oia = ia; ia != NULL; ia = ia->ia_next) {
147                         if (ia->ia_ifp == ifp  &&
148                             ipx_neteq(ia->ia_addr.sipx_addr,
149                                   ifra->ifra_addr.sipx_addr))
150                             break;
151                     }
152                 if (cmd == SIOCDIFADDR && ia == NULL)
153                         return (EADDRNOTAVAIL);
154                 /* FALLTHROUGH */
155
156         case SIOCSIFADDR:
157         case SIOCSIFDSTADDR:
158                 if (td && (error = priv_check(td, PRIV_NET_SETLLADDR)) != 0)
159                         return (error);
160                 if (ia == NULL) {
161                         oia = (struct ipx_ifaddr *)
162                                 malloc(sizeof(*ia), M_IFADDR,
163                                 M_WAITOK | M_ZERO);
164                         if (oia == NULL)
165                                 return (ENOBUFS);
166                         if ((ia = ipx_ifaddr) != NULL) {
167                                 for ( ; ia->ia_next != NULL; ia = ia->ia_next)
168                                         ;
169                                 ia->ia_next = oia;
170                         } else
171                                 ipx_ifaddr = oia;
172                         ia = oia;
173                         ifa = (struct ifaddr *)ia;
174                         IFA_LOCK_INIT(ifa);
175                         ifa->ifa_refcnt = 1;
176                         TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link);
177                         ia->ia_ifp = ifp;
178                         ifa->ifa_addr = (struct sockaddr *)&ia->ia_addr;
179
180                         ifa->ifa_netmask = (struct sockaddr *)&ipx_netmask;
181
182                         ifa->ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
183                         if (ifp->if_flags & IFF_BROADCAST) {
184                                 ia->ia_broadaddr.sipx_family = AF_IPX;
185                                 ia->ia_broadaddr.sipx_len = sizeof(ia->ia_addr);
186                                 ia->ia_broadaddr.sipx_addr.x_host = ipx_broadhost;
187                         }
188                 }
189                 break;
190         default:
191                 if (td && (error = priv_check(td, PRIV_NET_HWIOCTL)) != 0)
192                         return (error);
193         }
194
195         switch (cmd) {
196
197         case SIOCSIFDSTADDR:
198                 if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
199                         return (EINVAL);
200                 if (ia->ia_flags & IFA_ROUTE) {
201                         rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
202                         ia->ia_flags &= ~IFA_ROUTE;
203                 }
204                 if (ifp->if_ioctl) {
205                         error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, (void *)ia);
206                         if (error)
207                                 return (error);
208                 }
209                 *(struct sockaddr *)&ia->ia_dstaddr = ifr->ifr_dstaddr;
210                 return (0);
211
212         case SIOCSIFADDR:
213                 return (ipx_ifinit(ifp, ia,
214                                 (struct sockaddr_ipx *)&ifr->ifr_addr, 1));
215
216         case SIOCDIFADDR:
217                 ipx_ifscrub(ifp, ia);
218                 ifa = (struct ifaddr *)ia;
219                 TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link);
220                 oia = ia;
221                 if (oia == (ia = ipx_ifaddr)) {
222                         ipx_ifaddr = ia->ia_next;
223                 } else {
224                         while (ia->ia_next && (ia->ia_next != oia)) {
225                                 ia = ia->ia_next;
226                         }
227                         if (ia->ia_next)
228                             ia->ia_next = oia->ia_next;
229                         else
230                                 printf("Didn't unlink ipxifadr from list\n");
231                 }
232                 IFAFREE((&oia->ia_ifa));
233                 return (0);
234
235         case SIOCAIFADDR:
236                 dstIsNew = 0;
237                 hostIsNew = 1;
238                 if (ia->ia_addr.sipx_family == AF_IPX) {
239                         if (ifra->ifra_addr.sipx_len == 0) {
240                                 ifra->ifra_addr = ia->ia_addr;
241                                 hostIsNew = 0;
242                         } else if (ipx_neteq(ifra->ifra_addr.sipx_addr,
243                                          ia->ia_addr.sipx_addr))
244                                 hostIsNew = 0;
245                 }
246                 if ((ifp->if_flags & IFF_POINTOPOINT) &&
247                     (ifra->ifra_dstaddr.sipx_family == AF_IPX)) {
248                         if (hostIsNew == 0)
249                                 ipx_ifscrub(ifp, ia);
250                         ia->ia_dstaddr = ifra->ifra_dstaddr;
251                         dstIsNew  = 1;
252                 }
253                 if (ifra->ifra_addr.sipx_family == AF_IPX &&
254                                             (hostIsNew || dstIsNew))
255                         error = ipx_ifinit(ifp, ia, &ifra->ifra_addr, 0);
256                 return (error);
257
258         default:
259                 if (ifp->if_ioctl == NULL)
260                         return (EOPNOTSUPP);
261                 return ((*ifp->if_ioctl)(ifp, cmd, data));
262         }
263 }
264
265 /*
266 * Delete any previous route for an old address.
267 */
268 static void
269 ipx_ifscrub(struct ifnet *ifp, struct ipx_ifaddr *ia)
270 {
271
272         if (ia->ia_flags & IFA_ROUTE) {
273                 if (ifp->if_flags & IFF_POINTOPOINT) {
274                         rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
275                 } else
276                         rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0);
277                 ia->ia_flags &= ~IFA_ROUTE;
278         }
279 }
280 /*
281  * Initialize an interface's internet address
282  * and routing table entry.
283  */
284 static int
285 ipx_ifinit(struct ifnet *ifp, struct ipx_ifaddr *ia,
286     struct sockaddr_ipx *sipx, int scrub)
287 {
288         struct sockaddr_ipx oldaddr;
289         int s = splimp(), error;
290
291         /*
292          * Set up new addresses.
293          */
294         oldaddr = ia->ia_addr;
295         ia->ia_addr = *sipx;
296
297         /*
298          * The convention we shall adopt for naming is that
299          * a supplied address of zero means that "we don't care".
300          * Use the MAC address of the interface. If it is an
301          * interface without a MAC address, like a serial line, the
302          * address must be supplied.
303          *
304          * Give the interface a chance to initialize
305          * if this is its first address,
306          * and to validate the address if necessary.
307          */
308         if (ifp->if_ioctl != NULL &&
309             (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (void *)ia))) {
310                 ia->ia_addr = oldaddr;
311                 splx(s);
312                 return (error);
313         }
314         splx(s);
315         ia->ia_ifa.ifa_metric = ifp->if_metric;
316         /*
317          * Add route for the network.
318          */
319         if (scrub) {
320                 ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr;
321                 ipx_ifscrub(ifp, ia);
322                 ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
323         }
324         if (ifp->if_flags & IFF_POINTOPOINT)
325                 rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
326         else {
327                 ia->ia_broadaddr.sipx_addr.x_net = ia->ia_addr.sipx_addr.x_net;
328                 rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_UP);
329         }
330         ia->ia_flags |= IFA_ROUTE;
331         return (0);
332 }
333
334 /*
335  * Return address info for specified internet network.
336  */
337 struct ipx_ifaddr *
338 ipx_iaonnetof(struct ipx_addr *dst)
339 {
340         struct ipx_ifaddr *ia;
341         struct ipx_addr *compare;
342         struct ifnet *ifp;
343         struct ipx_ifaddr *ia_maybe = NULL;
344         union ipx_net net = dst->x_net;
345
346         for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) {
347                 if ((ifp = ia->ia_ifp) != NULL) {
348                         if (ifp->if_flags & IFF_POINTOPOINT) {
349                                 compare = &satoipx_addr(ia->ia_dstaddr);
350                                 if (ipx_hosteq(*dst, *compare))
351                                         return (ia);
352                                 if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net))
353                                         ia_maybe = ia;
354                         } else {
355                                 if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net))
356                                         return (ia);
357                         }
358                 }
359         }
360         return (ia_maybe);
361 }
362
363
364 void
365 ipx_printhost(struct ipx_addr *addr)
366 {
367         u_short port;
368         struct ipx_addr work = *addr;
369         char *p; u_char *q;
370         char *net = "", *host = "";
371         char cport[10], chost[15], cnet[15];
372
373         port = ntohs(work.x_port);
374
375         if (ipx_nullnet(work) && ipx_nullhost(work)) {
376
377                 if (port)
378                         printf("*.%x", port);
379                 else
380                         printf("*.*");
381
382                 return;
383         }
384
385         if (ipx_wildnet(work))
386                 net = "any";
387         else if (ipx_nullnet(work))
388                 net = "*";
389         else {
390                 q = work.x_net.c_net;
391                 snprintf(cnet, sizeof(cnet), "%x%x%x%x",
392                         q[0], q[1], q[2], q[3]);
393                 for (p = cnet; *p == '0' && p < cnet + 8; p++)
394                         continue;
395                 net = p;
396         }
397
398         if (ipx_wildhost(work))
399                 host = "any";
400         else if (ipx_nullhost(work))
401                 host = "*";
402         else {
403                 q = work.x_host.c_host;
404                 snprintf(chost, sizeof(chost), "%x%x%x%x%x%x",
405                         q[0], q[1], q[2], q[3], q[4], q[5]);
406                 for (p = chost; *p == '0' && p < chost + 12; p++)
407                         continue;
408                 host = p;
409         }
410
411         if (port) {
412                 if (strcmp(host, "*") == 0) {
413                         host = "";
414                         snprintf(cport, sizeof(cport), "%x", port);
415                 } else
416                         snprintf(cport, sizeof(cport), ".%x", port);
417         } else
418                 *cport = 0;
419
420         printf("%s.%s%s", net, host, cport);
421 }