-// INFERNO
-#include <vfs.h>
-#include <kfs.h>
+/* Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+ * Portions Copyright © 1997-1999 Vita Nuova Limited
+ * Portions Copyright © 2000-2007 Vita Nuova Holdings Limited
+ * (www.vitanuova.com)
+ * Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+ *
+ * Modified for the Akaros operating system:
+ * Copyright (c) 2013-2014 The Regents of the University of California
+ * Copyright (c) 2013-2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE. */
+
#include <slab.h>
#include <kmalloc.h>
#include <kref.h>
#include <cpio.h>
#include <pmap.h>
#include <smp.h>
-#include <ip.h>
+#include <net/ip.h>
-typedef struct Ip4hdr Ip4hdr;
typedef struct IP IP;
typedef struct Fragment4 Fragment4;
typedef struct Fragment6 Fragment6;
typedef struct Ipfrag Ipfrag;
enum {
- IP4HDR = 20, /* sizeof(Ip4hdr) */
- IP6HDR = 40, /* sizeof(Ip6hdr) */
+ IP4HDR = 20, /* sizeof(Ip4hdr) */
+ IP6HDR = 40, /* sizeof(Ip6hdr) */
IP_HLEN4 = 0x05, /* Header length in words */
- IP_DF = 0x4000, /* Don't fragment */
- IP_MF = 0x2000, /* More fragments */
- IP6FHDR = 8, /* sizeof(Fraghdr6) */
+ IP_DF = 0x4000, /* Don't fragment */
+ IP_MF = 0x2000, /* More fragments */
+ IP6FHDR = 8, /* sizeof(Fraghdr6) */
IP_MAX = 64 * 1024, /* Maximum Internet packet size */
};
#define BLKIPVER(xp) (((struct Ip4hdr*)((xp)->rp))->vihl&0xF0)
#define NEXT_ID(x) (__sync_add_and_fetch(&(x), 1))
-struct Ip4hdr {
- uint8_t vihl; /* Version and header length */
- uint8_t tos; /* Type of service */
- uint8_t length[2]; /* packet length */
- uint8_t id[2]; /* ip->identification */
- uint8_t frag[2]; /* Fragment information */
- uint8_t ttl; /* Time to live */
- uint8_t proto; /* Protocol */
- uint8_t cksum[2]; /* Header checksum */
- uint8_t src[4]; /* IP source */
- uint8_t dst[4]; /* IP destination */
-};
-
/* MIB II counters */
enum {
Forwarding,
uint32_t src;
uint32_t dst;
uint16_t id;
- uint32_t age;
+ uint64_t age;
};
struct fragment6 {
uint8_t src[IPaddrlen];
uint8_t dst[IPaddrlen];
unsigned int id;
- uint32_t age;
+ uint64_t age;
};
struct Ipfrag {
struct fragment6 *fragfree6;
int id6;
- int iprouting; /* true if we route like a gateway */
+ int iprouting; /* true if we route like a gateway */
};
static char *statnames[] = {
#define BKFG(xp) ((struct Ipfrag*)((xp)->base))
uint16_t ipcsum(uint8_t * unused_uint8_p_t);
-struct block *ip4reassemble(struct IP *, int unused_int,
- struct block *, struct Ip4hdr *);
+struct block *ip4reassemble(struct IP *, int unused_int, struct block *,
+ struct Ip4hdr *);
void ipfragfree4(struct IP *, struct fragment4 *);
struct fragment4 *ipfragallo4(struct IP *);
struct fragment6 *fq6, *eq6;
ip->fragfree4 =
- (struct fragment4 *)kzmalloc(sizeof(struct fragment4) * size, 0);
+ (struct fragment4 *)kzmalloc(sizeof(struct fragment4) * size, 0);
if (ip->fragfree4 == NULL)
panic("initfrag");
ip->fragfree4[size - 1].next = NULL;
ip->fragfree6 =
- (struct fragment6 *)kzmalloc(sizeof(struct fragment6) * size, 0);
+ (struct fragment6 *)kzmalloc(sizeof(struct fragment6) * size, 0);
if (ip->fragfree6 == NULL)
panic("initfrag");
f->ip->stats[Forwarding] = 1;
}
-int
-ipoput4(struct Fs *f,
- struct block *bp, int gating, int ttl, int tos, struct conv *c)
+int ipoput4(struct Fs *f, struct block *bp, int gating, int ttl, int tos, struct
+ conv *c)
{
ERRSTACK(1);
struct Ipifc *ifc;
ip = f->ip;
+ /* Sanity check for our transport protocols. */
+ if (bp->mss)
+ assert(bp->flag & Btso);
/* Fill out the ip header */
eh = (struct Ip4hdr *)(bp->rp);
/* If we dont need to fragment just send it */
medialen = ifc->maxtu - ifc->m->hsize;
- if (len <= medialen) {
+ if (bp->flag & Btso || len <= medialen) {
if (!gating)
hnputs(eh->id, NEXT_ID(ip->id4));
hnputs(eh->length, len);
if (!gating) {
- eh->frag[0] = 0;
+ eh->frag[0] = 0x40;
eh->frag[1] = 0;
}
eh->cksum[0] = 0;
goto raise;
}
+ /* compute tcp/udp checksum in software before fragmenting */
+ ptclcsum_finalize(bp, 0);
+
dlen = len - IP4HDR;
xp = bp;
if (gating)
else
lid = NEXT_ID(ip->id4);
+ /* advance through the blist enough to drop IP4HDR size. this should
+ * usually just be the first block. */
offset = IP4HDR;
while (xp != NULL && offset && offset >= BLEN(xp)) {
offset -= BLEN(xp);
fragoff = 0;
dlen += fragoff;
for (; fragoff < dlen; fragoff += seglen) {
- nb = allocb(IP4HDR + seglen);
+ nb = blist_clone(xp, IP4HDR, seglen, fragoff);
feh = (struct Ip4hdr *)(nb->rp);
memmove(nb->wp, eh, IP4HDR);
hnputs(feh->length, seglen + IP4HDR);
hnputs(feh->id, lid);
- /* Copy up the data area */
- chunk = seglen;
- while (chunk) {
- if (!xp) {
- ip->stats[OutDiscards]++;
- ip->stats[FragFails]++;
- freeblist(nb);
- netlog(f, Logip, "!xp: chunk %d\n", chunk);
- goto raise;
- }
- blklen = chunk;
- if (BLEN(xp) < chunk)
- blklen = BLEN(xp);
- memmove(nb->wp, xp->rp, blklen);
- nb->wp += blklen;
- xp->rp += blklen;
- chunk -= blklen;
- if (xp->rp == xp->wp)
- xp = xp->next;
- }
-
feh->cksum[0] = 0;
feh->cksum[1] = 0;
hnputs(feh->cksum, ipcsum(&feh->vihl));
struct IP *ip;
struct route *r;
+ bp = pullupblock(bp, 1);
if (BLKIPVER(bp) != IP_VER4) {
ipiput6(f, ifc, bp);
return;
hl = (h->vihl & 0xF) << 2;
if (hl < (IP_HLEN4 << 2)) {
ip->stats[InHdrErrors]++;
- netlog(f, Logip, "ip: %V bad hivl 0x%x\n", h->src, h->vihl);
+ netlog(f, Logip, "ip: %V bad hivl 0x%x\n", h->src,
+ h->vihl);
freeblist(bp);
return;
}
}
frag = nhgets(h->frag);
- if (frag) {
+ if (frag && frag != IP_DF) {
h->tos = 0;
if (frag & IP_MF)
h->tos = 1;
p = buf;
e = p + len;
for (i = 0; i < Nstats; i++)
- p = seprintf(p, e, "%s: %lu\n", statnames[i], ip->stats[i]);
+ p = seprintf(p, e, "%s: %u\n", statnames[i], ip->stats[i]);
return p - buf;
}
* find a reassembly queue for this fragment
*/
for (f = ip->flisthead4; f; f = fnext) {
- fnext = f->next; /* because ipfragfree4 changes the list */
+ fnext = f->next;/* because ipfragfree4 changes the list */
if (f->src == src && f->dst == dst && f->id == id)
break;
if (f->age < NOW) {