1 /* $Id: if.c,v 1.6 2001-06-29 06:25:14 philipc Exp $
3 * dhcpcd - DHCP client daemon -
4 * Copyright (C) 1996 - 1997 Yoichi Hariguchi <yoichi@fore.com>
6 * Dhcpcd is an RFC2131 and RFC1541 compliant DHCP client daemon.
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.
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.
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.
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <sys/ioctl.h>
26 #include <netinet/in.h>
28 #include <net/if_arp.h>
29 #include <net/route.h>
30 #include <arpa/inet.h>
41 #include "error-handler.h"
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;
58 ifConfig(struct ifinfo * ifinfo)
63 struct sockaddr_in *p;
65 strncpy(ifr.ifr_name, ifinfo->ifname, sizeof(ifr.ifr_name));
67 if ( (s = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
68 logSysExit("socket (ifConfig)");
70 if ( ioctl(s, SIOCGIFHWADDR, &ifr) < 0 ) {
71 logSysExit("ioctl SIOCGIFHWADDR (ifConfig)");
73 if ( ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER ) {
74 logQuit("ifInit: interface %s is not Ethernet\n", ifr.ifr_name);
76 /* save hardware address of the interface
78 bcopy(ifr.ifr_hwaddr.sa_data, ifinfo->haddr, sizeof(ifinfo->haddr));
80 /* configure interface
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)");
88 p->sin_addr.s_addr = ifinfo->bcast;
89 if ( ioctl(s, SIOCSIFBRDADDR, &ifr) < 0 ) {
90 logSysExit("ioctl SIOCSIFBRDADDR (ifConfig)");
92 p->sin_addr.s_addr = ifinfo->mask;
93 if ( ioctl(s, SIOCSIFNETMASK, &ifr) < 0 ) {
94 logSysExit("ioctl SIOCSIFNETMASK (ifConfig)");
96 ifr.ifr_flags = ifinfo->flags;
97 if ( ioctl(s, SIOCSIFFLAGS, &ifr) < 0 ) {
98 logSysExit("ioctl SIOCSIFFLAGS (ifConfig)");
100 /* set route to the interface
102 bzero((char *)&rtent, sizeof(rtent));
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 */
108 if (p->sin_addr.s_addr == 0) {
109 p->sin_addr.s_addr = 0xffffffff;
110 rtent.rt_flags |= RTF_HOST;
113 p = (struct sockaddr_in *)&rtent.rt_gateway;
114 p->sin_family = AF_INET;
115 p->sin_addr.s_addr = ifinfo->addr; /* gateway address */
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)");
127 ifDown(struct ifinfo * ifinfo)
132 strncpy(ifr.ifr_name, ifinfo->ifname, sizeof(ifr.ifr_name));
134 if ( (s = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
135 logSysExit("socket (ifDown)");
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.
148 ifr.ifr_flags = ~IFF_UP;
150 if ( ioctl(s, SIOCSIFFLAGS, &ifr) < 0 ) {
151 logSysExit("ioctl SIOCSIFFLAGS (ifDown)");
159 getNaturalMask(u_long inaddr)
161 if ( isClassA(inaddr) ) {
162 return inet_addr("255.0.0.0");
164 if ( isClassB(inaddr) ) {
165 return inet_addr("255.255.0.0");
167 if ( isClassC(inaddr) ) {
168 return inet_addr("255.255.255.0");
174 getNaturalBcast(u_long inaddr)
176 if ( isClassA(inaddr) ) {
177 return (inaddr & htonl(0xff000000)) | htonl(0x00ffffff);
179 if ( isClassB(inaddr) ) {
180 return (inaddr & htonl(0xffff0000)) | htonl(0x0000ffff);
182 if ( isClassC(inaddr) ) {
183 return (inaddr & htonl(0xffffff00)) | htonl(0x000000ff);
191 saveIfInfo(struct ifinfo *ifbuf)
196 char filename[IFNAMSIZ + 128];
198 /* set up environmet variable on the attached network interface name
200 if ( setenv("DHCP_DEVICE", ifbuf->ifname, 1) < 0 ) {
201 logRet("setenv (saveIfInfo): insufficient space");
204 strcpy(filename, DHCP_CACHE_FILE);
205 strcat(filename, ifbuf->ifname);
206 if ( (fd = creat(filename, 0644)) < 0 ) {
207 logSysRet("creat (saveIfinfo)");
210 if ( write(fd, (const char *)&ifbuf->addr, sizeof(ifbuf->addr)) < 0 ) {
211 logSysRet("write (saveIfinfo)");
214 if ( LeaseTime == INFINITE_LEASE_TIME ) {
215 leaseLeft = INFINITE_LEASE_TIME;
217 leaseLeft = ntohl(LeaseTime) - (time(NULL) - ReqSentTime);
219 if ( write(fd, (const char *)&leaseLeft, sizeof(leaseLeft)) < 0 ) {
220 logSysRet("write (saveIfinfo)");
224 if ( unlink((const char*)filename) < 0 ) {
225 logSysRet("unlink (saveIfinfo)");
234 getIfInfo(struct ifinfo * ifinfo)
239 strcpy(ifr.ifr_name, ifinfo->ifname);
240 if ( (s = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
241 logSysExit("socket (getIfInfo)");
243 if ( ioctl(s, SIOCGIFHWADDR, &ifr) < 0 ) {
244 logSysExit("ioctl SIOCGIFHWADDR (getIfInfo)");
246 if ( ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER ) {
247 logQuit("getIfInfo: interface %s is not Ethernet\n", ifr.ifr_name);
249 /* save hardware address of the interface
251 bcopy(ifr.ifr_hwaddr.sa_data, ifinfo->haddr, sizeof(ifinfo->haddr));
253 /* configure interface
255 if ( ioctl(s, SIOCGIFADDR, &ifr) < 0 ) {
256 logSysExit("ioctl SIOCGIFADDR (getIfInfo)");
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)");
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)");
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)");
270 ifinfo->flags = ifr.ifr_flags;
275 setDefRoute(const char *routers, struct ifinfo *ifinfo)
277 u_long gwAddr; /* router's IP address (network byte order) */
280 struct rtentry rtent;
281 struct sockaddr_in *p;
283 if ( (s = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
284 logSysExit("socket (setDefRoute)");
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;
296 /* verify rouer addresses are correct
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)
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)");
311 /* TODO: also verify if the router is alive
312 * or not by using ping