OSDN Git Service

Fix no pic
[uclinux-h8/uClinux-dist.git] / user / slattach / route.c
1
2 /* This file is derived from pppd's sys-linux.c file, and is under
3    the following copyright: */
4
5 /*
6  * sys-linux.c - System-dependent procedures for setting up
7  * PPP interfaces on Linux systems
8  *
9  * Copyright (c) 1989 Carnegie Mellon University.
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms are permitted
13  * provided that the above copyright notice and this paragraph are
14  * duplicated in all such forms and that any documentation,
15  * advertising materials, and other materials related to such
16  * distribution and use acknowledge that the software was developed
17  * by Carnegie Mellon University.  The name of the
18  * University may not be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
22  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
23  */
24
25 /*
26  * TODO:
27  */
28
29 #include <sys/types.h>
30
31 /*
32  * This is to bypass problems with earlier kernels.
33  */
34
35 #include <string.h>
36 #undef  _I386_STRING_H_
37 #define _I386_STRING_H_
38 #undef  _LINUX_STRING_H_
39 #define _LINUX_STRING_H_
40
41 /*
42  * Continue with the rest of the include sequences.
43  */
44
45 #include <sys/ioctl.h>
46 #include <sys/socket.h>
47 #include <sys/time.h>
48 #include <sys/errno.h>
49 #include <sys/stat.h>
50 #include <sys/file.h>
51
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <syslog.h>
55 #include <time.h>
56 #include <memory.h>
57 #include <utmp.h>
58 #include <signal.h>
59 #include <fcntl.h>
60 #include <ctype.h>
61
62 /* This is in netdevice.h. However, this compile will fail miserably if
63    you attempt to include netdevice.h because it has so many references
64    to __memcpy functions which it should not attempt to do. So, since I
65    really don't use it, but it must be defined, define it now. */
66
67 #ifndef MAX_ADDR_LEN
68 #define MAX_ADDR_LEN 7
69 #endif
70
71 #include "../pppd.small/usr.include.net/if.h"
72 #include "../pppd.small/usr.include.net/ppp_defs.h"
73 #include "../pppd.small/usr.include.net/if_arp.h"
74 #include "../pppd.small/usr.include.net/if_ppp.h"
75 #include "../pppd.small/usr.include.net/route.h"
76 #include <linux/if_ether.h>
77 #include <netinet/in.h>
78 #include <arpa/inet.h>
79
80 #include "pppd.h"
81 #if 0
82 #include "fsm.h"
83 #include "ipcp.h"
84 #endif
85
86 static int initdisc = -1;       /* Initial TTY discipline */
87 static int prev_kdebugflag     = 0;
88 static int has_default_route   = 0;
89 static int has_proxy_arp       = 0;
90 static int driver_version      = 0;
91 static int driver_modification = 0;
92 static int driver_patch        = 0;
93 static int restore_term        = 0;     /* 1 => we've munged the terminal */
94 static struct termios inittermios;      /* Initial TTY termios */
95
96 int sockfd;                     /* socket for doing interface ioctls */
97
98 static char *lock_file;
99
100 #undef syslog
101 #define syslog(a,b,c...) ({ printf(b, ## c); })
102 #undef MAINDEBUG
103 #define MAINDEBUG(x) syslog x
104
105 #define MAX_IFS         6
106
107 #define FLAGS_GOOD (IFF_UP          | IFF_BROADCAST)
108 #define FLAGS_MASK (IFF_UP          | IFF_BROADCAST | \
109                     IFF_POINTOPOINT | IFF_LOOPBACK  | IFF_NOARP)
110
111 /*
112  * SET_SA_FAMILY - set the sa_family field of a struct sockaddr,
113  * if it exists.
114  */
115
116 #define SET_SA_FAMILY(addr, family)                     \
117     memset ((char *) &(addr), '\0', sizeof(addr));      \
118     addr.sa_family = (family);
119
120
121 /*
122  * path_to_proc - determine the path to the proc file system data
123  */
124
125 FILE *route_fd = (FILE *) 0;
126 static char route_buffer [512];
127
128 static char *path_to_proc (void);
129 static int open_route_table (void);
130 static void close_route_table (void);
131 static int read_route_table (struct rtentry *rt);
132 static int defaultroute_exists (void);
133
134 /*
135  * path_to_proc - find the path to the route tables in the proc file system
136  */
137
138 static char *path_to_proc (void)
139   {
140     static char buf[32];
141     strcpy(buf, "/proc");
142     return buf;
143   }
144
145 /*
146  * close_route_table - close the interface to the route table
147  */
148
149 static void close_route_table (void)
150   {
151     if (route_fd != (FILE *) 0)
152       {
153         fclose (route_fd);
154         route_fd = (FILE *) 0;
155       }
156   }
157
158 /*
159  * open_route_table - open the interface to the route table
160  */
161
162 static int open_route_table (void)
163   {
164     char *path;
165
166     close_route_table();
167
168     path = path_to_proc();
169     if (path == NULL)
170       {
171         return 0;
172       }
173
174     strcat (path, "/net/route");
175     route_fd = fopen (path, "r");
176     if (route_fd == (FILE *) 0)
177       {
178         syslog (LOG_ERR, "can not open %s: %m", path);
179         return 0;
180       }
181     return 1;
182   }
183
184 /*
185  * read_route_table - read the next entry from the route table
186  */
187
188 #define delims " \t\n"
189 static int read_route_table (struct rtentry *rt)
190   {
191     /*static char delims[] = " \t\n";*/
192     char *dev_ptr, *ptr, *dst_ptr, *gw_ptr, *flag_ptr;
193         
194     memset (rt, '\0', sizeof (struct rtentry));
195
196     for (;;)
197       {
198         if (fgets (route_buffer, sizeof (route_buffer), route_fd) ==
199             (char *) 0)
200           {
201             return 0;
202           }
203
204         dev_ptr  = strtok (route_buffer, delims); /* interface name */
205         dst_ptr  = strtok (NULL,         delims); /* destination address */
206         gw_ptr   = strtok (NULL,         delims); /* gateway */
207         flag_ptr = strtok (NULL,         delims); /* flags */
208     
209         if (flag_ptr == (char *) 0) /* assume that we failed, somewhere. */
210           {
211             return 0;
212           }
213         
214         /* Discard that stupid header line which should never
215          * have been there in the first place !! */
216         if (isxdigit (*dst_ptr) && isxdigit (*gw_ptr) && isxdigit (*flag_ptr))
217           {
218             break;
219           }
220       }
221
222     ((struct sockaddr_in *) &rt->rt_dst)->sin_addr.s_addr =
223       strtoul (dst_ptr, NULL, 16);
224
225     ((struct sockaddr_in *) &rt->rt_gateway)->sin_addr.s_addr =
226       strtoul (gw_ptr, NULL, 16);
227
228     rt->rt_flags = (short) strtoul (flag_ptr, NULL, 16);
229     rt->rt_dev   = dev_ptr;
230
231     return 1;
232   }
233 #undef delims
234
235 /*
236  * defaultroute_exists - determine if there is a default route
237  */
238
239 static int defaultroute_exists (void)
240   {
241     struct rtentry rt;
242     int    result = 0;
243
244     if (!open_route_table())
245       {
246         return 0;
247       }
248
249     while (read_route_table(&rt) != 0)
250       {
251         if ((rt.rt_flags & RTF_UP) == 0)
252           {
253             continue;
254           }
255          
256         if (((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr == 0L)
257           {
258             syslog (LOG_ERR,
259                     "ppp not replacing existing default route to %s[%s]",
260                     rt.rt_dev,
261                     inet_ntoa (((struct sockaddr_in *) &rt.rt_gateway)->
262                                sin_addr));
263             result = 1;
264             break;
265           }
266           
267       }
268
269     close_route_table();
270     return result;
271   }
272
273 /*
274  * sifdefaultroute - assign a default route through the address given.
275  */
276
277 int sifdefaultroute (int unit, int gateway)
278   {
279     struct rtentry rt;
280
281     if (has_default_route == 0)
282       {
283         if (defaultroute_exists())
284           {
285             return 0;
286           }
287
288         memset (&rt, '\0', sizeof (rt));
289         SET_SA_FAMILY (rt.rt_dst,     AF_INET);
290         SET_SA_FAMILY (rt.rt_gateway, AF_INET);
291         ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = gateway;
292     
293         rt.rt_flags = RTF_UP | RTF_GATEWAY;
294         if (ioctl(sockfd, SIOCADDRT, &rt) < 0)
295           {
296             syslog (LOG_ERR, "default route ioctl(SIOCADDRT): %m");
297             return 0;
298           }
299       }
300     has_default_route = 1;
301     return 1;
302   }
303
304 /*
305  * cifdefaultroute - delete a default route through the address given.
306  */
307
308 int cifdefaultroute (int unit, int gateway)
309   {
310     struct rtentry rt;
311
312     if (has_default_route)
313       {
314         memset (&rt, '\0', sizeof (rt));
315         SET_SA_FAMILY (rt.rt_dst,     AF_INET);
316         SET_SA_FAMILY (rt.rt_gateway, AF_INET);
317         ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = gateway;
318     
319         rt.rt_flags = RTF_UP | RTF_GATEWAY;
320         if (ioctl(sockfd, SIOCDELRT, &rt) < 0 && errno != ESRCH)
321           {
322             /*if (still_ppp())
323               {
324                 syslog (LOG_ERR, "default route ioctl(SIOCDELRT): %m");
325                 return 0;
326               }*/
327           }
328       }
329     has_default_route = 0;
330     return 1;
331   }
332
333 /*
334  * sifproxyarp - Make a proxy ARP entry for the peer.
335  */
336
337 int sifproxyarp (int unit, u_int32_t his_adr)
338   {
339     struct arpreq arpreq;
340 /*
341  * Sometime in the 1.3 series kernels, the arp request added a device name.
342  */
343 #include <linux/version.h>
344 #if LINUX_VERSION_CODE < 66381
345     char arpreq_arp_dev[32];
346 #else
347 #define  arpreq_arp_dev arpreq.arp_dev
348 #endif
349
350     if (has_proxy_arp == 0)
351       {
352         memset (&arpreq, '\0', sizeof(arpreq));
353 /*
354  * Get the hardware address of an interface on the same subnet
355  * as our local address.
356  */
357         if (!get_ether_addr(his_adr, &arpreq.arp_ha, arpreq_arp_dev))
358           {
359             syslog(LOG_ERR, "Cannot determine ethernet address for proxy ARP");
360             return 0;
361           }
362     
363         SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
364         ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = his_adr;
365         arpreq.arp_flags = ATF_PERM | ATF_PUBL;
366         
367         if (ioctl(sockfd, SIOCSARP, (caddr_t)&arpreq) < 0)
368           {
369             syslog(LOG_ERR, "ioctl(SIOCSARP): %m");
370             return 0;
371           }
372       }
373
374     has_proxy_arp = 1;
375     return 1;
376   }
377
378 /*
379  * cifproxyarp - Delete the proxy ARP entry for the peer.
380  */
381
382 int cifproxyarp (int unit, u_int32_t his_adr)
383   {
384     struct arpreq arpreq;
385
386     if (has_proxy_arp == 1)
387       {
388         memset (&arpreq, '\0', sizeof(arpreq));
389         SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
390         arpreq.arp_flags = ATF_PERM | ATF_PUBL;
391     
392         ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = his_adr;
393         if (ioctl(sockfd, SIOCDARP, (caddr_t)&arpreq) < 0)
394           {
395             syslog(LOG_WARNING, "ioctl(SIOCDARP): %m");
396             return 0;
397           }
398       }
399     has_proxy_arp = 0;
400     return 1;
401   }
402      
403 /*
404  * get_ether_addr - get the hardware address of an interface on the
405  * the same subnet as ipaddr.
406  */
407
408 char * ip_ntoa(u_int32_t x) { 
409         struct in_addr i;
410         i.s_addr = x;
411         return inet_ntoa(i);
412 }
413
414 static int local_get_ether_addr (u_int32_t ipaddr, struct sockaddr *hwaddr,
415                                  char *name, struct ifreq *ifs, int ifs_len)
416   {
417     struct ifreq *ifr, *ifend, *ifp;
418     int i;
419     u_int32_t ina, mask;
420     struct sockaddr_dl *dla;
421     struct ifreq ifreq;
422     struct ifconf ifc;
423 /*
424  * Request the total list of all devices configured on your system.
425  */    
426     ifc.ifc_len = ifs_len;
427     ifc.ifc_req = ifs;
428     if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0)
429       {
430         syslog(LOG_ERR, "ioctl(SIOCGIFCONF): %m");
431         return 0;
432       }
433
434     MAINDEBUG ((LOG_DEBUG, "proxy arp: scanning %d interfaces for IP %s",
435                 ifc.ifc_len / sizeof(struct ifreq), ip_ntoa(ipaddr)));
436 /*
437  * Scan through looking for an interface with an Internet
438  * address on the same subnet as `ipaddr'.
439  */
440     ifend = ifs + (ifc.ifc_len / sizeof(struct ifreq));
441     for (ifr = ifc.ifc_req; ifr < ifend; ifr++)
442       {
443         if (ifr->ifr_addr.sa_family == AF_INET)
444           {
445             ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
446             strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
447             MAINDEBUG ((LOG_DEBUG, "proxy arp: examining interface %s",
448                         ifreq.ifr_name));
449 /*
450  * Check that the interface is up, and not point-to-point
451  * nor loopback.
452  */
453             if (ioctl(sockfd, SIOCGIFFLAGS, &ifreq) < 0)
454               {
455                 continue;
456               }
457
458             if (((ifreq.ifr_flags ^ FLAGS_GOOD) & FLAGS_MASK) != 0)
459               {
460                 continue;
461               }
462 /*
463  * Get its netmask and check that it's on the right subnet.
464  */
465             if (ioctl(sockfd, SIOCGIFNETMASK, &ifreq) < 0)
466               {
467                 continue;
468               }
469
470             mask = ((struct sockaddr_in *) &ifreq.ifr_addr)->sin_addr.s_addr;
471             MAINDEBUG ((LOG_DEBUG, "proxy arp: interface addr %s mask %lx",
472                         ip_ntoa(ina), ntohl(mask)));
473
474             if (((ipaddr ^ ina) & mask) != 0)
475               {
476                 continue;
477               }
478             break;
479           }
480       }
481     
482     if (ifr >= ifend)
483       {
484         return 0;
485       }
486
487     memcpy (name, ifreq.ifr_name, sizeof(ifreq.ifr_name));
488     syslog(LOG_INFO, "found interface %s for proxy arp", name);
489 /*
490  * Now get the hardware address.
491  */
492     memset (&ifreq.ifr_hwaddr, 0, sizeof (struct sockaddr));
493     if (ioctl (sockfd, SIOCGIFHWADDR, &ifreq) < 0)
494       {
495         syslog(LOG_ERR, "SIOCGIFHWADDR(%s): %m", ifreq.ifr_name);
496         return 0;
497       }
498
499     memcpy (hwaddr,
500             &ifreq.ifr_hwaddr,
501             sizeof (struct sockaddr));
502
503     MAINDEBUG ((LOG_DEBUG,
504            "proxy arp: found hwaddr %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
505                 (int) ((unsigned char *) &hwaddr->sa_data)[0],
506                 (int) ((unsigned char *) &hwaddr->sa_data)[1],
507                 (int) ((unsigned char *) &hwaddr->sa_data)[2],
508                 (int) ((unsigned char *) &hwaddr->sa_data)[3],
509                 (int) ((unsigned char *) &hwaddr->sa_data)[4],
510                 (int) ((unsigned char *) &hwaddr->sa_data)[5],
511                 (int) ((unsigned char *) &hwaddr->sa_data)[6],
512                 (int) ((unsigned char *) &hwaddr->sa_data)[7]));
513     return 1;
514   }
515
516 int get_ether_addr (u_int32_t ipaddr, struct sockaddr *hwaddr, char *name)
517   {
518     int ifs_len;
519     int answer;
520     void *base_addr;
521 /*
522  * Allocate memory to hold the request.
523  */    
524     ifs_len = MAX_IFS * sizeof (struct ifreq);
525     base_addr = (void *) malloc (ifs_len);
526     if (base_addr == (void *) 0)
527       {
528         syslog(LOG_ERR, "malloc(%d) failed to return memory", ifs_len);
529         return 0;
530       }
531 /*
532  * Find the hardware address associated with the controller
533  */    
534     answer = local_get_ether_addr (ipaddr, hwaddr, name,
535                                    (struct ifreq *) base_addr, ifs_len);
536
537     free (base_addr);
538     return answer;
539   }