]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netipx/ipx.c
This commit was generated by cvs2svn to compensate for changes in r167612,
[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/sockio.h>
70 #include <sys/socket.h>
71
72 #include <net/if.h>
73 #include <net/route.h>
74
75 #include <netipx/ipx.h>
76 #include <netipx/ipx_if.h>
77 #include <netipx/ipx_var.h>
78
79 /*
80  * XXXRW: Requires synchronization.
81  */
82 struct ipx_ifaddr *ipx_ifaddr;
83
84 static  void ipx_ifscrub(struct ifnet *ifp, struct ipx_ifaddr *ia);
85 static  int ipx_ifinit(struct ifnet *ifp, struct ipx_ifaddr *ia,
86                        struct sockaddr_ipx *sipx, int scrub);
87
88 /*
89  * Generic internet control operations (ioctl's).
90  */
91 int
92 ipx_control(so, cmd, data, ifp, td)
93         struct socket *so;
94         u_long cmd;
95         caddr_t data;
96         register struct ifnet *ifp;
97         struct thread *td;
98 {
99         register struct ifreq *ifr = (struct ifreq *)data;
100         register struct ipx_aliasreq *ifra = (struct ipx_aliasreq *)data;
101         register struct ipx_ifaddr *ia;
102         struct ifaddr *ifa;
103         struct ipx_ifaddr *oia;
104         int dstIsNew, hostIsNew;
105         int error = 0;
106
107         /*
108          * Find address for this interface, if it exists.
109          */
110         if (ifp == NULL)
111                 return (EADDRNOTAVAIL);
112         for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next)
113                 if (ia->ia_ifp == ifp)
114                         break;
115
116         switch (cmd) {
117
118         case SIOCGIFADDR:
119                 if (ia == NULL)
120                         return (EADDRNOTAVAIL);
121                 *(struct sockaddr_ipx *)&ifr->ifr_addr = ia->ia_addr;
122                 return (0);
123
124         case SIOCGIFBRDADDR:
125                 if (ia == NULL)
126                         return (EADDRNOTAVAIL);
127                 if ((ifp->if_flags & IFF_BROADCAST) == 0)
128                         return (EINVAL);
129                 *(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_broadaddr;
130                 return (0);
131
132         case SIOCGIFDSTADDR:
133                 if (ia == NULL)
134                         return (EADDRNOTAVAIL);
135                 if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
136                         return (EINVAL);
137                 *(struct sockaddr_ipx *)&ifr->ifr_dstaddr = ia->ia_dstaddr;
138                 return (0);
139         }
140
141         if (td && (error = suser(td)) != 0)
142                 return (error);
143
144         switch (cmd) {
145         case SIOCAIFADDR:
146         case SIOCDIFADDR:
147                 if (ifra->ifra_addr.sipx_family == AF_IPX)
148                     for (oia = ia; ia != NULL; ia = ia->ia_next) {
149                         if (ia->ia_ifp == ifp  &&
150                             ipx_neteq(ia->ia_addr.sipx_addr,
151                                   ifra->ifra_addr.sipx_addr))
152                             break;
153                     }
154                 if (cmd == SIOCDIFADDR && ia == NULL)
155                         return (EADDRNOTAVAIL);
156                 /* FALLTHROUGH */
157
158         case SIOCSIFADDR:
159         case SIOCSIFDSTADDR:
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         }
190
191         switch (cmd) {
192
193         case SIOCSIFDSTADDR:
194                 if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
195                         return (EINVAL);
196                 if (ia->ia_flags & IFA_ROUTE) {
197                         rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
198                         ia->ia_flags &= ~IFA_ROUTE;
199                 }
200                 if (ifp->if_ioctl) {
201                         error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, (void *)ia);
202                         if (error)
203                                 return (error);
204                 }
205                 *(struct sockaddr *)&ia->ia_dstaddr = ifr->ifr_dstaddr;
206                 return (0);
207
208         case SIOCSIFADDR:
209                 return (ipx_ifinit(ifp, ia,
210                                 (struct sockaddr_ipx *)&ifr->ifr_addr, 1));
211
212         case SIOCDIFADDR:
213                 ipx_ifscrub(ifp, ia);
214                 ifa = (struct ifaddr *)ia;
215                 TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link);
216                 oia = ia;
217                 if (oia == (ia = ipx_ifaddr)) {
218                         ipx_ifaddr = ia->ia_next;
219                 } else {
220                         while (ia->ia_next && (ia->ia_next != oia)) {
221                                 ia = ia->ia_next;
222                         }
223                         if (ia->ia_next)
224                             ia->ia_next = oia->ia_next;
225                         else
226                                 printf("Didn't unlink ipxifadr from list\n");
227                 }
228                 IFAFREE((&oia->ia_ifa));
229                 return (0);
230
231         case SIOCAIFADDR:
232                 dstIsNew = 0;
233                 hostIsNew = 1;
234                 if (ia->ia_addr.sipx_family == AF_IPX) {
235                         if (ifra->ifra_addr.sipx_len == 0) {
236                                 ifra->ifra_addr = ia->ia_addr;
237                                 hostIsNew = 0;
238                         } else if (ipx_neteq(ifra->ifra_addr.sipx_addr,
239                                          ia->ia_addr.sipx_addr))
240                                 hostIsNew = 0;
241                 }
242                 if ((ifp->if_flags & IFF_POINTOPOINT) &&
243                     (ifra->ifra_dstaddr.sipx_family == AF_IPX)) {
244                         if (hostIsNew == 0)
245                                 ipx_ifscrub(ifp, ia);
246                         ia->ia_dstaddr = ifra->ifra_dstaddr;
247                         dstIsNew  = 1;
248                 }
249                 if (ifra->ifra_addr.sipx_family == AF_IPX &&
250                                             (hostIsNew || dstIsNew))
251                         error = ipx_ifinit(ifp, ia, &ifra->ifra_addr, 0);
252                 return (error);
253
254         default:
255                 if (ifp->if_ioctl == NULL)
256                         return (EOPNOTSUPP);
257                 return ((*ifp->if_ioctl)(ifp, cmd, data));
258         }
259 }
260
261 /*
262 * Delete any previous route for an old address.
263 */
264 static void
265 ipx_ifscrub(ifp, ia)
266         register struct ifnet *ifp;
267         register struct ipx_ifaddr *ia;
268 {
269         if (ia->ia_flags & IFA_ROUTE) {
270                 if (ifp->if_flags & IFF_POINTOPOINT) {
271                         rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
272                 } else
273                         rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0);
274                 ia->ia_flags &= ~IFA_ROUTE;
275         }
276 }
277 /*
278  * Initialize an interface's internet address
279  * and routing table entry.
280  */
281 static int
282 ipx_ifinit(ifp, ia, sipx, scrub)
283         register struct ifnet *ifp;
284         register struct ipx_ifaddr *ia;
285         register struct sockaddr_ipx *sipx;
286         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(dst)
339         register struct ipx_addr *dst;
340 {
341         register struct ipx_ifaddr *ia;
342         register struct ipx_addr *compare;
343         register struct ifnet *ifp;
344         struct ipx_ifaddr *ia_maybe = NULL;
345         union ipx_net net = dst->x_net;
346
347         for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next) {
348                 if ((ifp = ia->ia_ifp) != NULL) {
349                         if (ifp->if_flags & IFF_POINTOPOINT) {
350                                 compare = &satoipx_addr(ia->ia_dstaddr);
351                                 if (ipx_hosteq(*dst, *compare))
352                                         return (ia);
353                                 if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net))
354                                         ia_maybe = ia;
355                         } else {
356                                 if (ipx_neteqnn(net, ia->ia_addr.sipx_addr.x_net))
357                                         return (ia);
358                         }
359                 }
360         }
361         return (ia_maybe);
362 }
363
364
365 void
366 ipx_printhost(addr)
367 register struct ipx_addr *addr;
368 {
369         u_short port;
370         struct ipx_addr work = *addr;
371         register char *p; register u_char *q;
372         register char *net = "", *host = "";
373         char cport[10], chost[15], cnet[15];
374
375         port = ntohs(work.x_port);
376
377         if (ipx_nullnet(work) && ipx_nullhost(work)) {
378
379                 if (port)
380                         printf("*.%x", port);
381                 else
382                         printf("*.*");
383
384                 return;
385         }
386
387         if (ipx_wildnet(work))
388                 net = "any";
389         else if (ipx_nullnet(work))
390                 net = "*";
391         else {
392                 q = work.x_net.c_net;
393                 snprintf(cnet, sizeof(cnet), "%x%x%x%x",
394                         q[0], q[1], q[2], q[3]);
395                 for (p = cnet; *p == '0' && p < cnet + 8; p++)
396                         continue;
397                 net = p;
398         }
399
400         if (ipx_wildhost(work))
401                 host = "any";
402         else if (ipx_nullhost(work))
403                 host = "*";
404         else {
405                 q = work.x_host.c_host;
406                 snprintf(chost, sizeof(chost), "%x%x%x%x%x%x",
407                         q[0], q[1], q[2], q[3], q[4], q[5]);
408                 for (p = chost; *p == '0' && p < chost + 12; p++)
409                         continue;
410                 host = p;
411         }
412
413         if (port) {
414                 if (strcmp(host, "*") == 0) {
415                         host = "";
416                         snprintf(cport, sizeof(cport), "%x", port);
417                 } else
418                         snprintf(cport, sizeof(cport), ".%x", port);
419         } else
420                 *cport = 0;
421
422         printf("%s.%s%s", net, host, cport);
423 }