1/* 2 * Linux network interface code 3 * 4 * Copyright (C) 2013, Broadcom Corporation. All Rights Reserved. 5 * 6 * Permission to use, copy, modify, and/or distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 13 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 15 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 * 18 * $Id: interface.c 291523 2011-10-24 06:12:27Z $ 19 */ 20 21#include <stdio.h> 22#include <stdlib.h> 23#include <ctype.h> 24#include <errno.h> 25#include <error.h> 26#include <string.h> 27#include <unistd.h> 28#include <sys/ioctl.h> 29#include <sys/types.h> 30#include <sys/socket.h> 31#include <linux/route.h> 32#include <linux/if.h> 33#include <netinet/in.h> 34#include <arpa/inet.h> 35#include <net/if_arp.h> 36#include <proto/ethernet.h> 37#include <shutils.h> 38#include <bcmnvram.h> 39#include <bcmutils.h> 40#include <bcmparams.h> 41#include <rc.h> 42 43int 44ifconfig(char *name, int flags, char *addr, char *netmask) 45{ 46 int s; 47 struct ifreq ifr; 48 struct in_addr in_addr, in_netmask, in_broadaddr; 49 50 /* Open a raw socket to the kernel */ 51 if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) 52 goto err; 53 54 /* Set interface name */ 55 strncpy(ifr.ifr_name, name, IFNAMSIZ); 56 57 /* Set interface flags */ 58 ifr.ifr_flags = flags; 59 if (ioctl(s, SIOCSIFFLAGS, &ifr) < 0) 60 goto err; 61 62 /* Set IP address */ 63 if (addr) { 64 inet_aton(addr, &in_addr); 65 sin_addr(&ifr.ifr_addr).s_addr = in_addr.s_addr; 66 ifr.ifr_addr.sa_family = AF_INET; 67 if (ioctl(s, SIOCSIFADDR, &ifr) < 0) 68 goto err; 69 } 70 71 /* Set IP netmask and broadcast */ 72 if (addr && netmask) { 73 inet_aton(netmask, &in_netmask); 74 sin_addr(&ifr.ifr_netmask).s_addr = in_netmask.s_addr; 75 ifr.ifr_netmask.sa_family = AF_INET; 76 if (ioctl(s, SIOCSIFNETMASK, &ifr) < 0) 77 goto err; 78 79 in_broadaddr.s_addr = (in_addr.s_addr & in_netmask.s_addr) | ~in_netmask.s_addr; 80 sin_addr(&ifr.ifr_broadaddr).s_addr = in_broadaddr.s_addr; 81 ifr.ifr_broadaddr.sa_family = AF_INET; 82 if (ioctl(s, SIOCSIFBRDADDR, &ifr) < 0) 83 goto err; 84 } 85 86 close(s); 87 88 return 0; 89 90err: 91 close(s); 92 perror(name); 93 return errno; 94} 95 96int 97ifconfig_get(char *name, int *flags, unsigned long *addr, unsigned long *netmask) 98{ 99 int s; 100 struct ifreq ifr; 101 102 /* Open a raw socket to the kernel */ 103 if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) 104 goto err; 105 106 /* Set interface name */ 107 strncpy(ifr.ifr_name, name, IFNAMSIZ); 108 109 /* Check MAC first */ 110 if (ioctl(s, SIOCGIFHWADDR, &ifr) < 0) 111 goto err; 112 else if (memcmp(ifr.ifr_hwaddr.sa_data, "\0\0\0\0\0\0", 6) == 0) 113 goto err; 114 115 /* Get interface flags */ 116 if (flags) { 117 if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) 118 goto err; 119 else 120 memcpy(flags, &(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr), 121 sizeof(*flags)); 122 } 123 124 /* Get IP address */ 125 if (addr) { 126 if (ioctl(s, SIOCGIFADDR, &ifr) < 0) 127 goto err; 128 else 129 memcpy(addr, &(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr), 130 sizeof(*addr)); 131 } 132 133 /* Get Net mask */ 134 if (netmask) { 135 if (ioctl(s, SIOCGIFNETMASK, &ifr) < 0) 136 goto err; 137 else { 138 memcpy(netmask, &(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr), 139 sizeof(*netmask)); 140 } 141 } 142 143 close(s); 144 145 return 0; 146 147err: 148 close(s); 149 perror(name); 150 return errno; 151} 152 153static int 154route_manip(int cmd, char *name, int metric, char *dst, char *gateway, char *genmask) 155{ 156 int s; 157 struct rtentry rt; 158 159 /* Open a raw socket to the kernel */ 160 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 161 goto err; 162 163 /* Fill in rtentry */ 164 memset(&rt, 0, sizeof(rt)); 165 if (dst) 166 inet_aton(dst, &sin_addr(&rt.rt_dst)); 167 if (gateway) 168 inet_aton(gateway, &sin_addr(&rt.rt_gateway)); 169 if (genmask) 170 inet_aton(genmask, &sin_addr(&rt.rt_genmask)); 171 rt.rt_metric = metric; 172 rt.rt_flags = RTF_UP; 173 if (sin_addr(&rt.rt_gateway).s_addr) 174 rt.rt_flags |= RTF_GATEWAY; 175 if (sin_addr(&rt.rt_genmask).s_addr == INADDR_BROADCAST) 176 rt.rt_flags |= RTF_HOST; 177 rt.rt_dev = name; 178 179 /* Force address family to AF_INET */ 180 rt.rt_dst.sa_family = AF_INET; 181 rt.rt_gateway.sa_family = AF_INET; 182 rt.rt_genmask.sa_family = AF_INET; 183 184 if (ioctl(s, cmd, &rt) < 0) 185 goto err; 186 187 close(s); 188 return 0; 189 190err: 191 close(s); 192 perror(name); 193 return errno; 194} 195 196int 197route_add(char *name, int metric, char *dst, char *gateway, char *genmask) 198{ 199 return route_manip(SIOCADDRT, name, metric, dst, gateway, genmask); 200} 201 202int 203route_del(char *name, int metric, char *dst, char *gateway, char *genmask) 204{ 205 return route_manip(SIOCDELRT, name, metric, dst, gateway, genmask); 206} 207 208/* configure loopback interface */ 209void 210config_loopback(void) 211{ 212 /* Bring up loopback interface */ 213 ifconfig("lo", IFUP, "127.0.0.1", "255.0.0.0"); 214 215 /* Add to routing table */ 216 route_add("lo", 0, "127.0.0.0", "0.0.0.0", "255.0.0.0"); 217} 218 219/* configure/start vlan interface(s) based on nvram settings */ 220int 221start_vlan(void) 222{ 223 int s; 224 struct ifreq ifr; 225 int i, j; 226 unsigned char ea[ETHER_ADDR_LEN]; 227 char buf[256]; 228 229 230 231 /* Bob added start, 09/03/2009, to avoid sending router solicitation packets */ 232#ifdef INCLUDE_IPV6 233 system("echo 0 > /proc/sys/net/ipv6/conf/all/router_solicitations"); 234 system("echo 0 > /proc/sys/net/ipv6/conf/default/router_solicitations"); // pling added 08/16/2010 235#endif 236 /* Bob added end, 09/03/2009, to avoid sending router solicitation packets */ 237 238 /* set vlan i/f name to style "vlan<ID>" */ 239 eval("vconfig", "set_name_type", "VLAN_PLUS_VID_NO_PAD"); 240 241 /* create vlan interfaces */ 242 if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) 243 return errno; 244 245 for (i = 0; i <= VLAN_MAXVID; i ++) 246 { 247 char nvvar_name[16]; 248 char vlan_id[16]; 249 char *hwname, *hwaddr; 250 char prio[8]; 251 252 /* get the address of the EMAC on which the VLAN sits */ 253 snprintf(nvvar_name, sizeof(nvvar_name), "vlan%dhwname", i); 254 if (!(hwname = nvram_get(nvvar_name))) 255 continue; 256 snprintf(nvvar_name, sizeof(nvvar_name), "%smacaddr", hwname); 257 if (!(hwaddr = nvram_get(nvvar_name))) 258 continue; 259 ether_atoe(hwaddr, ea); 260 /* find the interface name to which the address is assigned */ 261 for (j = 1; j <= DEV_NUMIFS; j ++) { 262 ifr.ifr_ifindex = j; 263 if (ioctl(s, SIOCGIFNAME, &ifr)) 264 continue; 265 if (ioctl(s, SIOCGIFHWADDR, &ifr)) 266 continue; 267 if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) 268 continue; 269 if (!bcmp(ifr.ifr_hwaddr.sa_data, ea, ETHER_ADDR_LEN)) 270 break; 271 } 272 if (j > DEV_NUMIFS) 273 continue; 274 if (ioctl(s, SIOCGIFFLAGS, &ifr)) 275 continue; 276 277 /* Bob added start, 09/03/2009, to avoid sending router solicitation packets */ 278#ifdef INCLUDE_IPV6 279 sprintf(buf, "echo 0 > /proc/sys/net/ipv6/conf/%s/router_solicitations", ifr.ifr_name); 280 system(buf); 281#endif 282 /* Bob added end, 09/03/2009, to avoid sending router solicitation packets */ 283 284 if (!(ifr.ifr_flags & IFF_UP)) 285 ifconfig(ifr.ifr_name, IFUP, 0, 0); 286 /* create the VLAN interface */ 287 snprintf(vlan_id, sizeof(vlan_id), "%d", i); 288 eval("vconfig", "add", ifr.ifr_name, vlan_id); 289 /* setup ingress map (vlan->priority => skb->priority) */ 290 snprintf(vlan_id, sizeof(vlan_id), "vlan%d", i); 291 /* Bob added start, 09/03/2009, to avoid sending router solicitation packets */ 292#ifdef INCLUDE_IPV6 293 sprintf(buf, "echo 0 > /proc/sys/net/ipv6/conf/%s/router_solicitations", vlan_id); 294 system(buf); 295#endif 296 /* Bob added end, 09/03/2009, to avoid sending router solicitation packets */ 297 for (j = 0; j < VLAN_NUMPRIS; j ++) { 298 snprintf(prio, sizeof(prio), "%d", j); 299 eval("vconfig", "set_ingress_map", vlan_id, prio, prio); 300 } 301 } 302 303 /* Bob added start 09/03/2009 */ 304#ifdef INCLUDE_IPV6 305 if (nvram_match("ipv6ready", "1")) 306 { 307 char cmd[32]; 308 sprintf(cmd, "ifconfig vlan1 hw ether %s", nvram_get("lan_hwaddr")); 309 system(cmd); 310 } 311#endif 312 /* Bob added end 09/03/2009 */ 313 314 close(s); 315 316 return 0; 317} 318 319/* stop/rem vlan interface(s) based on nvram settings */ 320int 321stop_vlan(void) 322{ 323 int i; 324 char nvvar_name[16]; 325 char vlan_id[16]; 326 char *hwname; 327 328 for (i = 0; i <= VLAN_MAXVID; i ++) { 329 /* get the address of the EMAC on which the VLAN sits */ 330 snprintf(nvvar_name, sizeof(nvvar_name), "vlan%dhwname", i); 331 if (!(hwname = nvram_get(nvvar_name))) 332 continue; 333 334 /* remove the VLAN interface */ 335 snprintf(vlan_id, sizeof(vlan_id), "vlan%d", i); 336 eval("vconfig", "rem", vlan_id); 337 } 338 339 return 0; 340} 341