mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-30 19:51:31 -04:00
Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6: [DNS RESOLVER] Minor typo correction DNS: Fixes for the DNS query module cifs: Include linux/err.h for IS_ERR and PTR_ERR DNS: Make AFS go to the DNS for AFSDB records for unknown cells DNS: Separate out CIFS DNS Resolver code cifs: account for new creduid=0x%x parameter in spnego upcall string cifs: reduce false positives with inode aliasing serverino autodisable CIFS: Make cifs_convert_address() take a const src pointer and a length cifs: show features compiled in as part of DebugData cifs: update README Fix up trivial conflicts in fs/cifs/cifsfs.c due to workqueue changes
This commit is contained in:
commit
1fc7995d19
24 changed files with 833 additions and 257 deletions
|
|
@ -70,14 +70,14 @@ config CIFS_WEAK_PW_HASH
|
|||
If unsure, say N.
|
||||
|
||||
config CIFS_UPCALL
|
||||
bool "Kerberos/SPNEGO advanced session setup"
|
||||
depends on CIFS && KEYS
|
||||
help
|
||||
Enables an upcall mechanism for CIFS which accesses
|
||||
userspace helper utilities to provide SPNEGO packaged (RFC 4178)
|
||||
Kerberos tickets which are needed to mount to certain secure servers
|
||||
(for which more secure Kerberos authentication is required). If
|
||||
unsure, say N.
|
||||
bool "Kerberos/SPNEGO advanced session setup"
|
||||
depends on CIFS && KEYS
|
||||
select DNS_RESOLVER
|
||||
help
|
||||
Enables an upcall mechanism for CIFS which accesses userspace helper
|
||||
utilities to provide SPNEGO packaged (RFC 4178) Kerberos tickets
|
||||
which are needed to mount to certain secure servers (for which more
|
||||
secure Kerberos authentication is required). If unsure, say N.
|
||||
|
||||
config CIFS_XATTR
|
||||
bool "CIFS extended attributes"
|
||||
|
|
@ -121,6 +121,7 @@ config CIFS_DEBUG2
|
|||
config CIFS_DFS_UPCALL
|
||||
bool "DFS feature support"
|
||||
depends on CIFS && KEYS
|
||||
select DNS_RESOLVER
|
||||
help
|
||||
Distributed File System (DFS) support is used to access shares
|
||||
transparently in an enterprise name space, even if the share
|
||||
|
|
|
|||
|
|
@ -568,8 +568,9 @@ module can be displayed via modinfo.
|
|||
Misc /proc/fs/cifs Flags and Debug Info
|
||||
=======================================
|
||||
Informational pseudo-files:
|
||||
DebugData Displays information about active CIFS sessions
|
||||
and shares, as well as the cifs.ko version.
|
||||
DebugData Displays information about active CIFS sessions and
|
||||
shares, features enabled as well as the cifs.ko
|
||||
version.
|
||||
Stats Lists summary resource usage information as well as per
|
||||
share statistics, if CONFIG_CIFS_STATS in enabled
|
||||
in the kernel configuration.
|
||||
|
|
|
|||
|
|
@ -119,6 +119,31 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
|
|||
"Display Internal CIFS Data Structures for Debugging\n"
|
||||
"---------------------------------------------------\n");
|
||||
seq_printf(m, "CIFS Version %s\n", CIFS_VERSION);
|
||||
seq_printf(m, "Features: ");
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
seq_printf(m, "dfs");
|
||||
seq_putc(m, ' ');
|
||||
#endif
|
||||
#ifdef CONFIG_CIFS_FSCACHE
|
||||
seq_printf(m, "fscache");
|
||||
seq_putc(m, ' ');
|
||||
#endif
|
||||
#ifdef CONFIG_CIFS_WEAK_PW_HASH
|
||||
seq_printf(m, "lanman");
|
||||
seq_putc(m, ' ');
|
||||
#endif
|
||||
#ifdef CONFIG_CIFS_POSIX
|
||||
seq_printf(m, "posix");
|
||||
seq_putc(m, ' ');
|
||||
#endif
|
||||
#ifdef CONFIG_CIFS_UPCALL
|
||||
seq_printf(m, "spnego");
|
||||
seq_putc(m, ' ');
|
||||
#endif
|
||||
#ifdef CONFIG_CIFS_XATTR
|
||||
seq_printf(m, "xattr");
|
||||
#endif
|
||||
seq_putc(m, '\n');
|
||||
seq_printf(m, "Active VFS Requests: %d\n", GlobalTotalActiveXid);
|
||||
seq_printf(m, "Servers:");
|
||||
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ char *cifs_compose_mount_options(const char *sb_mountdata,
|
|||
}
|
||||
|
||||
rc = dns_resolve_server_name_to_ip(*devname, &srvIP);
|
||||
if (rc != 0) {
|
||||
if (rc < 0) {
|
||||
cERROR(1, "%s: Failed to resolve server part of %s to IP: %d",
|
||||
__func__, *devname, rc);
|
||||
goto compose_mount_options_err;
|
||||
|
|
@ -150,8 +150,7 @@ char *cifs_compose_mount_options(const char *sb_mountdata,
|
|||
* assuming that we have 'unc=' and 'ip=' in
|
||||
* the original sb_mountdata
|
||||
*/
|
||||
md_len = strlen(sb_mountdata) + strlen(srvIP) +
|
||||
strlen(ref->node_name) + 12;
|
||||
md_len = strlen(sb_mountdata) + rc + strlen(ref->node_name) + 12;
|
||||
mountdata = kzalloc(md_len+1, GFP_KERNEL);
|
||||
if (mountdata == NULL) {
|
||||
rc = -ENOMEM;
|
||||
|
|
|
|||
|
|
@ -84,6 +84,9 @@ struct key_type cifs_spnego_key_type = {
|
|||
/* strlen of ";uid=0x" */
|
||||
#define UID_KEY_LEN 7
|
||||
|
||||
/* strlen of ";creduid=0x" */
|
||||
#define CREDUID_KEY_LEN 11
|
||||
|
||||
/* strlen of ";user=" */
|
||||
#define USER_KEY_LEN 6
|
||||
|
||||
|
|
@ -107,6 +110,7 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo)
|
|||
IP_KEY_LEN + INET6_ADDRSTRLEN +
|
||||
MAX_MECH_STR_LEN +
|
||||
UID_KEY_LEN + (sizeof(uid_t) * 2) +
|
||||
CREDUID_KEY_LEN + (sizeof(uid_t) * 2) +
|
||||
USER_KEY_LEN + strlen(sesInfo->userName) +
|
||||
PID_KEY_LEN + (sizeof(pid_t) * 2) + 1;
|
||||
|
||||
|
|
|
|||
|
|
@ -45,7 +45,6 @@
|
|||
#include "cifs_fs_sb.h"
|
||||
#include <linux/mm.h>
|
||||
#include <linux/key-type.h>
|
||||
#include "dns_resolve.h"
|
||||
#include "cifs_spnego.h"
|
||||
#include "fscache.h"
|
||||
#define CIFS_MAGIC_NUMBER 0xFF534D42 /* the first four bytes of SMB PDUs */
|
||||
|
|
@ -934,22 +933,13 @@ init_cifs(void)
|
|||
if (rc)
|
||||
goto out_unregister_filesystem;
|
||||
#endif
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
rc = cifs_init_dns_resolver();
|
||||
if (rc)
|
||||
goto out_unregister_key_type;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
out_unregister_key_type:
|
||||
#endif
|
||||
#ifdef CONFIG_CIFS_UPCALL
|
||||
unregister_key_type(&cifs_spnego_key_type);
|
||||
out_unregister_filesystem:
|
||||
#endif
|
||||
unregister_filesystem(&cifs_fs_type);
|
||||
#endif
|
||||
out_destroy_request_bufs:
|
||||
cifs_destroy_request_bufs();
|
||||
out_destroy_mids:
|
||||
|
|
@ -971,7 +961,6 @@ exit_cifs(void)
|
|||
cifs_fscache_unregister();
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
cifs_dfs_release_automount_timer();
|
||||
cifs_exit_dns_resolver();
|
||||
#endif
|
||||
#ifdef CONFIG_CIFS_UPCALL
|
||||
unregister_key_type(&cifs_spnego_key_type);
|
||||
|
|
|
|||
|
|
@ -86,8 +86,8 @@ extern unsigned int smbCalcSize(struct smb_hdr *ptr);
|
|||
extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr);
|
||||
extern int decode_negTokenInit(unsigned char *security_blob, int length,
|
||||
struct TCP_Server_Info *server);
|
||||
extern int cifs_convert_address(struct sockaddr *dst, char *src);
|
||||
extern int cifs_fill_sockaddr(struct sockaddr *dst, char *src,
|
||||
extern int cifs_convert_address(struct sockaddr *dst, const char *src, int len);
|
||||
extern int cifs_fill_sockaddr(struct sockaddr *dst, const char *src, int len,
|
||||
unsigned short int port);
|
||||
extern int map_smb_to_linux_error(struct smb_hdr *smb, int logErr);
|
||||
extern void header_assemble(struct smb_hdr *, char /* command */ ,
|
||||
|
|
|
|||
|
|
@ -1543,6 +1543,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
|
|||
if (volume_info->UNCip && volume_info->UNC) {
|
||||
rc = cifs_fill_sockaddr((struct sockaddr *)&addr,
|
||||
volume_info->UNCip,
|
||||
strlen(volume_info->UNCip),
|
||||
volume_info->port);
|
||||
if (!rc) {
|
||||
/* we failed translating address */
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
* Copyright (c) 2007 Igor Mammedov
|
||||
* Author(s): Igor Mammedov (niallain@gmail.com)
|
||||
* Steve French (sfrench@us.ibm.com)
|
||||
* Wang Lei (wang840925@gmail.com)
|
||||
* David Howells (dhowells@redhat.com)
|
||||
*
|
||||
* Contains the CIFS DFS upcall routines used for hostname to
|
||||
* IP address translation.
|
||||
|
|
@ -24,214 +26,73 @@
|
|||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/keyctl.h>
|
||||
#include <linux/key-type.h>
|
||||
#include <keys/user-type.h>
|
||||
#include <linux/dns_resolver.h>
|
||||
#include "dns_resolve.h"
|
||||
#include "cifsglob.h"
|
||||
#include "cifsproto.h"
|
||||
#include "cifs_debug.h"
|
||||
|
||||
static const struct cred *dns_resolver_cache;
|
||||
|
||||
/* Checks if supplied name is IP address
|
||||
* returns:
|
||||
* 1 - name is IP
|
||||
* 0 - name is not IP
|
||||
*/
|
||||
static int
|
||||
is_ip(char *name)
|
||||
{
|
||||
struct sockaddr_storage ss;
|
||||
|
||||
return cifs_convert_address((struct sockaddr *)&ss, name);
|
||||
}
|
||||
|
||||
static int
|
||||
dns_resolver_instantiate(struct key *key, const void *data,
|
||||
size_t datalen)
|
||||
{
|
||||
int rc = 0;
|
||||
char *ip;
|
||||
|
||||
ip = kmalloc(datalen + 1, GFP_KERNEL);
|
||||
if (!ip)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(ip, data, datalen);
|
||||
ip[datalen] = '\0';
|
||||
|
||||
/* make sure this looks like an address */
|
||||
if (!is_ip(ip)) {
|
||||
kfree(ip);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
key->type_data.x[0] = datalen;
|
||||
key->payload.data = ip;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void
|
||||
dns_resolver_destroy(struct key *key)
|
||||
{
|
||||
kfree(key->payload.data);
|
||||
}
|
||||
|
||||
struct key_type key_type_dns_resolver = {
|
||||
.name = "dns_resolver",
|
||||
.def_datalen = sizeof(struct in_addr),
|
||||
.describe = user_describe,
|
||||
.instantiate = dns_resolver_instantiate,
|
||||
.destroy = dns_resolver_destroy,
|
||||
.match = user_match,
|
||||
};
|
||||
|
||||
/* Resolves server name to ip address.
|
||||
* input:
|
||||
* unc - server UNC
|
||||
* output:
|
||||
* *ip_addr - pointer to server ip, caller responcible for freeing it.
|
||||
* return 0 on success
|
||||
/**
|
||||
* dns_resolve_server_name_to_ip - Resolve UNC server name to ip address.
|
||||
* @unc: UNC path specifying the server
|
||||
* @ip_addr: Where to return the IP address.
|
||||
*
|
||||
* The IP address will be returned in string form, and the caller is
|
||||
* responsible for freeing it.
|
||||
*
|
||||
* Returns length of result on success, -ve on error.
|
||||
*/
|
||||
int
|
||||
dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
|
||||
{
|
||||
const struct cred *saved_cred;
|
||||
int rc = -EAGAIN;
|
||||
struct key *rkey = ERR_PTR(-EAGAIN);
|
||||
struct sockaddr_storage ss;
|
||||
const char *hostname, *sep;
|
||||
char *name;
|
||||
char *data = NULL;
|
||||
int len;
|
||||
int len, rc;
|
||||
|
||||
if (!ip_addr || !unc)
|
||||
return -EINVAL;
|
||||
|
||||
/* search for server name delimiter */
|
||||
len = strlen(unc);
|
||||
if (len < 3) {
|
||||
cFYI(1, "%s: unc is too short: %s", __func__, unc);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Discount leading slashes for cifs */
|
||||
len -= 2;
|
||||
name = memchr(unc+2, '\\', len);
|
||||
if (!name) {
|
||||
hostname = unc + 2;
|
||||
|
||||
/* Search for server name delimiter */
|
||||
sep = memchr(hostname, '\\', len);
|
||||
if (sep)
|
||||
len = sep - unc;
|
||||
else
|
||||
cFYI(1, "%s: probably server name is whole unc: %s",
|
||||
__func__, unc);
|
||||
} else {
|
||||
len = (name - unc) - 2/* leading // */;
|
||||
}
|
||||
__func__, unc);
|
||||
|
||||
name = kmalloc(len+1, GFP_KERNEL);
|
||||
if (!name) {
|
||||
rc = -ENOMEM;
|
||||
return rc;
|
||||
}
|
||||
memcpy(name, unc+2, len);
|
||||
name[len] = 0;
|
||||
/* Try to interpret hostname as an IPv4 or IPv6 address */
|
||||
rc = cifs_convert_address((struct sockaddr *)&ss, hostname, len);
|
||||
if (rc > 0)
|
||||
goto name_is_IP_address;
|
||||
|
||||
if (is_ip(name)) {
|
||||
cFYI(1, "%s: it is IP, skipping dns upcall: %s",
|
||||
__func__, name);
|
||||
data = name;
|
||||
goto skip_upcall;
|
||||
}
|
||||
|
||||
saved_cred = override_creds(dns_resolver_cache);
|
||||
rkey = request_key(&key_type_dns_resolver, name, "");
|
||||
revert_creds(saved_cred);
|
||||
if (!IS_ERR(rkey)) {
|
||||
if (!(rkey->perm & KEY_USR_VIEW)) {
|
||||
down_read(&rkey->sem);
|
||||
rkey->perm |= KEY_USR_VIEW;
|
||||
up_read(&rkey->sem);
|
||||
}
|
||||
len = rkey->type_data.x[0];
|
||||
data = rkey->payload.data;
|
||||
} else {
|
||||
cERROR(1, "%s: unable to resolve: %s", __func__, name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
skip_upcall:
|
||||
if (data) {
|
||||
*ip_addr = kmalloc(len + 1, GFP_KERNEL);
|
||||
if (*ip_addr) {
|
||||
memcpy(*ip_addr, data, len + 1);
|
||||
if (!IS_ERR(rkey))
|
||||
cFYI(1, "%s: resolved: %s to %s", __func__,
|
||||
name,
|
||||
*ip_addr
|
||||
);
|
||||
rc = 0;
|
||||
} else {
|
||||
rc = -ENOMEM;
|
||||
}
|
||||
if (!IS_ERR(rkey))
|
||||
key_put(rkey);
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(name);
|
||||
/* Perform the upcall */
|
||||
rc = dns_query(NULL, hostname, len, NULL, ip_addr, NULL);
|
||||
if (rc < 0)
|
||||
cERROR(1, "%s: unable to resolve: %*.*s",
|
||||
__func__, len, len, hostname);
|
||||
else
|
||||
cFYI(1, "%s: resolved: %*.*s to %s",
|
||||
__func__, len, len, hostname, *ip_addr);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int __init cifs_init_dns_resolver(void)
|
||||
{
|
||||
struct cred *cred;
|
||||
struct key *keyring;
|
||||
int ret;
|
||||
|
||||
printk(KERN_NOTICE "Registering the %s key type\n",
|
||||
key_type_dns_resolver.name);
|
||||
|
||||
/* create an override credential set with a special thread keyring in
|
||||
* which DNS requests are cached
|
||||
*
|
||||
* this is used to prevent malicious redirections from being installed
|
||||
* with add_key().
|
||||
*/
|
||||
cred = prepare_kernel_cred(NULL);
|
||||
if (!cred)
|
||||
name_is_IP_address:
|
||||
name = kmalloc(len + 1, GFP_KERNEL);
|
||||
if (!name)
|
||||
return -ENOMEM;
|
||||
|
||||
keyring = key_alloc(&key_type_keyring, ".dns_resolver", 0, 0, cred,
|
||||
(KEY_POS_ALL & ~KEY_POS_SETATTR) |
|
||||
KEY_USR_VIEW | KEY_USR_READ,
|
||||
KEY_ALLOC_NOT_IN_QUOTA);
|
||||
if (IS_ERR(keyring)) {
|
||||
ret = PTR_ERR(keyring);
|
||||
goto failed_put_cred;
|
||||
}
|
||||
|
||||
ret = key_instantiate_and_link(keyring, NULL, 0, NULL, NULL);
|
||||
if (ret < 0)
|
||||
goto failed_put_key;
|
||||
|
||||
ret = register_key_type(&key_type_dns_resolver);
|
||||
if (ret < 0)
|
||||
goto failed_put_key;
|
||||
|
||||
/* instruct request_key() to use this special keyring as a cache for
|
||||
* the results it looks up */
|
||||
cred->thread_keyring = keyring;
|
||||
cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
|
||||
dns_resolver_cache = cred;
|
||||
memcpy(name, hostname, len);
|
||||
name[len] = 0;
|
||||
cFYI(1, "%s: unc is IP, skipping dns upcall: %s", __func__, name);
|
||||
*ip_addr = name;
|
||||
return 0;
|
||||
|
||||
failed_put_key:
|
||||
key_put(keyring);
|
||||
failed_put_cred:
|
||||
put_cred(cred);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void cifs_exit_dns_resolver(void)
|
||||
{
|
||||
key_revoke(dns_resolver_cache->thread_keyring);
|
||||
unregister_key_type(&key_type_dns_resolver);
|
||||
put_cred(dns_resolver_cache);
|
||||
printk(KERN_NOTICE "Unregistered %s key type\n",
|
||||
key_type_dns_resolver.name);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,8 +24,6 @@
|
|||
#define _DNS_RESOLVE_H
|
||||
|
||||
#ifdef __KERNEL__
|
||||
extern int __init cifs_init_dns_resolver(void);
|
||||
extern void cifs_exit_dns_resolver(void);
|
||||
extern int dns_resolve_server_name_to_ip(const char *unc, char **ip_addr);
|
||||
#endif /* KERNEL */
|
||||
|
||||
|
|
|
|||
|
|
@ -732,15 +732,9 @@ cifs_find_inode(struct inode *inode, void *opaque)
|
|||
if ((inode->i_mode & S_IFMT) != (fattr->cf_mode & S_IFMT))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* uh oh -- it's a directory. We can't use it since hardlinked dirs are
|
||||
* verboten. Disable serverino and return it as if it were found, the
|
||||
* caller can discard it, generate a uniqueid and retry the find
|
||||
*/
|
||||
if (S_ISDIR(inode->i_mode) && !list_empty(&inode->i_dentry)) {
|
||||
/* if it's not a directory or has no dentries, then flag it */
|
||||
if (S_ISDIR(inode->i_mode) && !list_empty(&inode->i_dentry))
|
||||
fattr->cf_flags |= CIFS_FATTR_INO_COLLISION;
|
||||
cifs_autodisable_serverino(CIFS_SB(inode->i_sb));
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -754,6 +748,27 @@ cifs_init_inode(struct inode *inode, void *opaque)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* walk dentry list for an inode and report whether it has aliases that
|
||||
* are hashed. We use this to determine if a directory inode can actually
|
||||
* be used.
|
||||
*/
|
||||
static bool
|
||||
inode_has_hashed_dentries(struct inode *inode)
|
||||
{
|
||||
struct dentry *dentry;
|
||||
|
||||
spin_lock(&dcache_lock);
|
||||
list_for_each_entry(dentry, &inode->i_dentry, d_alias) {
|
||||
if (!d_unhashed(dentry) || IS_ROOT(dentry)) {
|
||||
spin_unlock(&dcache_lock);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
spin_unlock(&dcache_lock);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Given fattrs, get a corresponding inode */
|
||||
struct inode *
|
||||
cifs_iget(struct super_block *sb, struct cifs_fattr *fattr)
|
||||
|
|
@ -769,12 +784,16 @@ retry_iget5_locked:
|
|||
|
||||
inode = iget5_locked(sb, hash, cifs_find_inode, cifs_init_inode, fattr);
|
||||
if (inode) {
|
||||
/* was there a problematic inode number collision? */
|
||||
/* was there a potentially problematic inode collision? */
|
||||
if (fattr->cf_flags & CIFS_FATTR_INO_COLLISION) {
|
||||
iput(inode);
|
||||
fattr->cf_uniqueid = iunique(sb, ROOT_I);
|
||||
fattr->cf_flags &= ~CIFS_FATTR_INO_COLLISION;
|
||||
goto retry_iget5_locked;
|
||||
|
||||
if (inode_has_hashed_dentries(inode)) {
|
||||
cifs_autodisable_serverino(CIFS_SB(sb));
|
||||
iput(inode);
|
||||
fattr->cf_uniqueid = iunique(sb, ROOT_I);
|
||||
goto retry_iget5_locked;
|
||||
}
|
||||
}
|
||||
|
||||
cifs_fattr_to_inode(inode, fattr);
|
||||
|
|
|
|||
|
|
@ -140,17 +140,18 @@ static const struct smb_to_posix_error mapping_table_ERRHRD[] = {
|
|||
* Returns 0 on failure.
|
||||
*/
|
||||
static int
|
||||
cifs_inet_pton(const int address_family, const char *cp, void *dst)
|
||||
cifs_inet_pton(const int address_family, const char *cp, int len, void *dst)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
/* calculate length by finding first slash or NULL */
|
||||
if (address_family == AF_INET)
|
||||
ret = in4_pton(cp, -1 /* len */, dst, '\\', NULL);
|
||||
ret = in4_pton(cp, len, dst, '\\', NULL);
|
||||
else if (address_family == AF_INET6)
|
||||
ret = in6_pton(cp, -1 /* len */, dst , '\\', NULL);
|
||||
ret = in6_pton(cp, len, dst , '\\', NULL);
|
||||
|
||||
cFYI(DBG2, "address conversion returned %d for %s", ret, cp);
|
||||
cFYI(DBG2, "address conversion returned %d for %*.*s",
|
||||
ret, len, len, cp);
|
||||
if (ret > 0)
|
||||
ret = 1;
|
||||
return ret;
|
||||
|
|
@ -165,37 +166,39 @@ cifs_inet_pton(const int address_family, const char *cp, void *dst)
|
|||
* Returns 0 on failure.
|
||||
*/
|
||||
int
|
||||
cifs_convert_address(struct sockaddr *dst, char *src)
|
||||
cifs_convert_address(struct sockaddr *dst, const char *src, int len)
|
||||
{
|
||||
int rc;
|
||||
char *pct, *endp;
|
||||
int rc, alen, slen;
|
||||
const char *pct;
|
||||
char *endp, scope_id[13];
|
||||
struct sockaddr_in *s4 = (struct sockaddr_in *) dst;
|
||||
struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) dst;
|
||||
|
||||
/* IPv4 address */
|
||||
if (cifs_inet_pton(AF_INET, src, &s4->sin_addr.s_addr)) {
|
||||
if (cifs_inet_pton(AF_INET, src, len, &s4->sin_addr.s_addr)) {
|
||||
s4->sin_family = AF_INET;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* temporarily terminate string */
|
||||
pct = strchr(src, '%');
|
||||
if (pct)
|
||||
*pct = '\0';
|
||||
|
||||
rc = cifs_inet_pton(AF_INET6, src, &s6->sin6_addr.s6_addr);
|
||||
|
||||
/* repair temp termination (if any) and make pct point to scopeid */
|
||||
if (pct)
|
||||
*pct++ = '%';
|
||||
/* attempt to exclude the scope ID from the address part */
|
||||
pct = memchr(src, '%', len);
|
||||
alen = pct ? pct - src : len;
|
||||
|
||||
rc = cifs_inet_pton(AF_INET6, src, alen, &s6->sin6_addr.s6_addr);
|
||||
if (!rc)
|
||||
return rc;
|
||||
|
||||
s6->sin6_family = AF_INET6;
|
||||
if (pct) {
|
||||
/* grab the scope ID */
|
||||
slen = len - (alen + 1);
|
||||
if (slen <= 0 || slen > 12)
|
||||
return 0;
|
||||
memcpy(scope_id, pct + 1, slen);
|
||||
scope_id[slen] = '\0';
|
||||
|
||||
s6->sin6_scope_id = (u32) simple_strtoul(pct, &endp, 0);
|
||||
if (!*pct || *endp)
|
||||
if (endp != scope_id + slen)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -203,10 +206,10 @@ cifs_convert_address(struct sockaddr *dst, char *src)
|
|||
}
|
||||
|
||||
int
|
||||
cifs_fill_sockaddr(struct sockaddr *dst, char *src,
|
||||
cifs_fill_sockaddr(struct sockaddr *dst, const char *src, int len,
|
||||
const unsigned short int port)
|
||||
{
|
||||
if (!cifs_convert_address(dst, src))
|
||||
if (!cifs_convert_address(dst, src, len))
|
||||
return 0;
|
||||
|
||||
switch (dst->sa_family) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue