libsodium: Needed for Dnscrypto-proxy Release 1.3.0
[tomato.git] / release / src / router / rc / interface.c
blobd5dd2b082f481cf3f97e5d9f83b5771392888186
1 /*
2 * Linux network interface code
4 * Copyright 2005, Broadcom Corporation
5 * All Rights Reserved.
6 *
7 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
8 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
9 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
10 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
12 * $Id: interface.c,v 1.13 2005/03/07 08:35:32 kanki Exp $
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <ctype.h>
18 #include <errno.h>
19 #include <error.h>
20 #include <string.h>
21 #include <unistd.h>
22 #include <sys/ioctl.h>
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <net/route.h>
26 #include <netinet/in.h>
27 #include <arpa/inet.h>
28 #include <net/if_arp.h>
29 #include <proto/ethernet.h>
31 #include <shutils.h>
32 #include <bcmnvram.h>
33 #include <bcmutils.h>
34 #include <bcmparams.h>
35 #include <bcmdevs.h>
36 #include <shared.h>
38 #include "rc.h"
40 int _ifconfig(const char *name, int flags, const char *addr, const char *netmask, const char *dstaddr)
42 int s;
43 struct ifreq ifr;
44 struct in_addr in_addr, in_netmask, in_broadaddr;
46 _dprintf("%s: name=%s flags=%s addr=%s netmask=%s\n", __FUNCTION__, name, flags == IFUP ? "IFUP" : "0", addr, netmask);
48 /* Open a raw socket to the kernel */
49 if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) return errno;
51 /* Set interface name */
52 strlcpy(ifr.ifr_name, name, IFNAMSIZ);
54 /* Set interface flags */
55 ifr.ifr_flags = flags;
56 if (ioctl(s, SIOCSIFFLAGS, &ifr) < 0)
57 goto ERROR;
59 /* Set IP address */
60 if (addr) {
61 inet_aton(addr, &in_addr);
62 sin_addr(&ifr.ifr_addr).s_addr = in_addr.s_addr;
63 ifr.ifr_addr.sa_family = AF_INET;
64 if (ioctl(s, SIOCSIFADDR, &ifr) < 0)
65 goto ERROR;
68 /* Set IP netmask and broadcast */
69 if (addr && netmask) {
70 inet_aton(netmask, &in_netmask);
71 sin_addr(&ifr.ifr_netmask).s_addr = in_netmask.s_addr;
72 ifr.ifr_netmask.sa_family = AF_INET;
73 if (ioctl(s, SIOCSIFNETMASK, &ifr) < 0)
74 goto ERROR;
76 in_broadaddr.s_addr = (in_addr.s_addr & in_netmask.s_addr) | ~in_netmask.s_addr;
77 sin_addr(&ifr.ifr_broadaddr).s_addr = in_broadaddr.s_addr;
78 ifr.ifr_broadaddr.sa_family = AF_INET;
79 if (ioctl(s, SIOCSIFBRDADDR, &ifr) < 0)
80 goto ERROR;
83 /* Set dst or P-t-P IP address */
84 if (dstaddr) {
85 inet_aton(dstaddr, &in_addr);
86 sin_addr(&ifr.ifr_dstaddr).s_addr = in_addr.s_addr;
87 ifr.ifr_dstaddr.sa_family = AF_INET;
88 if (ioctl(s, SIOCSIFDSTADDR, &ifr) < 0)
89 goto ERROR;
92 close(s);
93 return 0;
95 ERROR:
96 close(s);
97 perror(name);
98 return errno;
101 static int route_manip(int cmd, char *name, int metric, char *dst, char *gateway, char *genmask)
103 int s;
104 struct rtentry rt;
106 _dprintf("%s: cmd=%s name=%s addr=%s netmask=%s gateway=%s metric=%d\n",
107 __FUNCTION__, cmd == SIOCADDRT ? "ADD" : "DEL", name, dst, genmask, gateway, metric);
109 /* Open a raw socket to the kernel */
110 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) return errno;
112 /* Fill in rtentry */
113 memset(&rt, 0, sizeof(rt));
114 if (dst)
115 inet_aton(dst, &sin_addr(&rt.rt_dst));
116 if (gateway)
117 inet_aton(gateway, &sin_addr(&rt.rt_gateway));
118 if (genmask)
119 inet_aton(genmask, &sin_addr(&rt.rt_genmask));
120 rt.rt_metric = metric;
121 rt.rt_flags = RTF_UP;
122 if (sin_addr(&rt.rt_gateway).s_addr)
123 rt.rt_flags |= RTF_GATEWAY;
124 if (sin_addr(&rt.rt_genmask).s_addr == INADDR_BROADCAST)
125 rt.rt_flags |= RTF_HOST;
126 rt.rt_dev = name;
128 /* Force address family to AF_INET */
129 rt.rt_dst.sa_family = AF_INET;
130 rt.rt_gateway.sa_family = AF_INET;
131 rt.rt_genmask.sa_family = AF_INET;
133 if (ioctl(s, cmd, &rt) < 0) {
134 perror(name);
135 close(s);
136 return errno;
139 close(s);
140 return 0;
144 int route_add(char *name, int metric, char *dst, char *gateway, char *genmask)
146 return route_manip(SIOCADDRT, name, metric + 1, dst, gateway, genmask);
149 void route_del(char *name, int metric, char *dst, char *gateway, char *genmask)
151 while (route_manip(SIOCDELRT, name, metric + 1, dst, gateway, genmask) == 0) {
156 /* configure loopback interface */
157 void config_loopback(void)
159 /* Bring up loopback interface */
160 ifconfig("lo", IFUP, "127.0.0.1", "255.0.0.0");
162 /* Add to routing table */
163 route_add("lo", 0, "127.0.0.0", "0.0.0.0", "255.0.0.0");
166 #ifdef TCONFIG_IPV6
167 int ipv6_mapaddr4(struct in6_addr *addr6, int ip6len, struct in_addr *addr4, int ip4mask)
169 int i = ip6len >> 5;
170 int m = ip6len & 0x1f;
171 int ret = ip6len + 32 - ip4mask;
172 u_int32_t addr = 0;
173 u_int32_t mask = 0xffffffffUL << ip4mask;
175 if (ip6len > 128 || ip4mask > 32 || ret > 128)
176 return 0;
177 if (ip4mask == 32)
178 return ret;
180 if (addr4)
181 addr = ntohl(addr4->s_addr) << ip4mask;
183 addr6->s6_addr32[i] &= ~htonl(mask >> m);
184 addr6->s6_addr32[i] |= htonl(addr >> m);
185 if (m) {
186 i++;
187 addr6->s6_addr32[i] &= ~htonl(mask << (32 - m));
188 addr6->s6_addr32[i] |= htonl(addr << (32 - m));
191 return ret;
193 #endif
195 /* configure/start vlan interface(s) based on nvram settings */
196 int start_vlan(void)
198 int s;
199 struct ifreq ifr;
200 int i, j, vlan0tag;
201 char ea[ETHER_ADDR_LEN];
203 if ((strtoul(nvram_safe_get("boardflags"), NULL, 0) & BFL_ENETVLAN) == 0) return 0;
205 /* set vlan i/f name to style "vlan<ID>" */
206 eval("vconfig", "set_name_type", "VLAN_PLUS_VID_NO_PAD");
208 /* create vlan interfaces */
209 if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
210 return errno;
212 vlan0tag = nvram_get_int("vlan0tag");
214 for (i = 0; i <= VLAN_MAXVID; i ++) {
215 char nvvar_name[16];
216 char vlan_id[16];
217 char *hwname, *hwaddr;
218 char prio[8];
219 int vid_map;
221 /* get the address of the EMAC on which the VLAN sits */
222 snprintf(nvvar_name, sizeof(nvvar_name), "vlan%dhwname", i);
223 if (!(hwname = nvram_get(nvvar_name)))
224 continue;
225 snprintf(nvvar_name, sizeof(nvvar_name), "%smacaddr", hwname);
226 if (!(hwaddr = nvram_get(nvvar_name)))
227 continue;
228 ether_atoe(hwaddr, ea);
229 /* find the interface name to which the address is assigned */
230 for (j = 1; j <= DEV_NUMIFS; j ++) {
231 ifr.ifr_ifindex = j;
232 if (ioctl(s, SIOCGIFNAME, &ifr))
233 continue;
234 if (ioctl(s, SIOCGIFHWADDR, &ifr))
235 continue;
236 if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER)
237 continue;
238 if (!bcmp(ifr.ifr_hwaddr.sa_data, ea, ETHER_ADDR_LEN))
239 break;
241 if (j > DEV_NUMIFS)
242 continue;
243 if (ioctl(s, SIOCGIFFLAGS, &ifr))
244 continue;
245 if (!(ifr.ifr_flags & IFF_UP))
246 ifconfig(ifr.ifr_name, IFUP, 0, 0);
248 /* vlan ID mapping */
249 snprintf(nvvar_name, sizeof(nvvar_name), "vlan%dvid", i);
250 vid_map = nvram_get_int(nvvar_name);
251 if ((vid_map < 1) || (vid_map > 4094)) vid_map = vlan0tag | i;
253 /* create the VLAN interface */
254 snprintf(vlan_id, sizeof(vlan_id), "%d", vid_map);
255 eval("vconfig", "add", ifr.ifr_name, vlan_id);
256 /* setup ingress map (vlan->priority => skb->priority) */
257 snprintf(vlan_id, sizeof(vlan_id), "vlan%d", vid_map);
258 for (j = 0; j < VLAN_NUMPRIS; j ++) {
259 snprintf(prio, sizeof(prio), "%d", j);
260 eval("vconfig", "set_ingress_map", vlan_id, prio, prio);
264 close(s);
266 return 0;
269 /* stop/rem vlan interface(s) based on nvram settings */
270 int stop_vlan(void)
272 int i;
273 int vlan0tag, vid_map;
274 char nvvar_name[16];
275 char vlan_id[16];
276 char *hwname;
278 if ((strtoul(nvram_safe_get("boardflags"), NULL, 0) & BFL_ENETVLAN) == 0) return 0;
280 vlan0tag = nvram_get_int("vlan0tag");
282 for (i = 0; i <= VLAN_MAXVID; i ++) {
283 /* get the address of the EMAC on which the VLAN sits */
284 snprintf(nvvar_name, sizeof(nvvar_name), "vlan%dhwname", i);
285 if (!(hwname = nvram_get(nvvar_name)))
286 continue;
288 /* vlan ID mapping */
289 snprintf(nvvar_name, sizeof(nvvar_name), "vlan%dvid", i);
290 vid_map = nvram_get_int(nvvar_name);
291 if ((vid_map < 1) || (vid_map > 4094)) vid_map = vlan0tag | i;
293 /* remove the VLAN interface */
294 snprintf(vlan_id, sizeof(vlan_id), "vlan%d", vid_map);
295 eval("vconfig", "rem", vlan_id);
298 return 0;