OSDN Git Service

2013.10.24
[uclinux-h8/uClinux-dist.git] / user / dhcpcd / if.c
1 /* $Id: if.c,v 1.6 2001-06-29 06:25:14 philipc Exp $
2  *
3  * dhcpcd - DHCP client daemon -
4  * Copyright (C) 1996 - 1997 Yoichi Hariguchi <yoichi@fore.com>
5  *
6  * Dhcpcd is an RFC2131 and RFC1541 compliant DHCP client daemon.
7  *
8  * This is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16  * See the GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  */
22
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <sys/ioctl.h>
26 #include <netinet/in.h>
27 #include <net/if.h>
28 #include <net/if_arp.h>
29 #include <net/route.h>
30 #include <arpa/inet.h>
31 #include <errno.h>
32 #include <stdio.h>
33 #include <sys/stat.h>
34 #include <fcntl.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <time.h>
38 #include <unistd.h>
39 #include "if.h"
40 #include "dhcp.h"
41 #include "error-handler.h"
42
43 struct ifinfo Ifbuf;
44
45 void
46 ifReset(char *ifname)
47 {
48         bzero((char *)&Ifbuf, sizeof(Ifbuf));
49         strncpy(Ifbuf.ifname, ifname, sizeof(Ifbuf.ifname));
50         Ifbuf.addr      = htonl(0);
51         Ifbuf.mask      = htonl(0);
52         Ifbuf.bcast     = inet_addr("255.255.255.255");
53         Ifbuf.flags = IFF_UP | IFF_BROADCAST | IFF_NOTRAILERS | IFF_RUNNING;
54         ifConfig(&Ifbuf);
55 }
56
57 void
58 ifConfig(struct ifinfo * ifinfo)
59 {
60     int                                 s;
61         struct ifreq            ifr;
62         struct rtentry          rtent;
63         struct sockaddr_in      *p;
64
65         strncpy(ifr.ifr_name, ifinfo->ifname, sizeof(ifr.ifr_name));
66
67         if ( (s = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
68                 logSysExit("socket (ifConfig)");
69         }
70         if ( ioctl(s, SIOCGIFHWADDR, &ifr) < 0 ) {
71                 logSysExit("ioctl SIOCGIFHWADDR (ifConfig)");
72         }
73         if ( ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER ) {
74                 logQuit("ifInit: interface %s is not Ethernet\n", ifr.ifr_name);
75         }
76         /* save hardware address of the interface
77          */
78         bcopy(ifr.ifr_hwaddr.sa_data, ifinfo->haddr, sizeof(ifinfo->haddr));
79
80         /* configure interface
81          */
82         p = (struct sockaddr_in *)&(ifr.ifr_addr);
83         p->sin_family = AF_INET;
84         p->sin_addr.s_addr = ifinfo->addr;
85         if ( ioctl(s, SIOCSIFADDR, &ifr) < 0 ) {
86                 logSysExit("ioctl SIOCSIFADDR (ifConfig)");
87         }
88         p->sin_addr.s_addr = ifinfo->bcast;
89         if ( ioctl(s, SIOCSIFBRDADDR, &ifr) < 0 ) {
90                 logSysExit("ioctl SIOCSIFBRDADDR (ifConfig)");
91         }
92         p->sin_addr.s_addr = ifinfo->mask;
93         if ( ioctl(s, SIOCSIFNETMASK, &ifr) < 0 ) {
94                 logSysExit("ioctl SIOCSIFNETMASK (ifConfig)");
95         }
96         ifr.ifr_flags = ifinfo->flags;
97         if ( ioctl(s, SIOCSIFFLAGS, &ifr) < 0 ) {
98                 logSysExit("ioctl SIOCSIFFLAGS (ifConfig)");
99         }
100         /* set route to the interface
101          */
102         bzero((char *)&rtent, sizeof(rtent));
103
104         p = (struct sockaddr_in *)&rtent.rt_dst;
105         p->sin_family           = AF_INET;
106         p->sin_addr.s_addr      = ifinfo->addr & ifinfo->mask;  /* dest. net address */
107
108         if (p->sin_addr.s_addr == 0) {
109                 p->sin_addr.s_addr = 0xffffffff;
110                 rtent.rt_flags |= RTF_HOST;
111         }
112
113         p = (struct sockaddr_in *)&rtent.rt_gateway;
114         p->sin_family           = AF_INET;
115         p->sin_addr.s_addr      = ifinfo->addr;                         /* gateway address */
116
117         rtent.rt_dev            = ifinfo->ifname;                       /* interface name */
118         rtent.rt_metric         = 1;                                            /* metric (see route.h) */
119         rtent.rt_flags          |= RTF_UP;                                      /* net route */
120         if ( ioctl(s, SIOCADDRT, &rtent) < 0 ) {
121                 logSysExit("ioctl SIOCADDRT (ifConfig)");
122         }
123         close(s);
124 }
125
126 void
127 ifDown(struct ifinfo * ifinfo)
128 {
129     int                                 s;
130         struct ifreq            ifr;
131
132         strncpy(ifr.ifr_name, ifinfo->ifname, sizeof(ifr.ifr_name));
133
134         if ( (s = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
135                 logSysExit("socket (ifDown)");
136         }
137         /* down interface
138          */
139 #if 1
140         /*
141          *      I don't understand why you would turn on all flags
142          *      except the interface up when shutting down the line?
143          *      That makes it really hard to use ifconfig to then
144          *      set up the interface... It must be wrong.
145          */
146         ifr.ifr_flags = 0;
147 #else
148         ifr.ifr_flags = ~IFF_UP;
149 #endif
150         if ( ioctl(s, SIOCSIFFLAGS, &ifr) < 0 ) {
151                 logSysExit("ioctl SIOCSIFFLAGS (ifDown)");
152         }
153         close(s);
154 }
155
156
157
158 u_long
159 getNaturalMask(u_long inaddr)
160 {
161         if ( isClassA(inaddr) ) {
162                 return inet_addr("255.0.0.0");
163         }
164         if ( isClassB(inaddr) ) {
165                 return inet_addr("255.255.0.0");
166         }
167         if ( isClassC(inaddr) ) {
168                 return inet_addr("255.255.255.0");
169         }
170         return htonl(0);
171 }
172
173 u_long
174 getNaturalBcast(u_long inaddr)
175 {
176         if ( isClassA(inaddr) ) {
177                 return (inaddr & htonl(0xff000000)) | htonl(0x00ffffff);
178         }
179         if ( isClassB(inaddr) ) {
180                 return (inaddr & htonl(0xffff0000)) | htonl(0x0000ffff);
181         }
182         if ( isClassC(inaddr) ) {
183                 return (inaddr & htonl(0xffffff00)) | htonl(0x000000ff);
184         }
185         return htonl(0);
186 }
187
188 #ifndef EMBED
189
190 void
191 saveIfInfo(struct ifinfo *ifbuf)
192 {
193         int              fd;
194         int              isfailed;
195         u_long   leaseLeft;
196         char     filename[IFNAMSIZ + 128];
197
198         /* set up environmet variable on the attached network interface name
199          */
200         if ( setenv("DHCP_DEVICE", ifbuf->ifname, 1) < 0 ) {
201                 logRet("setenv (saveIfInfo): insufficient space");
202         }
203         isfailed = 0;
204         strcpy(filename, DHCP_CACHE_FILE);
205         strcat(filename, ifbuf->ifname);
206         if ( (fd = creat(filename, 0644)) < 0 ) {
207                 logSysRet("creat (saveIfinfo)");
208                 return;
209         }
210         if ( write(fd, (const char *)&ifbuf->addr, sizeof(ifbuf->addr)) < 0 ) {
211                 logSysRet("write (saveIfinfo)");
212                 isfailed = 1;
213         }
214         if ( LeaseTime == INFINITE_LEASE_TIME ) {
215                 leaseLeft = INFINITE_LEASE_TIME;
216         } else {
217                 leaseLeft = ntohl(LeaseTime) - (time(NULL) - ReqSentTime);
218         }
219         if ( write(fd, (const char *)&leaseLeft, sizeof(leaseLeft)) < 0 ) {
220                 logSysRet("write (saveIfinfo)");
221                 isfailed = 1;
222         }
223         if ( isfailed ) {
224                 if ( unlink((const char*)filename) < 0 ) {
225                         logSysRet("unlink (saveIfinfo)");
226                 }
227         }
228         close(fd);
229 }
230
231 #endif /* EMBED */
232
233 void
234 getIfInfo(struct ifinfo * ifinfo)
235 {
236     int                                 s;
237         struct ifreq            ifr;
238
239         strcpy(ifr.ifr_name, ifinfo->ifname);
240         if ( (s = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
241                 logSysExit("socket (getIfInfo)");
242         }
243         if ( ioctl(s, SIOCGIFHWADDR, &ifr) < 0 ) {
244                 logSysExit("ioctl SIOCGIFHWADDR (getIfInfo)");
245         }
246         if ( ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER ) {
247                 logQuit("getIfInfo: interface %s is not Ethernet\n", ifr.ifr_name);
248         }
249         /* save hardware address of the interface
250          */
251         bcopy(ifr.ifr_hwaddr.sa_data, ifinfo->haddr, sizeof(ifinfo->haddr));
252
253         /* configure interface
254          */
255         if ( ioctl(s, SIOCGIFADDR, &ifr) < 0 ) {
256                 logSysExit("ioctl SIOCGIFADDR (getIfInfo)");
257         }
258         ifinfo->addr = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
259         if ( ioctl(s, SIOCGIFBRDADDR, &ifr) < 0 ) {
260                 logSysExit("ioctl SIOCGIFBRDADDR (getIfInfo)");
261         }
262         ifinfo->addr = ((struct sockaddr_in *)&ifr.ifr_broadaddr)->sin_addr.s_addr;
263         if ( ioctl(s, SIOCGIFNETMASK, &ifr) < 0 ) {
264                 logSysExit("ioctl SIOCGIFNETMASK (getIfInfo)");
265         }
266         ifinfo->mask = ((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr.s_addr;
267         if ( ioctl(s, SIOCGIFFLAGS, &ifr) < 0 ) {
268                 logSysExit("ioctl SIOCGIFFLAGS (getIfInfo)");
269         }
270         ifinfo->flags = ifr.ifr_flags;
271         close(s);
272 }
273
274 void
275 setDefRoute(const char *routers, struct ifinfo *ifinfo)
276 {
277         u_long gwAddr;                          /* router's IP address (network byte order) */
278         int s;
279         int i;
280         struct rtentry          rtent;
281         struct sockaddr_in      *p;
282
283         if ( (s = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
284                 logSysExit("socket (setDefRoute)");
285         }
286         bzero((char *)&rtent, sizeof(rtent));
287         p = (struct sockaddr_in *)&rtent.rt_dst;
288         p->sin_family           = AF_INET;
289         p->sin_addr.s_addr      = 0;    /* dest. net address (default route) */
290         p = (struct sockaddr_in *)&rtent.rt_genmask;
291         p->sin_family           = AF_INET;
292         p->sin_addr.s_addr      = 0;
293         p = (struct sockaddr_in *)&rtent.rt_gateway;
294         p->sin_family           = AF_INET;
295
296         /* verify rouer addresses are correct
297          */
298         for ( i = 0; i < *routers/4; ++i ) {
299                 gwAddr = *((u_long *)(routers+1) + i);
300                 if ( (gwAddr & ifinfo->mask) == (ifinfo->addr & ifinfo->mask)
301                                 && (gwAddr != ifinfo->addr)
302                                 && (gwAddr != 0) ) {
303                         p->sin_addr.s_addr      = gwAddr;
304                         rtent.rt_dev            = ifinfo->ifname;       /* interface name */
305                         rtent.rt_metric         = 1;                            /* metric (see route.h) */
306                         rtent.rt_flags          = RTF_UP|RTF_GATEWAY;   /* dest. is a gateway */
307                         if ( ioctl(s, SIOCADDRT, &rtent) < 0 ) {
308                                 logSysRet("ioctl SIOCADDRT (setDefRoute)");
309                         }
310                         else {
311                                 /* TODO: also verify if the router is alive
312                                  *  or not by using ping
313                                  */
314                                 break;
315                         }
316                 }
317         }
318         close(s);
319 }
320