diff --git a/README.md b/README.md index 29bf36d..c03dbe5 100644 --- a/README.md +++ b/README.md @@ -23,8 +23,24 @@ puis mettre a jour le initramfs : ``` sudo update-initramfs -u + ``` +En l'etat (5/2/26) le driver s'installe, s'attache au device ch349 puis creer une interface reseau sur la machine. on peut alors recuperer le nom de l'interface grace a : + +``` +ip a +``` + +puis attribuer une IP a l'interface grace aux commandes suivantes : + +``` +sudo ip addr add 192.168.1.100/24 dev +sudo ip link set up +``` + +ce qui nous permet ensuite, depuis une autre machine d'envoyer des pings a l'ip (192.168.1.100) qui sont ensuite parses en hexadecimal et affiches sur l'interface usb (visibles en executant dmesg | grep ch349) + ## Todo - Enregistrer une interface réseau @@ -47,4 +63,3 @@ sudo update-initramfs -u ## Utile - diff --git a/src/ch349_driver.c b/src/ch349_driver.c index 2abcb71..f426ac1 100644 --- a/src/ch349_driver.c +++ b/src/ch349_driver.c @@ -5,6 +5,7 @@ * */ +#include #include #include #include @@ -23,6 +24,8 @@ struct ch349_device { __u8 bulk_out_endpointAddr; size_t bulk_in_size; unsigned char *bulk_in_buffer; + struct urb *rx_urb; + struct net_device *netdev; }; static const struct usb_device_id ch349_table[] = { @@ -32,27 +35,246 @@ static const struct usb_device_id ch349_table[] = { }; MODULE_DEVICE_TABLE(usb, ch349_table); +// Fonction pour récupérer la MAC +static int ch349_get_mac_address(struct ch349_device *dev, u8 *mac) +{ + char buf[13]; + int ret, i; + + ret = usb_string(dev->udev, 3, buf, sizeof(buf)); + if (ret != 12) { + dev_err(&dev->interface->dev, + "Cannot read MAC (got %d bytes)\n", ret); + // MAC par défaut si échec + eth_random_addr(mac); + return 0; + } + + // Convertir "DC3262229393" -> DC:32:62:22:93:93 + for (i = 0; i < 6; i++) { + char hex[3] = { buf[i * 2], buf[i * 2 + 1], 0 }; + if (kstrtou8(hex, 16, &mac[i])) { + dev_err(&dev->interface->dev, "Invalid MAC format\n"); + eth_random_addr(mac); + return 0; + } + } + + return 0; +} + +static void ch349_hexdump(const struct device *dev, const char *prefix, + const void *data, size_t len) +{ + const unsigned char *buf = data; + char line[80]; + size_t i, j; + + for (i = 0; i < len; i += 16) { + char *p = line; + p += sprintf(p, "%s %04zx: ", prefix, i); + + // Hexa + for (j = 0; j < 16; j++) { + if (i + j < len) + p += sprintf(p, "%02x ", buf[i + j]); + else + p += sprintf(p, " "); + } + + p += sprintf(p, " "); + + // ASCII + for (j = 0; j < 16 && i + j < len; j++) { + unsigned char c = buf[i + j]; + p += sprintf(p, "%c", (c >= 32 && c < 127) ? c : '.'); + } + + dev_info(dev, "%s\n", line); + } +} + +static void ch349_read_callback(struct urb *urb) +{ + struct ch349_device *dev = urb->context; + struct net_device *netdev = dev->netdev; + struct sk_buff *skb; + struct ethhdr *eth; + int status = urb->status; + + switch (status) { + case 0: // Success! + if (urb->actual_length > 0) { + dev_info(&dev->interface->dev, + "ch349: Received %d bytes\n", + urb->actual_length); + ch349_hexdump(&dev->interface->dev, "RX", + urb->transfer_buffer, urb->actual_length); + + // Créer un sk_buff et passer au network stack + skb = netdev_alloc_skb(netdev, urb->actual_length + 2); + if (skb) { + skb_reserve(skb, + 2); // Alignement IP + skb_put_data(skb, urb->transfer_buffer, + urb->actual_length); + skb->protocol = eth_type_trans(skb, netdev); + + // Passer au kernel network stack + netif_rx(skb); + + netdev->stats.rx_packets++; + netdev->stats.rx_bytes += urb->actual_length; + + printk(KERN_INFO + "ch349: Packet passed to network stack\n"); + } else { + netdev->stats.rx_dropped++; + printk(KERN_ERR "ch349: Cannot allocate skb\n"); + } + } + break; + + case -ENOENT: + case -ECONNRESET: + case -ESHUTDOWN: + return; + + default: + dev_err(&dev->interface->dev, "RX URB error: %d\n", status); + netdev->stats.rx_errors++; + break; + } + + // Resoumettre l'URB + status = usb_submit_urb(urb, GFP_ATOMIC); + if (status) { + dev_err(&dev->interface->dev, "Failed to resubmit URB: %d\n", + status); + netdev->stats.rx_errors++; + } +} + +// Fonction pour démarrer la lecture +static int ch349_start_rx(struct ch349_device *dev) +{ + struct urb *urb; + int retval; + + // Allouer un URB + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) { + dev_err(&dev->interface->dev, "Cannot allocate URB\n"); + return -ENOMEM; + } + + // En CDC-ECM, les packets peuvent être jusqu'à ~1600 bytes + + // Préparer l'URB + usb_fill_bulk_urb(urb, dev->udev, + usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr), + dev->bulk_in_buffer, dev->bulk_in_size, + ch349_read_callback, dev); + + // Sauvegarder l'URB dans la structure + dev->rx_urb = urb; + + // Soumettre l'URB + retval = usb_submit_urb(urb, GFP_KERNEL); + if (retval) { + dev_err(&dev->interface->dev, "Failed to submit URB: %d\n", + retval); + usb_free_urb(urb); + dev->rx_urb = NULL; + return retval; + } + + dev_info(&dev->interface->dev, "RX started, waiting for packets...\n"); + return 0; +} + +// Fonction pour arrêter la lecture +static void ch349_stop_rx(struct ch349_device *dev) +{ + if (dev->rx_urb) { + usb_kill_urb(dev->rx_urb); + usb_free_urb(dev->rx_urb); + dev->rx_urb = NULL; + } +} + +static int ch349_net_open(struct net_device *netdev) +{ + struct ch349_device *dev = netdev_priv(netdev); + int retval; + + printk(KERN_INFO "ch349: Interface UP\n"); + + retval = ch349_start_rx(dev); + if (retval) + return retval; + + netif_start_queue(netdev); + return 0; +} + +static int ch349_net_stop(struct net_device *netdev) +{ + struct ch349_device *dev = netdev_priv(netdev); + + printk(KERN_INFO "ch349: Interface DOWN\n"); + + netif_stop_queue(netdev); + ch349_stop_rx(dev); + + return 0; +} + +static netdev_tx_t ch349_start_xmit(struct sk_buff *skb, + struct net_device *netdev) +{ + // Pour l'instant, on drop juste les packets TX + //printk(KERN_INFO "ch349: TX packet dropped (not implemented yet)\n"); + dev_kfree_skb(skb); + netdev->stats.tx_dropped++; + return NETDEV_TX_OK; +} + +static const struct net_device_ops ch349_netdev_ops = { + .ndo_open = ch349_net_open, + .ndo_stop = ch349_net_stop, + .ndo_start_xmit = ch349_start_xmit, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, +}; + static int ch349_probe(struct usb_interface *interface, const struct usb_device_id *id) { struct ch349_device *dev; + struct net_device *netdev; struct usb_endpoint_descriptor *endpoint; - //size_t buffer_size; + u8 mac[ETH_ALEN]; int i; int retval = -ENOMEM; dev_info(&interface->dev, "Probing CH349 device\n"); - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) { - dev_err(&interface->dev, "Out of memory\n"); - goto error; + // Allouer net_device + notre structure + netdev = alloc_etherdev(sizeof(struct ch349_device)); + if (!netdev) { + dev_err(&interface->dev, "Cannot allocate netdev\n"); + return -ENOMEM; } + dev = netdev_priv(netdev); + dev->netdev = netdev; + mutex_init(&dev->io_mutex); dev->udev = usb_get_dev(interface_to_usbdev(interface)); dev->interface = interface; + // Sélectionne l'altsetting 1 retval = usb_set_interface( dev->udev, interface->cur_altsetting->desc.bInterfaceNumber, 1); if (retval) { @@ -63,15 +285,6 @@ static int ch349_probe(struct usb_interface *interface, dev_info(&interface->dev, "Interface obtained\n"); - if (dev->udev->actconfig->desc.bConfigurationValue != 2) { - retval = usb_set_configuration(dev->udev, 2); - if (retval) { - dev_err(&interface->dev, - "Cannot set configuration 2\n"); - goto error; - } - } - for (i = 0; i < interface->cur_altsetting->desc.bNumEndpoints; i++) { endpoint = &interface->cur_altsetting->endpoint[i].desc; @@ -81,7 +294,7 @@ static int ch349_probe(struct usb_interface *interface, if (!dev->bulk_in_endpointAddr && usb_endpoint_is_bulk_in(endpoint)) { dev->bulk_in_endpointAddr = endpoint->bEndpointAddress; - dev->bulk_in_size = usb_endpoint_maxp(endpoint); + dev->bulk_in_size = 2048; // Buffer ethernet dev->bulk_in_buffer = kmalloc(dev->bulk_in_size, GFP_KERNEL); if (!dev->bulk_in_buffer) { @@ -109,29 +322,61 @@ static int ch349_probe(struct usb_interface *interface, goto error; } + // Récupère la MAC + ch349_get_mac_address(dev, mac); + eth_hw_addr_set(netdev, mac); + + // Configure net_device + netdev->netdev_ops = &ch349_netdev_ops; + netdev->watchdog_timeo = 5 * HZ; + usb_set_intfdata(interface, dev); - dev_info(&interface->dev, "CH349 device now attached\n"); + // Enregistre l'interface réseau + retval = register_netdev(netdev); + if (retval) { + dev_err(&interface->dev, "Cannot register netdev: %d\n", + retval); + goto error; + } + + dev_info(&interface->dev, "CH349 attached as %s (MAC: %pM)\n", + netdev->name, mac); + + //retval = ch349_start_rx(dev); + //if (retval) + // goto error; return 0; error: - if (dev) + if (dev) { kfree(dev->bulk_in_buffer); - kfree(dev); + usb_put_dev(dev->udev); + } + if (netdev) + free_netdev(netdev); return retval; } static void ch349_disconnect(struct usb_interface *interface) { struct ch349_device *dev; + struct net_device *netdev; dev = usb_get_intfdata(interface); + if (!dev) + return; + + netdev = dev->netdev; usb_set_intfdata(interface, NULL); + unregister_netdev(netdev); + ch349_stop_rx(dev); + kfree(dev->bulk_in_buffer); usb_put_dev(dev->udev); - kfree(dev); + free_netdev(netdev); dev_info(&interface->dev, "CH349 device now disconnected\n"); }