Only linearizeblock on #M qremoves
[akaros.git] / kern / drivers / dev / ether.c
index b7c4d4c..4319b86 100644 (file)
 #include <smp.h>
 #include <ip.h>
 
-#include <vfs.h>
-#include <kfs.h>
-#include <slab.h>
-#include <kmalloc.h>
-#include <kref.h>
-#include <string.h>
-#include <stdio.h>
-#include <assert.h>
-#include <error.h>
-#include <cpio.h>
-#include <pmap.h>
-#include <smp.h>
-#include <ip.h>
-
 enum {
        Type8021Q = 0x8100,                     /* value of type field for 802.1[pQ] tags */
 };
@@ -265,6 +251,18 @@ static void etherrtrace(struct netfile *f, struct etherpkt *pkt, int len)
        qpass(f->in, bp);
 }
 
+#ifdef CONFIG_RISCV
+#warning "Potentially unaligned ethernet addrs!"
+#endif
+
+static inline int eaddrcmp(uint8_t *x, uint8_t *y)
+{
+       uint16_t *a = (uint16_t *)x;
+       uint16_t *b = (uint16_t *)y;
+
+       return (a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2]);
+}
+
 struct block *etheriq(struct ether *ether, struct block *bp, int fromwire)
 {
        struct etherpkt *pkt;
@@ -299,7 +297,7 @@ struct block *etheriq(struct ether *ether, struct block *bp, int fromwire)
 
        multi = pkt->d[0] & 1;
        /* check for valid multcast addresses */
-       if (multi && memcmp(pkt->d, ether->netif.bcast, sizeof(pkt->d)) != 0
+       if (multi && eaddrcmp(pkt->d, ether->netif.bcast) != 0
                && ether->netif.prom == 0) {
                if (!activemulti(&ether->netif, pkt->d, sizeof(pkt->d))) {
                        if (fromwire) {
@@ -311,8 +309,8 @@ struct block *etheriq(struct ether *ether, struct block *bp, int fromwire)
        }
 
        /* is it for me? */
-       tome = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
-       fromme = memcmp(pkt->s, ether->ea, sizeof(pkt->s)) == 0;
+       tome = eaddrcmp(pkt->d, ether->ea) == 0;
+       fromme = eaddrcmp(pkt->s, ether->ea) == 0;
 
        /*
         * Multiplex the packet to all the connections which want it.
@@ -362,6 +360,8 @@ static int etheroq(struct ether *ether, struct block *bp)
 
        ether->netif.outpackets++;
 
+       if (!(ether->netif.feat & NETF_SG))
+               bp = linearizeblock(bp);
        /*
         * Check if the packet has to be placed back onto the input queue,
         * i.e. if it's a loopback or broadcast packet or the interface is
@@ -373,8 +373,8 @@ static int etheroq(struct ether *ether, struct block *bp)
         */
        pkt = (struct etherpkt *)bp->rp;
        len = BLEN(bp);
-       loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
-       if (loopback || memcmp(pkt->d, ether->netif.bcast, sizeof(pkt->d)) == 0
+       loopback = eaddrcmp(pkt->d, ether->ea) == 0;
+       if (loopback || eaddrcmp(pkt->d, ether->netif.bcast) == 0
                || ether->netif.prom) {
                disable_irqsave(&irq_state);
                etheriq(ether, bp, 0);
@@ -390,6 +390,11 @@ static int etheroq(struct ether *ether, struct block *bp)
                        hnputs(bp->rp + 2 * Eaddrlen + 2, ether->vlanid & 0xFFF);       /* prio:3 0:1 vid:12 */
                        ether = ether->ctlr;
                }
+
+               if ((ether->netif.feat & NETF_PADMIN) == 0 && BLEN(bp) < ether->minmtu)
+                       bp = adjustblock(bp, ether->minmtu);
+
+               ptclcsum_finalize(bp, ether->netif.feat);
                qbwrite(ether->oq, bp);
                if (ether->transmit != NULL)
                        ether->transmit(ether);
@@ -439,8 +444,6 @@ static long etherwrite(struct chan *chan, void *buf, long n, int64_t unused)
 
        if (n > ether->maxmtu)
                error(Etoobig);
-       if (n < ether->minmtu)
-               error(Etoosmall);
        bp = allocb(n);
        if (waserror()) {
                freeb(bp);
@@ -485,10 +488,6 @@ static long etherbwrite(struct chan *chan, struct block *bp, uint32_t unused)
                freeb(bp);
                error(Etoobig);
        }
-       if (n < ether->minmtu) {
-               freeb(bp);
-               error(Etoosmall);
-       }
        n = etheroq(ether, bp);
        poperror();
        runlock(&ether->rwlock);