All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ben Greear <greearb@candelatech.com>
To: samba-technical@lists.samba.org,
	linux-kernel <linux-kernel@vger.kernel.org>
Subject: PATCH:  Enable binding to local IPv4 IP address for CIFS file system.
Date: Tue, 01 Aug 2006 10:30:55 -0700	[thread overview]
Message-ID: <44CF8FCF.6070401@candelatech.com> (raw)

This patch provides the ability to bind to a local IP address when
mounting CIFS file systems.  This allows better specification of which
interface a mount may use on a multi-homed machine, for instance.

The corresponding patch for mount.cifs has already been sent to the
samba mailing list.

Please consider this for 2.6.19.

Signed-off-by:  Ben Greear <greearb@candelatech.com>



diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 006eb33..1f34c3f 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -118,6 +118,7 @@ struct TCP_Server_Info {
  		struct sockaddr_in sockAddr;
  		struct sockaddr_in6 sockAddr6;
  	} addr;
+	u32 ip4_local_ip; /* if != 0, will bind locally to this IP */
  	wait_queue_head_t response_q;
  	wait_queue_head_t request_q; /* if more than maxmpx to srvr must block*/
  	struct list_head pending_mid_q;
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index bae1479..1b4b0c1 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -94,13 +94,15 @@ struct smb_vol {
  	unsigned int rsize;
  	unsigned int wsize;
  	unsigned int sockopt;
+	u32 local_ip; /* allow binding to a local IP address if != 0 */
  	unsigned short int port;
  };

  static int ipv4_connect(struct sockaddr_in *psin_server,
  			struct socket **csocket,
  			char * netb_name,
-			char * server_netb_name);
+			char * server_netb_name,
+			u32 local_ip);
  static int ipv6_connect(struct sockaddr_in6 *psin_server,
  			struct socket **csocket);

@@ -194,7 +196,8 @@ cifs_reconnect(struct TCP_Server_Info *s
  			rc = ipv4_connect(&server->addr.sockAddr,
  					&server->ssocket,
  					server->workstation_RFC1001_name,
-					server->server_RFC1001_name);
+					  server->server_RFC1001_name,
+					  server->ip4_local_ip);
  		}
  		if(rc) {
  			cFYI(1,("reconnect error %d",rc));
@@ -983,6 +986,18 @@ cifs_parse_mount_options(char *options,
  				printk(KERN_WARNING "CIFS: domain name too long\n");
  				return 1;
  			}
+		} else if (strnicmp(data, "local_ip", 8) == 0) {
+			if (!value || !*value) {
+				printk(KERN_WARNING "CIFS: local_ip value not specified.\n");
+				return 1;	/* needs_arg; */
+			}
+			i = cifs_inet_pton(AF_INET, value, &(vol->local_ip));
+			if (i < 0) {
+				vol->local_ip = 0;
+				printk(KERN_WARNING "CIFS:  Could not parse local_ip: %s\n",
+				       value);
+				return 1;
+			}
  		} else if (strnicmp(data, "iocharset", 9) == 0) {
  			if (!value || !*value) {
  				printk(KERN_WARNING "CIFS: invalid iocharset specified\n");
@@ -1217,7 +1232,8 @@ cifs_parse_mount_options(char *options,
  static struct cifsSesInfo *
  cifs_find_tcp_session(struct in_addr * target_ip_addr,
  		struct in6_addr *target_ip6_addr,
-		 char *userName, struct TCP_Server_Info **psrvTcp)
+		      char *userName, struct TCP_Server_Info **psrvTcp,
+		      u32 local_ip)
  {
  	struct list_head *tmp;
  	struct cifsSesInfo *ses;
@@ -1227,7 +1243,11 @@ cifs_find_tcp_session(struct in_addr * t
  	list_for_each(tmp, &GlobalSMBSessionList) {
  		ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
  		if (ses->server) {
-			if((target_ip_addr &&
+			if((target_ip_addr &&
+			    /* If binding to a local IP, do not re-use sessions bound to different
+			     * local IP addresses.
+			     */
+			    (local_ip == ses->server->ip4_local_ip) &&
  				(ses->server->addr.sockAddr.sin_addr.s_addr
  				  == target_ip_addr->s_addr)) || (target_ip6_addr
  				&& memcmp(&ses->server->addr.sockAddr6.sin6_addr,
@@ -1250,7 +1270,7 @@ cifs_find_tcp_session(struct in_addr * t
  }

  static struct cifsTconInfo *
-find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
+find_unc(__be32 new_target_ip_addr, char *uncName, char *userName, u32 local_ip)
  {
  	struct list_head *tmp;
  	struct cifsTconInfo *tcon;
@@ -1265,8 +1285,9 @@ find_unc(__be32 new_target_ip_addr, char
  				     (" old ip addr: %x == new ip %x ?",
  				      tcon->ses->server->addr.sockAddr.sin_addr.
  				      s_addr, new_target_ip_addr));
-				if (tcon->ses->server->addr.sockAddr.sin_addr.
-				    s_addr == new_target_ip_addr) {
+				if ((local_ip == tcon->ses->server->ip4_local_ip) &&
+				    (tcon->ses->server->addr.sockAddr.sin_addr.
+				     s_addr == new_target_ip_addr)) {
  	/* BB lock tcon and server and tcp session and increment use count here? */
  					/* found a match on the TCP session */
  					/* BB check if reconnection needed */
@@ -1366,7 +1387,8 @@ static void rfc1002mangle(char * target,

  static int
  ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
-	     char * netbios_name, char * target_name)
+	     char * netbios_name, char * target_name,
+	     u32 local_ip /* in network byte order */)
  {
  	int rc = 0;
  	int connected = 0;
@@ -1385,6 +1407,24 @@ ipv4_connect(struct sockaddr_in *psin_se
  		}
  	}

+	/* Bind to the local IP address if specified */
+	if (local_ip) {
+		struct sockaddr_in myaddr = {
+			.sin_family = AF_INET,
+		};
+		myaddr.sin_addr.s_addr = local_ip;
+		myaddr.sin_port = 0; /* any */
+		rc = (*csocket)->ops->bind(*csocket, (struct sockaddr *) &myaddr,
+					   sizeof(myaddr));
+		if (rc < 0) {
+			printk("Tried to bind to local ip: 0x%x, but failed with error: %d\n",
+			       local_ip, rc);
+		}
+		else {
+			printk("CIFS:  Successfully bound to local ip: 0x%x\n", local_ip);
+		}
+	}
+	
  	psin_server->sin_family = AF_INET;
  	if(psin_server->sin_port) { /* user overrode default port */
  		rc = (*csocket)->ops->connect(*csocket,
@@ -1664,11 +1704,12 @@ cifs_mount(struct super_block *sb, struc
  	if(address_type == AF_INET)
  		existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
  			NULL /* no ipv6 addr */,
-			volume_info.username, &srvTcp);
+			volume_info.username, &srvTcp,
+			volume_info.local_ip);
  	else if(address_type == AF_INET6)
  		existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
  			&sin_server6.sin6_addr,
-			volume_info.username, &srvTcp);
+			volume_info.username, &srvTcp, 0);
  	else {
  		kfree(volume_info.UNC);
  		kfree(volume_info.password);
@@ -1686,7 +1727,8 @@ cifs_mount(struct super_block *sb, struc
  			sin_server.sin_port = 0;
  		rc = ipv4_connect(&sin_server,&csocket,
  				  volume_info.source_rfc1001_name,
-				  volume_info.target_rfc1001_name);
+				  volume_info.target_rfc1001_name,
+				  volume_info.local_ip);
  		if (rc < 0) {
  			cERROR(1,
  			       ("Error connecting to IPv4 socket. Aborting operation"));
@@ -1713,6 +1755,7 @@ cifs_mount(struct super_block *sb, struc
  			/* BB Add code for ipv6 case too */
  			srvTcp->ssocket = csocket;
  			srvTcp->protocolType = IPV4;
+			srvTcp->ip4_local_ip = volume_info.local_ip;
  			init_waitqueue_head(&srvTcp->response_q);
  			init_waitqueue_head(&srvTcp->request_q);
  			INIT_LIST_HEAD(&srvTcp->pending_mid_q);
@@ -1839,7 +1882,7 @@ cifs_mount(struct super_block *sb, struc

  		tcon =
  		    find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
-			     volume_info.username);
+			     volume_info.username, volume_info.local_ip);
  		if (tcon) {
  			cFYI(1, ("Found match on UNC path"));
  			/* we can have only one retry value for a connection

-- 
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc  http://www.candelatech.com


             reply	other threads:[~2006-08-01 17:30 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-08-01 17:30 Ben Greear [this message]
2006-08-01 18:56 ` PATCH: Enable binding to local IPv4 IP address for CIFS file system Andi Kleen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=44CF8FCF.6070401@candelatech.com \
    --to=greearb@candelatech.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=samba-technical@lists.samba.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.