📄 connect.c
字号:
} else if (strnicmp(data, "in6_addr", 8) == 0) { if (!value || !*value) { vol->in6_addr = NULL; } else if (strnlen(value, 49) == 48) { vol->in6_addr = value; } else { printk(KERN_WARNING "CIFS: ip v6 address not " "48 characters long\n"); return 1; } } else if (strnicmp(data, "noac", 4) == 0) { printk(KERN_WARNING "CIFS: Mount option noac not " "supported. Instead set " "/proc/fs/cifs/LookupCacheEnabled to 0\n"); } else printk(KERN_WARNING "CIFS: Unknown mount option %s\n", data); } if (vol->UNC == NULL) { if (devname == NULL) { printk(KERN_WARNING "CIFS: Missing UNC name for mount " "target\n"); return 1; } if ((temp_len = strnlen(devname, 300)) < 300) { vol->UNC = kmalloc(temp_len+1, GFP_KERNEL); if (vol->UNC == NULL) return 1; strcpy(vol->UNC, devname); if (strncmp(vol->UNC, "//", 2) == 0) { vol->UNC[0] = '\\'; vol->UNC[1] = '\\'; } 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"));#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) (*csocket)->sk->sk_allocation = GFP_NOFS;#else (*csocket)->sk->allocation = GFP_NOFS;#endif } } 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 */#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) 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;#else cFYI(1,("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",(*csocket)->sk->sndbuf, (*csocket)->sk->rcvbuf, (*csocket)->sk->rcvtimeo)); (*csocket)->sk->rcvtimeo = 7 * HZ; /* make the bufsizes depend on wsize/rsize and max requests */ if((*csocket)->sk->sndbuf < (200 * 1024)) (*csocket)->sk->sndbuf = 200 * 1024; if((*csocket)->sk->rcvbuf < (140 * 1024)) (*csocket)->sk->rcvbuf = 140 * 1024;#endif /* 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"));#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) (*csocket)->sk->sk_allocation = GFP_NOFS;#else (*csocket)->sk->allocation = GFP_NOFS;#endif } } 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 */#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0) (*csocket)->sk->sk_rcvtimeo = 7 * HZ;#else (*csocket)->sk->rcvtimeo = 7 * HZ;#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -