open-isns: Fix warnings reported by gcc-4.5.2
[open-iscsi.git] / usr / iscsi_net_util.c
blobe801b4891e6e7ef22e59ca2c09a51bc330e30181
1 /*
2 * net helpers
4 * Copyright (C) 2010 Mike Christie
5 * Copyright (C) 2010 Red Hat, Inc. All rights reserved.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published
9 * by the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 #include <stdio.h>
18 #include <string.h>
19 #include <errno.h>
20 #include <net/if.h>
21 #include <unistd.h>
22 #include <netinet/in.h>
23 #include <arpa/inet.h>
24 #include <net/route.h>
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <sys/ioctl.h>
28 #include <sys/socket.h>
29 #include <linux/sockios.h>
31 #include "sysdeps.h"
32 #include "ethtool-copy.h"
33 #include "iscsi_net_util.h"
34 #include "log.h"
36 struct iscsi_net_driver {
37 const char *net_drv_name;
38 const char *iscsi_transport;
41 static struct iscsi_net_driver net_drivers[] = {
42 #ifdef OFFLOAD_BOOT_SUPPORTED
43 {"cxgb3", "cxgb3i" },
44 {"cxgb4", "cxgb4i" },
45 {"bnx2", "bnx2i" },
46 {"bnx2x", "bnx2i"},
47 #endif
48 {NULL, NULL}
51 /**
52 * net_get_transport_name_from_netdev - get name of transport to use for iface
53 * @netdev: netdev iface name
54 * @transport: buffer to hold transport name
56 * transport buffer should be ISCSI_TRANSPORT_NAME_MAXLEN bytes
58 int net_get_transport_name_from_netdev(char *netdev, char *transport)
60 struct ethtool_drvinfo drvinfo;
61 struct ifreq ifr;
62 int err, fd, i;
64 memset(&ifr, 0, sizeof(ifr));
65 strcpy(ifr.ifr_name, netdev);
67 fd = socket(AF_INET, SOCK_DGRAM, 0);
68 if (fd < 0) {
69 log_error("Could not open socket for ioctl.");
70 return errno;
73 drvinfo.cmd = ETHTOOL_GDRVINFO;
74 ifr.ifr_data = (caddr_t)&drvinfo;
75 err = ioctl(fd, SIOCETHTOOL, &ifr);
76 if (err < 0) {
77 log_error("Could not get driver.");
78 err = errno;
79 goto close_sock;
82 for (i = 0; net_drivers[i].net_drv_name != NULL; i++) {
83 struct iscsi_net_driver *net_driver = &net_drivers[i];
85 if (!strcmp(net_driver->net_drv_name, drvinfo.driver)) {
86 strcpy(transport, net_driver->iscsi_transport);
87 err = 0;
88 goto close_sock;
91 err = ENODEV;
93 close_sock:
94 close(fd);
95 return err;
98 /**
99 * net_get_netdev_from_hwaddress - given a hwaddress return the ethX
100 * @hwaddress: hw address no larger than ISCSI_HWADDRESS_BUF_SIZE
101 * @netdev: buffer of IFNAMSIZ size that will hold the ethX
103 * Does not support interfaces like a bond or alias because
104 * multiple interfaces will have the same hwaddress.
106 int net_get_netdev_from_hwaddress(char *hwaddress, char *netdev)
108 struct if_nameindex *ifni;
109 struct ifreq if_hwaddr;
110 int found = 0, sockfd, i = 0;
111 unsigned char *hwaddr;
112 char tmp_hwaddress[ISCSI_HWADDRESS_BUF_SIZE];
114 ifni = if_nameindex();
115 if (ifni == NULL) {
116 log_error("Could not match hwaddress %s to netdev. "
117 "getifaddrs failed %d", hwaddress, errno);
118 return errno;
121 /* Open a basic socket. */
122 sockfd = socket(AF_INET, SOCK_DGRAM, 0);
123 if (sockfd < 0) {
124 log_error("Could not open socket for ioctl.");
125 goto free_ifni;
128 for (i = 0; ifni[i].if_index && ifni[i].if_name; i++) {
129 struct if_nameindex *n = &ifni[i];
131 strlcpy(if_hwaddr.ifr_name, n->if_name, IFNAMSIZ);
132 if (ioctl(sockfd, SIOCGIFHWADDR, &if_hwaddr) < 0) {
133 log_error("Could not match %s to netdevice.",
134 hwaddress);
135 continue;
138 /* check for ARPHRD_ETHER (ethernet) */
139 if (if_hwaddr.ifr_hwaddr.sa_family != 1)
140 continue;
141 hwaddr = (unsigned char *)if_hwaddr.ifr_hwaddr.sa_data;
143 memset(tmp_hwaddress, 0, ISCSI_HWADDRESS_BUF_SIZE);
144 /* TODO should look and covert so we do not need tmp buf */
145 sprintf(tmp_hwaddress, "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
146 hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3],
147 hwaddr[4], hwaddr[5]);
148 log_debug(4, "Found hardware address %s", tmp_hwaddress);
149 if (!strcasecmp(tmp_hwaddress, hwaddress)) {
150 log_debug(4, "Matches %s to %s", hwaddress,
151 n->if_name);
152 memset(netdev, 0, IFNAMSIZ);
153 strlcpy(netdev, n->if_name, IFNAMSIZ);
154 found = 1;
155 break;
159 close(sockfd);
160 free_ifni:
161 if_freenameindex(ifni);
162 if (!found)
163 return ENODEV;
164 return 0;
168 * net_setup_netdev - bring up NIC
169 * @netdev: network device name
170 * @local: ip address for netdev
171 * @mask: net mask
172 * @gateway: gateway
173 * @remote_ip: target portal ip
174 * @needs_bringup: bool indicating if the netdev needs to be started
176 * Bring up required NIC and use routing
177 * to force iSCSI traffic through correct NIC.
179 int net_setup_netdev(char *netdev, char *local_ip, char *mask, char *gateway,
180 char *remote_ip, int needs_bringup)
182 struct sockaddr_in sk_ipaddr = { .sin_family = AF_INET };
183 struct sockaddr_in sk_netmask = { .sin_family = AF_INET };
184 struct sockaddr_in sk_hostmask = { .sin_family = AF_INET };
185 struct sockaddr_in sk_gateway = { .sin_family = AF_INET };
186 struct sockaddr_in sk_tgt_ipaddr = { .sin_family = AF_INET };
187 struct rtentry rt;
188 struct ifreq ifr;
189 int sock;
190 int ret;
192 if (!strlen(netdev)) {
193 log_error("No netdev name in fw entry.\n");
194 return EINVAL;
197 /* Create socket for making networking changes */
198 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
199 log_error("Could not open socket to manage network "
200 "(err %d - %s)", errno, strerror(errno));
201 return errno;
204 /* Bring up NIC with correct address - unless it
205 * has already been handled (2 targets in IBFT may share one NIC)
207 if (!inet_aton(local_ip, &sk_ipaddr.sin_addr)) {
208 log_error("Invalid or missing ipaddr in fw entry\n");
209 ret = EINVAL;
210 goto done;
213 if (!inet_aton(mask, &sk_netmask.sin_addr)) {
214 log_error("Invalid or missing netmask in fw entry\n");
215 ret = EINVAL;
216 goto done;
219 inet_aton("255.255.255.255", &sk_hostmask.sin_addr);
221 if (!inet_aton(remote_ip, &sk_tgt_ipaddr.sin_addr)) {
222 log_error("Invalid or missing target ipaddr in fw entry\n");
223 ret = EINVAL;
224 goto done;
227 /* Only set IP/NM if this is a new interface */
228 if (needs_bringup) {
229 /* TODO: create vlan if strlen(vlan) */
231 /* Bring up interface */
232 memset(&ifr, 0, sizeof(ifr));
233 strncpy(ifr.ifr_name, netdev, IFNAMSIZ);
234 ifr.ifr_flags = IFF_UP | IFF_RUNNING;
235 if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) {
236 log_error("Could not bring up netdev %s (err %d - %s)",
237 netdev, errno, strerror(errno));
238 ret = errno;
239 goto done;
241 /* Set IP address */
242 memset(&ifr, 0, sizeof(ifr));
243 strncpy(ifr.ifr_name, netdev, IFNAMSIZ);
244 memcpy(&ifr.ifr_addr, &sk_ipaddr, sizeof(struct sockaddr));
245 if (ioctl(sock, SIOCSIFADDR, &ifr) < 0) {
246 log_error("Could not set ip for %s (err %d - %s)",
247 netdev, errno, strerror(errno));
248 ret = errno;
249 goto done;
252 /* Set netmask */
253 memset(&ifr, 0, sizeof(ifr));
254 strncpy(ifr.ifr_name, netdev, IFNAMSIZ);
255 memcpy(&ifr.ifr_addr, &sk_netmask, sizeof(struct sockaddr));
256 if (ioctl(sock, SIOCSIFNETMASK, &ifr) < 0) {
257 log_error("Could not set ip for %s (err %d - %s)",
258 netdev, errno, strerror(errno));
259 ret = errno;
260 goto done;
264 /* Set static route to target via this interface */
265 memset((char *) &rt, 0, sizeof(rt));
266 memcpy(&rt.rt_dst, &sk_tgt_ipaddr, sizeof(sk_tgt_ipaddr));
267 memcpy(&rt.rt_genmask, &sk_hostmask, sizeof(sk_hostmask));
268 rt.rt_flags = RTF_UP | RTF_HOST;
269 rt.rt_dev = netdev;
271 if ((sk_tgt_ipaddr.sin_addr.s_addr & sk_netmask.sin_addr.s_addr) ==
272 (sk_ipaddr.sin_addr.s_addr & sk_netmask.sin_addr.s_addr)) {
273 /* Same subnet */
274 if (ioctl(sock, SIOCADDRT, &rt) < 0) {
275 if (errno != EEXIST) {
276 log_error("Could not set ip for %s "
277 "(err %d - %s)", netdev,
278 errno, strerror(errno));
279 ret = errno;
280 goto done;
283 } else {
284 /* Different subnet. Use gateway */
285 rt.rt_flags |= RTF_GATEWAY;
286 if (!inet_aton(gateway, &sk_gateway.sin_addr)) {
287 log_error("Invalid or missing gateway for %s "
288 "(err %d - %s)",
289 netdev, errno, strerror(errno));
290 ret = errno;
291 goto done;
293 memcpy(&rt.rt_gateway, &sk_gateway, sizeof(sk_gateway));
294 if (ioctl(sock, SIOCADDRT, &rt) < 0) {
295 if (errno != EEXIST) {
296 log_error("Could not set gateway for %s "
297 "(err %d - %s)", netdev,
298 errno, strerror(errno));
299 ret = errno;
300 goto done;
304 ret = 0;
306 done:
307 close(sock);
308 return ret;