📄 connect.c
字号:
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 and server and tcp session and increment use count here? */ /* found a match on the TCP session */ /* BB check if reconnection needed */ cFYI(1,("Matched ip, old UNC: %s == new: %s ?", tcon->treeName, uncName)); if (strncmp (tcon->treeName, uncName, MAX_TREE_SIZE) == 0) { cFYI(1, ("Matched UNC, old user: %s == new: %s ?", tcon->treeName, uncName)); if (strncmp (tcon->ses->userName, userName, MAX_USERNAME_SIZE) == 0) { read_unlock(&GlobalSMBSeslock); return tcon;/* also matched user (smb session)*/ } } } } } } read_unlock(&GlobalSMBSeslock); return NULL;}intconnect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path, const struct nls_table *nls_codepage){ unsigned char *referrals = NULL; unsigned int num_referrals; int rc = 0; rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage, &num_referrals, &referrals); /* 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 */ if(referrals) 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){ 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); 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){ 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 */ (*csocket)->sk->sk_rcvtimeo = 7 * HZ; /* 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 = cifs_kcalloc(sizeof(struct rfc1002_session_packet), GFP_KERNEL); if(ses_init_buf) { ses_init_buf->trailer.session_req.called_len = 32; 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); } /* 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;}intcifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, char *mount_data, const char *devname){ int rc = 0; int xid; int address_type = AF_INET; struct socket *csocket = NULL; struct sockaddr_in sin_server; struct sockaddr_in6 sin_server6; struct smb_vol volume_info; struct cifsSesInfo *pSesInfo = NULL; struct cifsSesInfo *existingCifsSes = NULL; struct cifsTconInfo *tcon = NULL; struct TCP_Server_Info *srvTcp = NULL; xid = GetXid();/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */ memset(&volume_info,0,sizeof(struct smb_vol)); if (cifs_parse_mount_options(mount_data, devname, &volume_info)) { if(volume_info.UNC) kfree(volume_info.UNC); if(volume_info.password) kfree(volume_info.password); FreeXid(xid); return -EINVAL; } if (volume_info.username) { cFYI(1, ("Username: %s ", volume_info.username)); } else { cifserror("No username specified "); /* In userspace mount helper we can get user name from alternate locations such as env variables and files on disk */ if(volume_info.UNC) kfree(volume_info.UNC); if(volume_info.password) kfree(volume_info.password); FreeXid(xid); return -EINVAL; } if (volume_info.UNCip && volume_info.UNC) { rc = cifs_inet_pton(AF_INET, volume_info.UNCip,&sin_server.sin_addr.s_addr); if(rc <= 0) { /* not ipv4 address, try ipv6 */ rc = cifs_inet_pton(AF_INET6,volume_info.UNCip,&sin_server6.sin6_addr.in6_u); if(rc > 0) address_type = AF_INET6; } else { address_type = AF_INET; } if(rc <= 0) { /* we failed translating address */ if(volume_info.UNC) kfree(volume_info.UNC); if(volume_info.password) kfree(volume_info.password); FreeXid(xid); return -EINVAL; } cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip)); /* success */ rc = 0; } else if (volume_info.UNCip){ /* BB using ip addr as server name connect to the DFS root below */ cERROR(1,("Connecting to DFS root not implemented yet")); if(volume_info.UNC) kfree(volume_info.UNC); if(volume_info.password) kfree(volume_info.password); FreeXid(xid); return -EINVAL; } else /* which servers DFS root would we conect to */ { cERROR(1, ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified ")); if(volume_info.UNC) kfree(volume_info.UNC); if(volume_info.password) kfree(volume_info.password); FreeXid(xid); return -EINVAL; } /* this is needed for ASCII cp to Unicode converts */ if(volume_info.iocharset == NULL) { cifs_sb->local_nls = load_nls_default(); /* load_nls_default can not return null */ } else { cifs_sb->local_nls = load_nls(volume_info.iocharset); if(cifs_sb->local_nls == NULL) { cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset)); if(volume_info.UNC) kfree(volume_info.UNC); if(volume_info.password) kfree(volume_info.password); FreeXid(xid); return -ELIBACC; } } if(address_type == AF_INET) existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr, NULL /* no ipv6 addr */, volume_info.username, &srvTcp); else if(address_type == AF_INET6) existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */, &sin_server6.sin6_addr, volume_info.username, &srvTcp); else { if(volume_info.UNC) kfree(volume_info.UNC); if(volume_info.password) kfree(volume_info.password); FreeXid(xid); return -EINVAL; } if (srvTcp) { cFYI(1, ("Existing tcp session with server found ")); } else { /* create socket */ if(volume_info.port) sin_server.sin_port = htons(volume_info.port); else sin_server.sin_port = 0; rc = ipv4_connect(&sin_server,&csocket,volume_info.source_rfc1001_name); if (rc < 0) { cERROR(1, ("Error connecting to IPv4 socket. Aborting operation"));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -