netfs.c

来自「EFI(Extensible Firmware Interface)是下一代BI」· C语言 代码 · 共 791 行 · 第 1/2 页

C
791
字号
		VERB_PRT(2, Print(L"Done\n"));	} else {		netfs_fd_free(nfs, f);		VERB_PRT(2, Print(L"Failed: %r\n", status));	}	DBG_PRT((L"File %s netbuf_size=%d: %r", name, f->netbuf_size, status));#if 0	Print(L"\n---\n");	{ INTN i; 		for(i=0; i < netbuf_size; i++) {			Print(L"%c", (CHAR16)netbuf[i]);		}	}	Print(L"\n---\n");#endif	return status;}static EFI_STATUSnetfs_read(netfs_interface_t *this, UINTN fd, VOID *buf, UINTN *size){	netfs_priv_state_t *nfs;	netfs_fd_t	   *f;	UINTN		   count;	if (this == NULL || fd >= NETFS_FD_MAX || buf == NULL || size == NULL) return EFI_INVALID_PARAMETER;	nfs = FS_PRIVATE(this);	f   = NETFS_FD2F(nfs, fd);	if (NETFS_F_INVALID(f)) return EFI_INVALID_PARAMETER;	count = MIN(*size, f->netbuf_size - f->netbuf_pos);	if (count) Memcpy(buf, f->netbuf+f->netbuf_pos, count);	*size = count;	f->netbuf_pos += count;	return EFI_SUCCESS;}static EFI_STATUSnetfs_close(netfs_interface_t *this, UINTN fd){	netfs_priv_state_t *nfs;	netfs_fd_t	     *f;	if (this == NULL || fd >= NETFS_FD_MAX) return EFI_INVALID_PARAMETER;	nfs = FS_PRIVATE(this);	f   = NETFS_FD2F(nfs, fd);	if (NETFS_F_INVALID(f)) return EFI_INVALID_PARAMETER;	netfs_fd_free(nfs, f);	return EFI_SUCCESS;}static EFI_STATUSnetfs_seek(netfs_interface_t *this, UINTN fd, UINT64 newpos){	netfs_priv_state_t *nfs;	netfs_fd_t	   *f;	if (this == NULL || fd >= NETFS_FD_MAX) return EFI_INVALID_PARAMETER;	nfs = FS_PRIVATE(this);	f   = NETFS_FD2F(nfs, fd);	if (NETFS_F_INVALID(f)) return EFI_INVALID_PARAMETER;	if (newpos > f->netbuf_size) return EFI_INVALID_PARAMETER;	f->netbuf_pos = newpos;	return EFI_SUCCESS;}static EFI_STATUSnetfs_infosize(netfs_interface_t *this, UINTN fd, UINT64 *sz){	netfs_priv_state_t *nfs;	netfs_fd_t	   *f;	if (this == NULL || fd >= NETFS_FD_MAX || sz == NULL) return EFI_INVALID_PARAMETER;	nfs = FS_PRIVATE(this);	f   = NETFS_FD2F(nfs, fd);	if (NETFS_F_INVALID(f)) return EFI_INVALID_PARAMETER;	*sz = f->netbuf_size;	return EFI_SUCCESS;}static INTNfind_dhcp_option(EFI_PXE_BASE_CODE_PACKET *packet, UINT8 use_ipv6, UINT8 option, CHAR8 *str, INTN *len){	INTN i = 0;	UINT8 tag, length;	UINT8 *opts = packet->Dhcpv4.DhcpOptions;	*len = 0;	for(;;) {		if (i >= 56) {			DBG_PRT((L"reach end of options (no marker)\n"));			break;		}		tag = opts[i++];		if (tag == 0) continue;		if (tag == 255) break;		length = opts[i++];#if 0		{ UINT8 l = length, k = 0;			Print(L"found option %d len=%d: ", tag, length);			while (l--) { Print(L"%c(%d)\n", (CHAR16)opts[k], opts[k]); k++; }			Print(L"\n");		}#endif		if (tag == option) {			*len = length;			while (length--) { *str++ = opts[i++]; }			return 0;		}		i += length;	}	return -1;}static EFI_STATUSnetfs_getinfo(netfs_interface_t *this, netfs_info_t *info){	netfs_priv_state_t *nfs;	CHAR8 str[256];	INTN len, r;	if (this == NULL || info == NULL) return EFI_INVALID_PARAMETER;	nfs = FS_PRIVATE(this);	Memcpy(&info->cln_ipaddr, &nfs->cln_ip, sizeof(EFI_IP_ADDRESS));	Memcpy(&info->srv_ipaddr, &nfs->srv_ip, sizeof(EFI_IP_ADDRESS));	Memcpy(&info->netmask, &nfs->netmask, sizeof(EFI_IP_ADDRESS));	Memcpy(&info->gw_ipaddr, &nfs->gw_ip, sizeof(EFI_IP_ADDRESS));	Memcpy(&info->hw_addr, &nfs->hw_addr, sizeof(info->hw_addr));	info->using_pxe  = nfs->using_pxe;	info->started    = nfs->pxe->Mode->Started;	info->using_ipv6 = nfs->pxe->Mode->UsingIpv6;	if (nfs->pxe->Mode->UsingIpv6) goto skip_options;	r = find_dhcp_option(&nfs->pxe->Mode->DhcpAck,nfs->pxe->Mode->UsingIpv6, 15, str,  &len);	str[len] = '\0';	ascii2U(str, info->domainame, 255);	VERB_PRT(3, Print(L"domain(15): %a\n", str));	r = find_dhcp_option(&nfs->pxe->Mode->DhcpAck,nfs->pxe->Mode->UsingIpv6, 12, str,  &len);	str[len] = '\0';	ascii2U(str, info->hostname, 255);	VERB_PRT(3, Print(L"hostname(12): %a\n", str));	/*	 * extract bootfile name from DHCP exchanges	 */	if (nfs->using_pxe == 0) { 		ascii2U(nfs->pxe->Mode->DhcpAck.Dhcpv4.BootpBootFile, info->bootfile, NETFS_BOOTFILE_MAXLEN);		VERB_PRT(3, Print(L"bootfile: %s\n", info->bootfile));	}skip_options:	return EFI_SUCCESS;}static UINT16find_pxe_server_type(EFI_PXE_BASE_CODE *pxe){	INTN i = 0, max;	UINT8 tag, length;	UINT8 *opts = pxe->Mode->PxeReply.Dhcpv4.DhcpOptions;	UINT16 server_type;	while(i < 55) {		tag    = opts[i];		length = opts[i+1];		DBG_PRT((L"Tag #%d Length %d\n",tag, length));		if (tag == 43) goto found;		i += 2 + length;	}	return NETFS_DEFAULT_SERVER_TYPE;found:	max = i+2+length;	i  += 2;	while (i < max) {		tag    = opts[i];		length = opts[i+1];		if (tag == 71) {			server_type =(opts[i+2]<<8) | opts[i+3];			DBG_PRT((L"ServerType: %d\n", server_type));			return server_type;		}		i+= 2 + length;	}	return NETFS_DEFAULT_SERVER_TYPE;}static EFI_STATUSnetfs_query_layer(netfs_interface_t *this, UINT16 server_type, UINT16 layer, UINTN maxlen, CHAR16 *str){	netfs_priv_state_t *nfs;	EFI_STATUS	   status;	if (this == NULL || str == NULL) return EFI_INVALID_PARAMETER;	nfs = FS_PRIVATE(this);		if (nfs->using_pxe == FALSE) return EFI_UNSUPPORTED;	if (server_type == 0) server_type = find_pxe_server_type(nfs->pxe);	status = nfs->pxe->Discover(nfs->pxe, server_type, &layer, FALSE, 0);	if(status == EFI_SUCCESS) {		ascii2U(nfs->pxe->Mode->PxeReply.Dhcpv4.BootpBootFile, str, maxlen);	} 	return status;}static VOIDnetfs_init_state(netfs_t *netfs, EFI_HANDLE dev, EFI_PXE_BASE_CODE *pxe){	netfs_priv_state_t *nfs = FS_PRIVATE(netfs);	UINTN i;	/* need to do some init here on netfs_intf */	Memset(netfs, 0, sizeof(*netfs));	netfs->pub_intf.netfs_name        = netfs_name;	netfs->pub_intf.netfs_open        = netfs_open;	netfs->pub_intf.netfs_read        = netfs_read;	netfs->pub_intf.netfs_close       = netfs_close;	netfs->pub_intf.netfs_infosize    = netfs_infosize;	netfs->pub_intf.netfs_seek        = netfs_seek;	netfs->pub_intf.netfs_query_layer = netfs_query_layer;	netfs->pub_intf.netfs_getinfo     = netfs_getinfo;	nfs->dev = dev;	nfs->pxe = pxe;	/*	 * we defer DHCP request until it is really necessary (netfs_open)	 */	if (pxe->Mode->Started == TRUE) netfs_extract_ip(nfs);	Memset(nfs->fd_tab, 0, sizeof(nfs->fd_tab));	for (i=0; i < NETFS_FD_MAX-1; i++) {		nfs->fd_tab[i].next = &nfs->fd_tab[i+1];	}	/* null on last element is done by memset */	nfs->free_fd	    = nfs->fd_tab;	nfs->free_fd_count  = NETFS_FD_MAX;}static EFI_STATUSnetfs_install_one(EFI_HANDLE dev, VOID **intf){	EFI_STATUS status;	netfs_t *netfs;	EFI_PXE_BASE_CODE *pxe;	status = BS->HandleProtocol (dev, &NetFsProtocol, (VOID **)&netfs);	if (status == EFI_SUCCESS) {		ERR_PRT((L"Warning: found existing %s protocol on device", FS_NAME));		goto found;	}		status = BS->HandleProtocol (dev, &PxeBaseCodeProtocol, (VOID **)&pxe);	if (EFI_ERROR(status)) return EFI_INVALID_PARAMETER;	netfs = (netfs_t *)alloc(sizeof(*netfs), EfiLoaderData);	if (netfs == NULL) {		ERR_PRT((L"failed to allocate %s", FS_NAME));		return EFI_OUT_OF_RESOURCES;	}	netfs_init_state(netfs, dev, pxe);	status = LibInstallProtocolInterfaces(&dev, &NetFsProtocol, netfs, NULL);	if (EFI_ERROR(status)) {		ERR_PRT((L"Cannot install %s protocol: %r", FS_NAME, status));		free(netfs);		return status;	}found:	if (intf) *intf = (VOID *)netfs;	VERB_PRT(3,		{ EFI_DEVICE_PATH *dp; CHAR16 *str;		  dp  = DevicePathFromHandle(dev);		  str = DevicePathToStr(dp);		  Print(L"attached %s to %s\n", FS_NAME, str);		  FreePool(str);		});	return EFI_SUCCESS;}	EFI_STATUSnetfs_install(VOID){	UINTN size = 0;	UINTN i;	EFI_STATUS status;	VOID *intf;	BS->LocateHandle(ByProtocol, &PxeBaseCodeProtocol, NULL, &size, NULL);	if (size == 0) return EFI_UNSUPPORTED; /* no device found, oh well */	DBG_PRT((L"size=%d", size));	dev_tab = (dev_tab_t *)alloc(size, EfiLoaderData);	if (dev_tab == NULL) {		ERR_PRT((L"failed to allocate handle table"));		return EFI_OUT_OF_RESOURCES;	}		status = BS->LocateHandle(ByProtocol, &PxeBaseCodeProtocol, NULL, &size, (VOID **)dev_tab);	if (status != EFI_SUCCESS) {		ERR_PRT((L"failed to get handles: %r", status));		free(dev_tab);		return status;	}	ndev = size / sizeof(EFI_HANDLE);	for(i=0; i < ndev; i++) {		intf = NULL;		netfs_install_one(dev_tab[i].dev, &intf);		/* override device handle with interface pointer */		dev_tab[i].intf = intf;	}	return EFI_SUCCESS;}	EFI_STATUSnetfs_uninstall(VOID){		netfs_priv_state_t *nfs;	EFI_STATUS status;	UINTN i;	for(i=0; i < ndev; i++) {		if (dev_tab[i].intf == NULL) continue;		nfs = FS_PRIVATE(dev_tab[i].intf);		status = BS->UninstallProtocolInterface(nfs->dev, &NetFsProtocol, dev_tab[i].intf);		if (EFI_ERROR(status)) {			ERR_PRT((L"Uninstall %s error: %r", FS_NAME, status));			continue;		}		VERB_PRT(3,			{ EFI_DEVICE_PATH *dp; CHAR16 *str;		  	dp  = DevicePathFromHandle(nfs->dev);		  	str = DevicePathToStr(dp);		  	Print(L"uninstalled %s on %s\n", FS_NAME, str);		  	FreePool(str);			});		if (nfs->pxe->Mode->Started == TRUE) nfs->pxe->Stop(nfs->pxe);		free(dev_tab[i].intf);	}	if (dev_tab) free(dev_tab);	return EFI_SUCCESS;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?