@@ -105,6 +105,7 @@ struct smb_vol {
105
105
bool sockopt_tcp_nodelay :1 ;
106
106
unsigned short int port ;
107
107
char * prepath ;
108
+ struct sockaddr_storage srcaddr ; /* allow binding to a local IP */
108
109
struct nls_table * local_nls ;
109
110
};
110
111
@@ -1046,6 +1047,22 @@ cifs_parse_mount_options(char *options, const char *devname,
1046
1047
"long\n" );
1047
1048
return 1 ;
1048
1049
}
1050
+ } else if (strnicmp (data , "srcaddr" , 7 ) == 0 ) {
1051
+ vol -> srcaddr .ss_family = AF_UNSPEC ;
1052
+
1053
+ if (!value || !* value ) {
1054
+ printk (KERN_WARNING "CIFS: srcaddr value"
1055
+ " not specified.\n" );
1056
+ return 1 ; /* needs_arg; */
1057
+ }
1058
+ i = cifs_convert_address ((struct sockaddr * )& vol -> srcaddr ,
1059
+ value , strlen (value ));
1060
+ if (i < 0 ) {
1061
+ printk (KERN_WARNING "CIFS: Could not parse"
1062
+ " srcaddr: %s\n" ,
1063
+ value );
1064
+ return 1 ;
1065
+ }
1049
1066
} else if (strnicmp (data , "prefixpath" , 10 ) == 0 ) {
1050
1067
if (!value || !* value ) {
1051
1068
printk (KERN_WARNING
@@ -1374,8 +1391,36 @@ cifs_parse_mount_options(char *options, const char *devname,
1374
1391
return 0 ;
1375
1392
}
1376
1393
1394
+ /** Returns true if srcaddr isn't specified and rhs isn't
1395
+ * specified, or if srcaddr is specified and
1396
+ * matches the IP address of the rhs argument.
1397
+ */
1398
+ static bool
1399
+ srcip_matches (struct sockaddr * srcaddr , struct sockaddr * rhs )
1400
+ {
1401
+ switch (srcaddr -> sa_family ) {
1402
+ case AF_UNSPEC :
1403
+ return (rhs -> sa_family == AF_UNSPEC );
1404
+ case AF_INET : {
1405
+ struct sockaddr_in * saddr4 = (struct sockaddr_in * )srcaddr ;
1406
+ struct sockaddr_in * vaddr4 = (struct sockaddr_in * )rhs ;
1407
+ return (saddr4 -> sin_addr .s_addr == vaddr4 -> sin_addr .s_addr );
1408
+ }
1409
+ case AF_INET6 : {
1410
+ struct sockaddr_in6 * saddr6 = (struct sockaddr_in6 * )srcaddr ;
1411
+ struct sockaddr_in6 * vaddr6 = (struct sockaddr_in6 * )& rhs ;
1412
+ return ipv6_addr_equal (& saddr6 -> sin6_addr , & vaddr6 -> sin6_addr );
1413
+ }
1414
+ default :
1415
+ WARN_ON (1 );
1416
+ return false; /* don't expect to be here */
1417
+ }
1418
+ }
1419
+
1420
+
1377
1421
static bool
1378
- match_address (struct TCP_Server_Info * server , struct sockaddr * addr )
1422
+ match_address (struct TCP_Server_Info * server , struct sockaddr * addr ,
1423
+ struct sockaddr * srcaddr )
1379
1424
{
1380
1425
struct sockaddr_in * addr4 = (struct sockaddr_in * )addr ;
1381
1426
struct sockaddr_in6 * addr6 = (struct sockaddr_in6 * )addr ;
@@ -1402,6 +1447,9 @@ match_address(struct TCP_Server_Info *server, struct sockaddr *addr)
1402
1447
break ;
1403
1448
}
1404
1449
1450
+ if (!srcip_matches (srcaddr , (struct sockaddr * )& server -> srcaddr ))
1451
+ return false;
1452
+
1405
1453
return true;
1406
1454
}
1407
1455
@@ -1469,7 +1517,8 @@ cifs_find_tcp_session(struct sockaddr *addr, struct smb_vol *vol)
1469
1517
if (server -> tcpStatus == CifsNew )
1470
1518
continue ;
1471
1519
1472
- if (!match_address (server , addr ))
1520
+ if (!match_address (server , addr ,
1521
+ (struct sockaddr * )& vol -> srcaddr ))
1473
1522
continue ;
1474
1523
1475
1524
if (!match_security (server , vol ))
@@ -1584,6 +1633,8 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
1584
1633
* no need to spinlock this init of tcpStatus or srv_count
1585
1634
*/
1586
1635
tcp_ses -> tcpStatus = CifsNew ;
1636
+ memcpy (& tcp_ses -> srcaddr , & volume_info -> srcaddr ,
1637
+ sizeof (tcp_ses -> srcaddr ));
1587
1638
++ tcp_ses -> srv_count ;
1588
1639
1589
1640
if (addr .ss_family == AF_INET6 ) {
@@ -1999,6 +2050,33 @@ static void rfc1002mangle(char *target, char *source, unsigned int length)
1999
2050
2000
2051
}
2001
2052
2053
+ static int
2054
+ bind_socket (struct TCP_Server_Info * server )
2055
+ {
2056
+ int rc = 0 ;
2057
+ if (server -> srcaddr .ss_family != AF_UNSPEC ) {
2058
+ /* Bind to the specified local IP address */
2059
+ struct socket * socket = server -> ssocket ;
2060
+ rc = socket -> ops -> bind (socket ,
2061
+ (struct sockaddr * ) & server -> srcaddr ,
2062
+ sizeof (server -> srcaddr ));
2063
+ if (rc < 0 ) {
2064
+ struct sockaddr_in * saddr4 ;
2065
+ struct sockaddr_in6 * saddr6 ;
2066
+ saddr4 = (struct sockaddr_in * )& server -> srcaddr ;
2067
+ saddr6 = (struct sockaddr_in6 * )& server -> srcaddr ;
2068
+ if (saddr6 -> sin6_family == AF_INET6 )
2069
+ cERROR (1 , "cifs: "
2070
+ "Failed to bind to: %pI6c, error: %d\n" ,
2071
+ & saddr6 -> sin6_addr , rc );
2072
+ else
2073
+ cERROR (1 , "cifs: "
2074
+ "Failed to bind to: %pI4, error: %d\n" ,
2075
+ & saddr4 -> sin_addr .s_addr , rc );
2076
+ }
2077
+ }
2078
+ return rc ;
2079
+ }
2002
2080
2003
2081
static int
2004
2082
ipv4_connect (struct TCP_Server_Info * server )
@@ -2024,6 +2102,10 @@ ipv4_connect(struct TCP_Server_Info *server)
2024
2102
cifs_reclassify_socket4 (socket );
2025
2103
}
2026
2104
2105
+ rc = bind_socket (server );
2106
+ if (rc < 0 )
2107
+ return rc ;
2108
+
2027
2109
/* user overrode default port */
2028
2110
if (server -> addr .sockAddr .sin_port ) {
2029
2111
rc = socket -> ops -> connect (socket , (struct sockaddr * )
@@ -2186,6 +2268,10 @@ ipv6_connect(struct TCP_Server_Info *server)
2186
2268
cifs_reclassify_socket6 (socket );
2187
2269
}
2188
2270
2271
+ rc = bind_socket (server );
2272
+ if (rc < 0 )
2273
+ return rc ;
2274
+
2189
2275
/* user overrode default port */
2190
2276
if (server -> addr .sockAddr6 .sin6_port ) {
2191
2277
rc = socket -> ops -> connect (socket ,
0 commit comments