/* Attach a VLAN device to a mac address (ie Ethernet Card). * Returns the device that was created, or NULL if there was * an error of some kind. */ static struct net_device *register_vlan_device(const char *eth_IF_name, unsigned short VLAN_ID) { struct vlan_group *grp, *ngrp = NULL; struct net_device *new_dev; struct net_device *real_dev; /* the ethernet device */ char name[IFNAMSIZ]; #ifdef VLAN_DEBUG printk(VLAN_DBG "%s: if_name -:%s:- vid: %i\n", __FUNCTION__, eth_IF_name, VLAN_ID); #endif if (VLAN_ID >= VLAN_VID_MASK) goto out_ret_null; /* find the device relating to eth_IF_name. */ real_dev = dev_get_by_name(eth_IF_name); if (!real_dev) goto out_ret_null; if (real_dev->features & NETIF_F_VLAN_CHALLENGED) { printk(VLAN_DBG "%s: VLANs not supported on %s.\n", __FUNCTION__, real_dev->name); goto out_put_dev; } if ((real_dev->features & NETIF_F_HW_VLAN_RX) && (real_dev->vlan_rx_register == NULL || real_dev->vlan_rx_kill_vid == NULL)) { printk(VLAN_DBG "%s: Device %s has buggy VLAN hw accel.\n", __FUNCTION__, real_dev->name); goto out_put_dev; } if ((real_dev->features & NETIF_F_HW_VLAN_FILTER) && (real_dev->vlan_rx_add_vid == NULL || real_dev->vlan_rx_kill_vid == NULL)) { printk(VLAN_DBG "%s: Device %s has buggy VLAN hw accel.\n", __FUNCTION__, real_dev->name); goto out_put_dev; } /* From this point on, all the data structures must remain * consistent. */ rtnl_lock(); /* The real device must be up and operating in order to * assosciate a VLAN device with it. */ if (!(real_dev->flags & IFF_UP)) goto out_unlock; if (find_vlan_dev(real_dev, VLAN_ID) != NULL) { /* was already registered. */ printk(VLAN_DBG "%s: ALREADY had VLAN registered\n", __FUNCTION__); goto out_unlock; } /* Gotta set up the fields for the device. */ #ifdef VLAN_DEBUG printk(VLAN_DBG "About to allocate name, vlan_name_type: %i\n", vlan_name_type); #endif switch (vlan_name_type) { case VLAN_NAME_TYPE_RAW_PLUS_VID: /* name will look like: eth1.0005 */ snprintf(name, IFNAMSIZ, "%s.%.4i", real_dev->name, VLAN_ID); break; case VLAN_NAME_TYPE_PLUS_VID_NO_PAD: /* Put our vlan.VID in the name. * Name will look like: vlan5 */ snprintf(name, IFNAMSIZ, "vlan%i", VLAN_ID); break; case VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD: /* Put our vlan.VID in the name. * Name will look like: eth0.5 */ snprintf(name, IFNAMSIZ, "%s.%i", real_dev->name, VLAN_ID); break; case VLAN_NAME_TYPE_PLUS_VID: /* Put our vlan.VID in the name. * Name will look like: vlan0005 */ default: snprintf(name, IFNAMSIZ, "vlan%.4i", VLAN_ID); }; new_dev = alloc_netdev(sizeof(struct vlan_dev_info), name, vlan_setup); if (new_dev == NULL) goto out_unlock; /* need 4 bytes for extra VLAN header info, * hope the underlying device can handle it. */ new_dev->mtu = real_dev->mtu; #ifdef VLAN_DEBUG printk(VLAN_DBG "Allocated new name -:%s:-\n", new_dev->name); VLAN_MEM_DBG("new_dev->priv malloc, addr: %p size: %i\n", new_dev->priv, sizeof(struct vlan_dev_info)); #endif memcpy(new_dev->broadcast, real_dev->broadcast, real_dev->addr_len); memcpy(new_dev->dev_addr, real_dev->dev_addr, real_dev->addr_len); new_dev->addr_len = real_dev->addr_len; if (real_dev->features & NETIF_F_HW_VLAN_TX) { new_dev->hard_header = real_dev->hard_header; new_dev->hard_start_xmit = vlan_dev_hwaccel_hard_start_xmit; new_dev->rebuild_header = real_dev->rebuild_header; } else { new_dev->hard_header = vlan_dev_hard_header; new_dev->hard_start_xmit = vlan_dev_hard_start_xmit; new_dev->rebuild_header = vlan_dev_rebuild_header; } new_dev->hard_header_parse = real_dev->hard_header_parse; VLAN_DEV_INFO(new_dev)->vlan_id = VLAN_ID; /* 1 through VLAN_VID_MASK */ VLAN_DEV_INFO(new_dev)->real_dev = real_dev; VLAN_DEV_INFO(new_dev)->dent = NULL; VLAN_DEV_INFO(new_dev)->flags = 1; #ifdef VLAN_DEBUG printk(VLAN_DBG "About to go find the group for idx: %i\n", real_dev->ifindex); #endif grp = vlan_find_group(real_dev->ifindex); if (!grp) { ngrp = grp = vlan_group_alloc(real_dev->ifindex); if (!grp) goto out_free_newdev; } if (register_netdevice(new_dev)) goto out_free_group; vlan_transfer_operstate(real_dev, new_dev); linkwatch_fire_event(new_dev); /* _MUST_ call rfc2863_policy() */ /* So, got the sucker initialized, now lets place * it into our local structure. */ if (ngrp && real_dev->features & NETIF_F_HW_VLAN_RX) real_dev->vlan_rx_register(real_dev, ngrp); vlan_group_set_device(grp, VLAN_ID, new_dev); if (vlan_proc_add_dev(new_dev)<0)/* create it's proc entry */ printk(KERN_WARNING "VLAN: failed to add proc entry for %s\n", new_dev->name); if (real_dev->features & NETIF_F_HW_VLAN_FILTER) real_dev->vlan_rx_add_vid(real_dev, VLAN_ID); rtnl_unlock(); #ifdef VLAN_DEBUG printk(VLAN_DBG "Allocated new device successfully, returning.\n"); #endif return new_dev; out_free_group: if (ngrp) vlan_group_free(ngrp); out_free_newdev: free_netdev(new_dev); out_unlock: rtnl_unlock(); out_put_dev: dev_put(real_dev); out_ret_null: return NULL; }
/** * net_setup_netdev - bring up NIC * @netdev: network device name * @local: ip address for netdev * @mask: net mask * @gateway: gateway * @remote_ip: target portal ip * @needs_bringup: bool indicating if the netdev needs to be started * * Bring up required NIC and use routing * to force iSCSI traffic through correct NIC. */ int net_setup_netdev(char *netdev, char *local_ip, char *mask, char *gateway, char *vlan, char *remote_ip, int needs_bringup) { struct sockaddr_in sk_ipaddr = { .sin_family = AF_INET }; struct sockaddr_in sk_netmask = { .sin_family = AF_INET }; struct sockaddr_in sk_hostmask = { .sin_family = AF_INET }; struct sockaddr_in sk_gateway = { .sin_family = AF_INET }; struct sockaddr_in sk_tgt_ipaddr = { .sin_family = AF_INET }; struct rtentry rt; struct ifreq ifr; char *physdev = NULL; int sock; int ret; int vlan_id; if (!strlen(netdev)) { log_error("No netdev name in fw entry."); return EINVAL; } vlan_id = atoi(vlan); if (vlan_id != 0) { physdev = netdev; netdev = find_vlan_dev(physdev, vlan_id); } if (vlan_id && !netdev) { /* TODO: create vlan if not found */ log_error("No matching vlan found for fw entry."); return EINVAL; } /* Create socket for making networking changes */ if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { log_error("Could not open socket to manage network " "(err %d - %s)", errno, strerror(errno)); return errno; } /* Bring up NIC with correct address - unless it * has already been handled (2 targets in IBFT may share one NIC) */ if (!inet_aton(local_ip, &sk_ipaddr.sin_addr)) { log_error("Invalid or missing ipaddr in fw entry"); ret = EINVAL; goto done; } if (!inet_aton(mask, &sk_netmask.sin_addr)) { log_error("Invalid or missing netmask in fw entry"); ret = EINVAL; goto done; } inet_aton("255.255.255.255", &sk_hostmask.sin_addr); if (!inet_aton(remote_ip, &sk_tgt_ipaddr.sin_addr)) { log_error("Invalid or missing target ipaddr in fw entry"); ret = EINVAL; goto done; } /* Only set IP/NM if this is a new interface */ if (needs_bringup) { if (physdev) { /* Bring up interface */ memset(&ifr, 0, sizeof(ifr)); strlcpy(ifr.ifr_name, physdev, IFNAMSIZ); ifr.ifr_flags = IFF_UP | IFF_RUNNING; if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) { log_error("Could not bring up netdev %s (err %d - %s)", physdev, errno, strerror(errno)); ret = errno; goto done; } } /* Bring up interface */ memset(&ifr, 0, sizeof(ifr)); strlcpy(ifr.ifr_name, netdev, IFNAMSIZ); ifr.ifr_flags = IFF_UP | IFF_RUNNING; if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) { log_error("Could not bring up netdev %s (err %d - %s)", netdev, errno, strerror(errno)); ret = errno; goto done; } /* Set IP address */ memset(&ifr, 0, sizeof(ifr)); strlcpy(ifr.ifr_name, netdev, IFNAMSIZ); memcpy(&ifr.ifr_addr, &sk_ipaddr, sizeof(struct sockaddr)); if (ioctl(sock, SIOCSIFADDR, &ifr) < 0) { log_error("Could not set ip for %s (err %d - %s)", netdev, errno, strerror(errno)); ret = errno; goto done; } /* Set netmask */ memset(&ifr, 0, sizeof(ifr)); strlcpy(ifr.ifr_name, netdev, IFNAMSIZ); memcpy(&ifr.ifr_addr, &sk_netmask, sizeof(struct sockaddr)); if (ioctl(sock, SIOCSIFNETMASK, &ifr) < 0) { log_error("Could not set ip for %s (err %d - %s)", netdev, errno, strerror(errno)); ret = errno; goto done; } } /* Set static route to target via this interface */ memset((char *) &rt, 0, sizeof(rt)); memcpy(&rt.rt_dst, &sk_tgt_ipaddr, sizeof(sk_tgt_ipaddr)); memcpy(&rt.rt_genmask, &sk_hostmask, sizeof(sk_hostmask)); rt.rt_flags = RTF_UP | RTF_HOST; rt.rt_dev = netdev; if ((sk_tgt_ipaddr.sin_addr.s_addr & sk_netmask.sin_addr.s_addr) == (sk_ipaddr.sin_addr.s_addr & sk_netmask.sin_addr.s_addr)) { /* Same subnet */ if (ioctl(sock, SIOCADDRT, &rt) < 0) { if (errno != EEXIST) { log_error("Could not set ip for %s " "(err %d - %s)", netdev, errno, strerror(errno)); ret = errno; goto done; } } } else { /* Different subnet. Use gateway */ rt.rt_flags |= RTF_GATEWAY; if (!inet_aton(gateway, &sk_gateway.sin_addr)) { log_error("Invalid or missing gateway for %s " "(err %d - %s)", netdev, errno, strerror(errno)); ret = errno; goto done; } memcpy(&rt.rt_gateway, &sk_gateway, sizeof(sk_gateway)); if (ioctl(sock, SIOCADDRT, &rt) < 0) { if (errno != EEXIST) { log_error("Could not set gateway for %s " "(err %d - %s)", netdev, errno, strerror(errno)); ret = errno; goto done; } } } ret = 0; done: close(sock); if (vlan_id) free(netdev); return ret; }