📄 connect.c
字号:
} else if (strncmp(vol->UNC, "\\\\", 2) != 0) { printk(KERN_WARNING "CIFS: UNC Path does not " "begin with // or \\\\ \n"); return 1; } } else { printk(KERN_WARNING "CIFS: UNC name too long\n"); return 1; } } if (vol->UNCip == NULL) vol->UNCip = &vol->UNC[2]; return 0;}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){ struct list_head *tmp; struct cifsSesInfo *ses; *psrvTcp = NULL; read_lock(&GlobalSMBSeslock); list_for_each(tmp, &GlobalSMBSessionList) { ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); if (ses->server) { if ((target_ip_addr && (ses->server->addr.sockAddr.sin_addr.s_addr == target_ip_addr->s_addr)) || (target_ip6_addr && memcmp(&ses->server->addr.sockAddr6.sin6_addr, target_ip6_addr, sizeof(*target_ip6_addr)))) { /* BB lock server and tcp session and increment use count here?? */ /* found a match on the TCP session */ *psrvTcp = ses->server; /* BB check if reconnection needed */ if (strncmp (ses->userName, userName, MAX_USERNAME_SIZE) == 0){ read_unlock(&GlobalSMBSeslock); /* Found exact match on both TCP and SMB sessions */ return ses; } } } /* else tcp and smb sessions need reconnection */ } read_unlock(&GlobalSMBSeslock); return NULL;}static struct cifsTconInfo *find_unc(__be32 new_target_ip_addr, char *uncName, char *userName){ struct list_head *tmp; struct cifsTconInfo *tcon; read_lock(&GlobalSMBSeslock); list_for_each(tmp, &GlobalTreeConnectionList) { cFYI(1, ("Next tcon")); tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); if (tcon->ses) { if (tcon->ses->server) { cFYI(1, ("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) { /* BB lock tcon, server and tcp session and increment use count here? */ /* found a match on the TCP session */ /* BB check if reconnection needed */ cFYI(1, ("IP match, old UNC: %s new: %s", tcon->treeName, uncName)); if (strncmp (tcon->treeName, uncName, MAX_TREE_SIZE) == 0) { cFYI(1, ("and old usr: %s new: %s", tcon->treeName, uncName)); if (strncmp (tcon->ses->userName, userName, MAX_USERNAME_SIZE) == 0) { read_unlock(&GlobalSMBSeslock); /* matched smb session (user name */ return tcon; } } } } } } read_unlock(&GlobalSMBSeslock); return NULL;}intconnect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path, const struct nls_table *nls_codepage, int remap){ unsigned char *referrals = NULL; unsigned int num_referrals; int rc = 0; rc = get_dfs_path(xid, pSesInfo, old_path, nls_codepage, &num_referrals, &referrals, remap); /* BB Add in code to: if valid refrl, if not ip address contact the helper that resolves tcp names, mount to it, try to tcon to it unmount it if fail */ kfree(referrals); return rc;}intget_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path, const struct nls_table *nls_codepage, unsigned int *pnum_referrals, unsigned char **preferrals, int remap){ char *temp_unc; int rc = 0; *pnum_referrals = 0; if (pSesInfo->ipc_tid == 0) { temp_unc = kmalloc(2 /* for slashes */ + strnlen(pSesInfo->serverName, SERVER_NAME_LEN_WITH_NULL * 2) + 1 + 4 /* slash IPC$ */ + 2, GFP_KERNEL); if (temp_unc == NULL) return -ENOMEM; temp_unc[0] = '\\'; temp_unc[1] = '\\'; strcpy(temp_unc + 2, pSesInfo->serverName); strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$"); rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage); cFYI(1, ("CIFS Tcon rc = %d ipc_tid = %d", rc, pSesInfo->ipc_tid)); kfree(temp_unc); } if (rc == 0) rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals, pnum_referrals, nls_codepage, remap); return rc;}/* See RFC1001 section 14 on representation of Netbios names */static void rfc1002mangle(char *target, char *source, unsigned int length){ unsigned int i, j; for (i = 0, j = 0; i < (length); i++) { /* mask a nibble at a time and encode */ target[j] = 'A' + (0x0F & (source[i] >> 4)); target[j+1] = 'A' + (0x0F & source[i]); j += 2; }}static intipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, char *netbios_name, char *target_name){ int rc = 0; int connected = 0; __be16 orig_port = 0; if (*csocket == NULL) { rc = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket); if (rc < 0) { cERROR(1, ("Error %d creating socket", rc)); *csocket = NULL; return rc; } else { /* BB other socket options to set KEEPALIVE, NODELAY? */ cFYI(1, ("Socket created")); (*csocket)->sk->sk_allocation = GFP_NOFS; } } psin_server->sin_family = AF_INET; if (psin_server->sin_port) { /* user overrode default port */ rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) psin_server, sizeof(struct sockaddr_in), 0); if (rc >= 0) connected = 1; } if (!connected) { /* save original port so we can retry user specified port later if fall back ports fail this time */ orig_port = psin_server->sin_port; /* do not retry on the same port we just failed on */ if (psin_server->sin_port != htons(CIFS_PORT)) { psin_server->sin_port = htons(CIFS_PORT); rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) psin_server, sizeof(struct sockaddr_in), 0); if (rc >= 0) connected = 1; } } if (!connected) { psin_server->sin_port = htons(RFC1001_PORT); rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) psin_server, sizeof(struct sockaddr_in), 0); if (rc >= 0) connected = 1; } /* give up here - unless we want to retry on different protocol families some day */ if (!connected) { if (orig_port) psin_server->sin_port = orig_port; cFYI(1, ("Error %d connecting to server via ipv4", rc)); sock_release(*csocket); *csocket = NULL; return rc; } /* Eventually check for other socket options to change from the default. sock_setsockopt not used because it expects user space buffer */ cFYI(1, ("sndbuf %d rcvbuf %d rcvtimeo 0x%lx", (*csocket)->sk->sk_sndbuf, (*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo)); (*csocket)->sk->sk_rcvtimeo = 7 * HZ; /* make the bufsizes depend on wsize/rsize and max requests */ if ((*csocket)->sk->sk_sndbuf < (200 * 1024)) (*csocket)->sk->sk_sndbuf = 200 * 1024; if ((*csocket)->sk->sk_rcvbuf < (140 * 1024)) (*csocket)->sk->sk_rcvbuf = 140 * 1024; /* send RFC1001 sessinit */ if (psin_server->sin_port == htons(RFC1001_PORT)) { /* some servers require RFC1001 sessinit before sending negprot - BB check reconnection in case where second sessinit is sent but no second negprot */ struct rfc1002_session_packet *ses_init_buf; struct smb_hdr *smb_buf; ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet), GFP_KERNEL); if (ses_init_buf) { ses_init_buf->trailer.session_req.called_len = 32; if (target_name && (target_name[0] != 0)) { rfc1002mangle(ses_init_buf->trailer.session_req.called_name, target_name, 16); } else { rfc1002mangle(ses_init_buf->trailer.session_req.called_name, DEFAULT_CIFS_CALLED_NAME, 16); } ses_init_buf->trailer.session_req.calling_len = 32; /* calling name ends in null (byte 16) from old smb convention. */ if (netbios_name && (netbios_name[0] != 0)) { rfc1002mangle(ses_init_buf->trailer.session_req.calling_name, netbios_name, 16); } else { rfc1002mangle(ses_init_buf->trailer.session_req.calling_name, "LINUX_CIFS_CLNT", 16); } ses_init_buf->trailer.session_req.scope1 = 0; ses_init_buf->trailer.session_req.scope2 = 0; smb_buf = (struct smb_hdr *)ses_init_buf; /* sizeof RFC1002_SESSION_REQUEST with no scope */ smb_buf->smb_buf_length = 0x81000044; rc = smb_send(*csocket, smb_buf, 0x44, (struct sockaddr *)psin_server); kfree(ses_init_buf); msleep(1); /* RFC1001 layer in at least one server requires very short break before negprot presumably because not expecting negprot to follow so fast. This is a simple solution that works without complicating the code and causes no significant slowing down on mount for everyone else */ } /* else the negprot may still work without this even though malloc failed */ } return rc;}static intipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket){ int rc = 0; int connected = 0; __be16 orig_port = 0; if (*csocket == NULL) { rc = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, csocket); if (rc < 0) { cERROR(1, ("Error %d creating ipv6 socket", rc)); *csocket = NULL; return rc; } else { /* BB other socket options to set KEEPALIVE, NODELAY? */ cFYI(1, ("ipv6 Socket created")); (*csocket)->sk->sk_allocation = GFP_NOFS; } } psin_server->sin6_family = AF_INET6; if (psin_server->sin6_port) { /* user overrode default port */ rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) psin_server, sizeof(struct sockaddr_in6), 0); if (rc >= 0) connected = 1; } if (!connected) { /* save original port so we can retry user specified port later if fall back ports fail this time */ orig_port = psin_server->sin6_port; /* do not retry on the same port we just failed on */ if (psin_server->sin6_port != htons(CIFS_PORT)) { psin_server->sin6_port = htons(CIFS_PORT); rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) psin_server, sizeof(struct sockaddr_in6), 0); if (rc >= 0) connected = 1; } } if (!connected) { psin_server->sin6_port = htons(RFC1001_PORT); rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) psin_server, sizeof(struct sockaddr_in6), 0); if (rc >= 0) connected = 1; } /* give up here - unless we want to retry on different protocol families some day */ if (!connected) { if (orig_port) psin_server->sin6_port = orig_port; cFYI(1, ("Error %d connecting to server via ipv6", rc)); sock_release(*csocket); *csocket = NULL; return rc; } /* Eventually check for other socket options to change from the default. sock_setsockopt not used because it expects user space buffer */ (*csocket)->sk->sk_rcvtimeo = 7 * HZ; return rc;}void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon, struct super_block *sb, struct smb_vol *vol_info){ /* if we are reconnecting then should we check to see if * any requested capabilities changed locally e.g. via * remount but we can not do much about it here * if they have (even if we could detect it by the following) * Perhaps we could add a backpointer to array of sb from tcon * or if we change to make all sb to same share the same * sb as NFS - then we only have one backpointer to sb. * What if we wanted to mount the server share twice once with * and once without posixacls or posix paths? */ __u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability); if (vol_info && vol_info->no_linux_ext) { tcon->fsUnixInfo.Capability = 0; tcon->unix_ext = 0; /* Unix Extensions disabled */ cFYI(1, ("Linux protocol extensions disabled")); return; } else if (vol_info) tcon->unix_ext = 1; /* Unix Extensions supported */ if (tcon->unix_ext == 0) { cFYI(1, ("Unix extensions disabled so not set on reconnect")); return; } if (!CIFSSMBQFSUnixInfo(xid, tcon)) { __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability); /* check for reconnect case in which we do not want to change the mount behavior if we can avoid it */ if (vol_info == NULL) { /* turn off POSIX ACL and PATHNAMES if not set originally at mount time */ if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0) cap &= ~CIFS_UNIX_POSIX_ACL_CAP; if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0) cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP; } cap &= CIFS_UNIX_CAP_MASK; if (vol_info && vol_info->no_psx_acl) cap &= ~CIFS_UNIX_POSIX_ACL_CAP; else if (CIFS_UNIX_POSIX_ACL_CAP & cap) { cFYI(1, ("negotiated posix acl support")); if (sb) sb->s_flags |= MS_POSIXACL; } if (vol_info && vol_info->posix_paths == 0) cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP; else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -