--- Gnu-Mach/linux/dev/glue/net.c 2020/09/02 04:41:39 1.1 +++ Gnu-Mach/linux/dev/glue/net.c 2020/09/02 04:45:58 1.1.1.2 @@ -61,6 +61,7 @@ #include #include +#include #include #include @@ -69,6 +70,9 @@ #include #include +#include +#include + #include #include @@ -82,9 +86,9 @@ #include #include #include -#include "device_reply.h" - -#include +#include +#include +#include #define MACH_INCLUDE #include @@ -96,8 +100,9 @@ #include #include #include +#include -extern int linux_intr_pri; +#include /* One of these is associated with each instance of a device. */ struct net_data @@ -248,7 +253,6 @@ void dev_kfree_skb (struct sk_buff *skb, int mode) { unsigned flags; - extern void *io_done_list; /* Queue sk_buff on done list if there is a page list attached or we need to send a reply. @@ -290,6 +294,9 @@ netif_rx (struct sk_buff *skb) eh = (struct ether_header *) (net_kmsg (kmsg)->header); ph = (struct packet_header *) (net_kmsg (kmsg)->packet); memcpy (eh, skb->data, sizeof (struct ether_header)); + + /* packet is prefixed with a struct packet_header, + see include/device/net_status.h. */ memcpy (ph + 1, skb->data + sizeof (struct ether_header), skb->len - sizeof (struct ether_header)); ph->type = eh->ether_type; @@ -298,6 +305,8 @@ netif_rx (struct sk_buff *skb) dev_kfree_skb (skb, FREE_READ); + net_kmsg(kmsg)->sent = FALSE; /* Mark packet as received. */ + /* Pass packet up to the microkernel. */ net_packet (&dev->net_data->ifnet, kmsg, ph->length, ethernet_priority (kmsg)); @@ -393,8 +402,14 @@ device_open (ipc_port_t reply_port, mach } else { - dev->flags |= LINUX_IFF_UP | LINUX_IFF_RUNNING; + /* IPv6 heavily relies on multicasting (especially router and + neighbor solicits and advertisements), so enable reception of + those multicast packets by setting `LINUX_IFF_ALLMULTI'. */ + dev->flags |= LINUX_IFF_UP | LINUX_IFF_RUNNING | LINUX_IFF_ALLMULTI; skb_queue_head_init (&dev->buffs[0]); + + if (dev->set_multicast_list) + dev->set_multicast_list (dev); } if (IP_VALID (reply_port)) ds_device_open_reply (reply_port, reply_port_type, @@ -414,7 +429,6 @@ device_write (void *d, ipc_port_t reply_ { unsigned char *p; int i, amt, skblen, s; - io_return_t err = 0; vm_map_copy_t copy = (vm_map_copy_t) data; struct net_data *nd = d; struct linux_device *dev = nd->dev; @@ -436,7 +450,7 @@ device_write (void *d, ipc_port_t reply_ assert (copy->cpy_npages == 1); skb->copy = copy; - skb->data = ((void *) copy->cpy_page_list[0]->phys_addr + skb->data = ((void *) phystokv(copy->cpy_page_list[0]->phys_addr) + (copy->offset & PAGE_MASK)); skb->len = count; skb->head = skb->data; @@ -450,7 +464,7 @@ device_write (void *d, ipc_port_t reply_ skb->end = skb->tail; memcpy (skb->data, - ((void *) copy->cpy_page_list[0]->phys_addr + ((void *) phystokv(copy->cpy_page_list[0]->phys_addr) + (copy->offset & PAGE_MASK)), amt); count -= amt; @@ -460,7 +474,7 @@ device_write (void *d, ipc_port_t reply_ amt = PAGE_SIZE; if (amt > count) amt = count; - memcpy (p, (void *) copy->cpy_page_list[i]->phys_addr, amt); + memcpy (p, (void *) phystokv(copy->cpy_page_list[i]->phys_addr), amt); count -= amt; p += amt; } @@ -484,16 +498,163 @@ device_write (void *d, ipc_port_t reply_ } splx (s); + /* Send packet to filters. */ + { + struct packet_header *packet; + struct ether_header *header; + ipc_kmsg_t kmsg; + + kmsg = net_kmsg_get (); + + if (kmsg != IKM_NULL) + { + /* Suitable for Ethernet only. */ + header = (struct ether_header *) (net_kmsg (kmsg)->header); + packet = (struct packet_header *) (net_kmsg (kmsg)->packet); + memcpy (header, skb->data, sizeof (struct ether_header)); + + /* packet is prefixed with a struct packet_header, + see include/device/net_status.h. */ + memcpy (packet + 1, skb->data + sizeof (struct ether_header), + skb->len - sizeof (struct ether_header)); + packet->length = skb->len - sizeof (struct ether_header) + + sizeof (struct packet_header); + packet->type = header->ether_type; + net_kmsg (kmsg)->sent = TRUE; /* Mark packet as sent. */ + s = splimp (); + net_packet (&dev->net_data->ifnet, kmsg, packet->length, + ethernet_priority (kmsg)); + splx (s); + } + } + return MIG_NO_REPLY; } + static io_return_t device_get_status (void *d, dev_flavor_t flavor, dev_status_t status, mach_msg_type_number_t *count) { - return net_getstat (&((struct net_data *) d)->ifnet, flavor, status, count); + if (flavor == NET_FLAGS) + { + struct net_data *net = (struct net_data *) d; + + if (*count != 1) + return D_INVALID_SIZE; + + status[0] = net->dev->flags; + return D_SUCCESS; + } + + if(flavor >= SIOCIWFIRST && flavor <= SIOCIWLAST) + { + /* handle wireless ioctl */ + if(! IW_IS_GET(flavor)) + return D_INVALID_OPERATION; + + if(*count * sizeof(int) < sizeof(struct ifreq)) + return D_INVALID_OPERATION; + + struct net_data *nd = d; + struct linux_device *dev = nd->dev; + + if(! dev->do_ioctl) + return D_INVALID_OPERATION; + + int result; + + if (flavor == SIOCGIWRANGE || flavor == SIOCGIWENCODE + || flavor == SIOCGIWESSID || flavor == SIOCGIWNICKN + || flavor == SIOCGIWSPY) + { + /* + * These ioctls require an `iw_point' as their argument (i.e. + * they want to return some data to userspace. + * Therefore supply some sane values and carry the data back + * to userspace right behind the `struct iwreq'. + */ + struct iw_point *iwp = &((struct iwreq *) status)->u.data; + iwp->length = *count * sizeof (dev_status_t) - sizeof (struct ifreq); + iwp->pointer = (void *) status + sizeof (struct ifreq); + + result = dev->do_ioctl (dev, (struct ifreq *) status, flavor); + + *count = ((sizeof (struct ifreq) + iwp->length) + / sizeof (dev_status_t)); + if (iwp->length % sizeof (dev_status_t)) + (*count) ++; + } + else + { + *count = sizeof(struct ifreq) / sizeof(int); + result = dev->do_ioctl(dev, (struct ifreq *) status, flavor); + } + + return result ? D_IO_ERROR : D_SUCCESS; + } + else + { + /* common get_status request */ + return net_getstat (&((struct net_data *) d)->ifnet, flavor, + status, count); + } } + +static io_return_t +device_set_status(void *d, dev_flavor_t flavor, dev_status_t status, + mach_msg_type_number_t count) +{ + if (flavor == NET_FLAGS) + { + if (count != 1) + return D_INVALID_SIZE; + + short flags = status[0]; + struct net_data *net = (struct net_data *) d; + + dev_change_flags (net->dev, flags); + + /* Change the flags of the Mach device, too. */ + net->ifnet.if_flags = net->dev->flags; + return D_SUCCESS; + } + + if(flavor < SIOCIWFIRST || flavor > SIOCIWLAST) + return D_INVALID_OPERATION; + + if(! IW_IS_SET(flavor)) + return D_INVALID_OPERATION; + + if(count * sizeof(int) < sizeof(struct ifreq)) + return D_INVALID_OPERATION; + + struct net_data *nd = d; + struct linux_device *dev = nd->dev; + + if(! dev->do_ioctl) + return D_INVALID_OPERATION; + + if((flavor == SIOCSIWENCODE || flavor == SIOCSIWESSID + || flavor == SIOCSIWNICKN || flavor == SIOCSIWSPY) + && ((struct iwreq *) status)->u.data.pointer) + { + struct iw_point *iwp = &((struct iwreq *) status)->u.data; + + /* safety check whether the status array is long enough ... */ + if(count * sizeof(int) < sizeof(struct ifreq) + iwp->length) + return D_INVALID_OPERATION; + + /* make sure, iwp->pointer points to the correct address */ + if(iwp->pointer) iwp->pointer = (void *) status + sizeof(struct ifreq); + } + + int result = dev->do_ioctl(dev, (struct ifreq *) status, flavor); + return result ? D_IO_ERROR : D_SUCCESS; +} + + static io_return_t device_set_filter (void *d, ipc_port_t port, int priority, filter_t * filter, unsigned filter_count) @@ -513,7 +674,7 @@ struct device_emulation_ops linux_net_em NULL, NULL, NULL, - NULL, + device_set_status, device_get_status, device_set_filter, NULL,