""" PCI Device Classifier Classifies PCI devices based on lspci output and device class information. """ import re from typing import Tuple, Optional, Dict, Any class PCIClassifier: """ Classifier for PCI devices based on device class and characteristics. """ # PCI device class mappings to type_principal and sous_type CLASS_MAPPINGS = { # Storage devices "SATA controller": ("PCI", "Contrôleur SATA"), "NVMe": ("PCI", "SSD NVMe"), "Non-Volatile memory controller": ("PCI", "SSD NVMe"), "RAID bus controller": ("PCI", "Contrôleur RAID"), "IDE interface": ("PCI", "Contrôleur IDE"), "SCSI storage controller": ("PCI", "Contrôleur SCSI"), # Network devices "Ethernet controller": ("PCI", "Carte réseau Ethernet"), "Network controller": ("PCI", "Carte réseau"), "Wireless controller": ("PCI", "Carte WiFi"), # Graphics "VGA compatible controller": ("PCI", "Carte graphique"), "3D controller": ("PCI", "Carte graphique"), "Display controller": ("PCI", "Carte graphique"), # Audio "Audio device": ("PCI", "Carte son"), "Multimedia audio controller": ("PCI", "Carte son"), # USB "USB controller": ("PCI", "Contrôleur USB"), # System infrastructure "Host bridge": ("PCI", "Pont système"), "PCI bridge": ("PCI", "Pont PCI"), "ISA bridge": ("PCI", "Pont ISA"), "SMBus": ("PCI", "Contrôleur SMBus"), "IOMMU": ("PCI", "Contrôleur IOMMU"), # Security "Encryption controller": ("PCI", "Contrôleur de chiffrement"), # Other "Serial controller": ("PCI", "Contrôleur série"), "Communication controller": ("PCI", "Contrôleur de communication"), "Signal processing controller": ("PCI", "Contrôleur de traitement du signal"), } @staticmethod def classify_device( device_section: str, device_info: Optional[Dict[str, Any]] = None ) -> Tuple[str, str]: """ Classify a PCI device based on lspci output. Args: device_section: Full lspci -v output for a single device device_info: Optional pre-parsed device information Returns: Tuple of (type_principal, sous_type) """ if not device_info: from app.utils.lspci_parser import parse_device_info device_info = parse_device_info(device_section) device_class = device_info.get("device_class", "") description = device_info.get("device_name", "") vendor_name = device_info.get("vendor_name", "") # Strategy 1: Direct class mapping for class_key, (type_principal, sous_type) in PCIClassifier.CLASS_MAPPINGS.items(): if class_key.lower() in device_class.lower(): # Refine network devices if sous_type == "Carte réseau": refined = PCIClassifier.refine_network_type(device_section, description) if refined: return ("PCI", refined) return (type_principal, sous_type) # Strategy 2: Keyword detection in description keyword_result = PCIClassifier.detect_from_keywords(device_section, description) if keyword_result: return ("PCI", keyword_result) # Strategy 3: Vendor-specific detection vendor_result = PCIClassifier.detect_from_vendor(vendor_name, description) if vendor_result: return ("PCI", vendor_result) # Default: Generic PCI device return ("PCI", "Autre") @staticmethod def refine_network_type(content: str, description: str) -> Optional[str]: """ Refine network device classification (WiFi vs Ethernet). Args: content: Full device section description: Device description Returns: Refined sous_type or None """ normalized = content.lower() + " " + description.lower() # WiFi patterns wifi_patterns = [ r"wi[‑-]?fi", r"wireless", r"802\.11[a-z]", r"wlan", r"wireless\s+adapter", r"wireless\s+network", r"atheros", r"qualcomm.*wireless", r"broadcom.*wireless", r"intel.*wireless", r"realtek.*wireless" ] for pattern in wifi_patterns: if re.search(pattern, normalized, re.IGNORECASE): return "Carte WiFi" # Ethernet patterns ethernet_patterns = [ r"ethernet", r"gigabit", r"10/100", r"1000base", r"rtl81\d+", r"e1000", r"bnx2", r"tg3" ] for pattern in ethernet_patterns: if re.search(pattern, normalized, re.IGNORECASE): return "Carte réseau Ethernet" return None @staticmethod def detect_from_keywords(content: str, description: str) -> Optional[str]: """ Detect device type from keywords in content and description. Args: content: Full device section description: Device description Returns: Detected sous_type or None """ normalized = content.lower() + " " + description.lower() keyword_mappings = [ # Storage (r"nvme|ssd.*pcie|non-volatile.*memory", "SSD NVMe"), (r"sata|ahci", "Contrôleur SATA"), # Network (r"wi[‑-]?fi|wireless|802\.11", "Carte WiFi"), (r"ethernet|gigabit|network", "Carte réseau Ethernet"), # Graphics (r"nvidia|geforce|quadro|rtx|gtx", "Carte graphique"), (r"amd.*radeon|rx\s*\d+", "Carte graphique"), (r"intel.*graphics|intel.*hd", "Carte graphique"), (r"vga|display|graphics", "Carte graphique"), # Audio (r"audio|sound|hda|ac97", "Carte son"), # USB (r"xhci|ehci|ohci|uhci|usb.*host", "Contrôleur USB"), ] for pattern, sous_type in keyword_mappings: if re.search(pattern, normalized, re.IGNORECASE): return sous_type return None @staticmethod def detect_from_vendor(vendor_name: str, description: str) -> Optional[str]: """ Detect device type from vendor name and description. Args: vendor_name: Vendor name description: Device description Returns: Detected sous_type or None """ if not vendor_name: return None vendor_lower = vendor_name.lower() # GPU vendors if any(v in vendor_lower for v in ["nvidia", "amd", "intel", "ati"]): if any(k in description.lower() for k in ["geforce", "radeon", "quadro", "graphics", "vga"]): return "Carte graphique" # Network vendors if any(v in vendor_lower for v in ["realtek", "intel", "broadcom", "qualcomm", "atheros"]): if any(k in description.lower() for k in ["ethernet", "network", "wireless", "wifi", "802.11"]): if any(k in description.lower() for k in ["wireless", "wifi", "802.11"]): return "Carte WiFi" return "Carte réseau Ethernet" # Storage vendors if any(v in vendor_lower for v in ["samsung", "crucial", "micron", "western digital", "seagate"]): if "nvme" in description.lower(): return "SSD NVMe" return None @staticmethod def extract_technical_specs(device_info: Dict[str, Any]) -> Dict[str, Any]: """ Extract technical specifications for caracteristiques_specifiques field. Args: device_info: Parsed device information Returns: Dictionary with technical specifications """ specs = { "slot": device_info.get("slot"), "device_class": device_info.get("device_class"), "vendor_name": device_info.get("vendor_name"), "subsystem": device_info.get("subsystem"), "driver": device_info.get("driver"), "iommu_group": device_info.get("iommu_group"), } # Add vendor:device ID if available if device_info.get("vendor_device_id"): specs["pci_device_id"] = device_info.get("vendor_device_id") # Add revision if available if device_info.get("revision"): specs["revision"] = device_info.get("revision") # Add modules if available if device_info.get("modules"): specs["modules"] = ", ".join(device_info.get("modules", [])) # Clean None values return {k: v for k, v in specs.items() if v is not None}