|  | /* 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. */ | 
|  |  | 
|  |  | 
|  | #pragma once | 
|  | #include <ns.h> | 
|  |  | 
|  | enum { | 
|  | Addrlen = 64, | 
|  | Maxproto = 20, | 
|  | Nhash = 64, | 
|  | Maxincall = 500, | 
|  | Nchans = 256, | 
|  | MAClen = 16,	/* longest mac address */ | 
|  |  | 
|  | MAXTTL = 255, | 
|  | DFLTTOS = 0, | 
|  |  | 
|  | IPaddrlen = 16, | 
|  | IPv4addrlen = 4, | 
|  | IPv4off = 12, | 
|  | IPllen = 4, | 
|  |  | 
|  | /* ip versions */ | 
|  | V4 = 4, | 
|  | V6 = 6, | 
|  | IP_VER4 = 0x40, | 
|  | IP_VER6 = 0x60, | 
|  |  | 
|  | /* 2^Lroot trees in the root table */ | 
|  | Lroot = 10, | 
|  |  | 
|  | Maxpath = 64, | 
|  | }; | 
|  |  | 
|  | enum { | 
|  | Idle = 0, | 
|  | Announcing = 1, | 
|  | Announced = 2, | 
|  | Connecting = 3, | 
|  | Connected = 4, | 
|  | Bypass = 5, | 
|  | }; | 
|  |  | 
|  | enum { | 
|  | SHUT_RD = 0, | 
|  | SHUT_WR = 1, | 
|  | SHUT_RDWR = 2, | 
|  | }; | 
|  |  | 
|  | /* | 
|  | *  one per conversation directory | 
|  | */ | 
|  | struct Proto; | 
|  | struct conv { | 
|  | qlock_t qlock; | 
|  |  | 
|  | int x;			/* conversation index */ | 
|  | struct Proto *p; | 
|  |  | 
|  | int restricted;		/* remote port is restricted */ | 
|  | uint32_t ttl;		/* max time to live */ | 
|  | uint32_t tos;		/* type of service */ | 
|  | int ignoreadvice;	/* don't terminate connection on icmp errors */ | 
|  |  | 
|  | uint8_t ipversion; | 
|  | uint8_t laddr[IPaddrlen];/* local IP address */ | 
|  | uint8_t raddr[IPaddrlen];/* remote IP address */ | 
|  | uint16_t lport;		/* local port number */ | 
|  | uint16_t rport;		/* remote port number */ | 
|  |  | 
|  | char *owner;		/* protections */ | 
|  | int perm; | 
|  | int inuse;		/* opens of listen/data/ctl */ | 
|  | int length; | 
|  | int state; | 
|  | struct queue *rq_save;	/* rq created by proto, saved during bypass */ | 
|  | struct queue *wq_save;	/* wq created by proto, saved during bypass */ | 
|  |  | 
|  | /* udp specific */ | 
|  | int headers;		/* data src/dst headers in udp */ | 
|  | int reliable;		/* true if reliable udp */ | 
|  |  | 
|  | struct conv *incall;	/* calls waiting to be listened for */ | 
|  | struct conv *next; | 
|  |  | 
|  | struct queue *rq;	/* queued data waiting to be read */ | 
|  | struct queue *wq;	/* queued data waiting to be written */ | 
|  | struct queue *eq;	/* returned error packets */ | 
|  | struct queue *sq;	/* snooping queue */ | 
|  | atomic_t snoopers;	/* number of processes with snoop open */ | 
|  |  | 
|  | struct fdtap_slist data_taps; | 
|  | struct fdtap_slist listen_taps; | 
|  | spinlock_t tap_lock; | 
|  |  | 
|  | struct rendez cr; | 
|  | char cerr[ERRMAX]; | 
|  |  | 
|  | qlock_t listenq; | 
|  | struct rendez listenr; | 
|  |  | 
|  | struct Ipmulti *multi;	/* multicast bindings for this interface */ | 
|  |  | 
|  | void *ptcl;		/* Protocol specific stuff */ | 
|  |  | 
|  | struct route *r;	/* last route used */ | 
|  | uint32_t rgen;		/* routetable generation for *r */ | 
|  | }; | 
|  |  | 
|  | struct Ipifc; | 
|  | struct Fs; | 
|  |  | 
|  | struct medium { | 
|  | char *name; | 
|  | int hsize;		/* medium header size */ | 
|  | int mintu;		/* default min mtu */ | 
|  | int maxtu;		/* default max mtu */ | 
|  | int maclen;		/* mac address length  */ | 
|  | void (*bind) (struct Ipifc * unused_Ipifc, int unused_int, | 
|  | char **unused_char_pp_t); | 
|  | void (*unbind) (struct Ipifc * unused_Ipifc); | 
|  | void (*bwrite) (struct Ipifc * ifc, struct block * b, int version, | 
|  | uint8_t * ip); | 
|  |  | 
|  | /* for arming interfaces to receive multicast */ | 
|  | void (*addmulti) (struct Ipifc * ifc, uint8_t * a, uint8_t * ia); | 
|  | void (*remmulti) (struct Ipifc * ifc, uint8_t * a, uint8_t * ia); | 
|  |  | 
|  | /* process packets written to 'data' */ | 
|  | void (*pktin) (struct Fs * f, struct Ipifc * ifc, struct block * bp); | 
|  |  | 
|  | /* routes for router boards */ | 
|  | void (*addroute) (struct Ipifc * ifc, int unused_int, uint8_t * u8p, | 
|  | uint8_t *, uint8_t * u8p2, int); | 
|  | void (*remroute) (struct Ipifc * ifc, int i, uint8_t * u8p, | 
|  | uint8_t * uu8p2); | 
|  | void (*flushroutes) (struct Ipifc * ifc); | 
|  |  | 
|  | /* for routing multicast groups */ | 
|  | void (*joinmulti) (struct Ipifc * ifc, uint8_t * a, uint8_t * ia); | 
|  | void (*leavemulti) (struct Ipifc * ifc, uint8_t * a, uint8_t * ia); | 
|  |  | 
|  | /* address resolution */ | 
|  | void (*ares) (struct Fs *, int unused_int, uint8_t * unused_uint8_p_t, | 
|  | uint8_t *, int, int);	/* resolve */ | 
|  | void (*areg) (struct Ipifc * unused_Ipifc, | 
|  | uint8_t * unused_uint8_p_t);	/* register */ | 
|  |  | 
|  | /* v6 address generation */ | 
|  | void (*pref2addr) (uint8_t * pref, uint8_t * ea); | 
|  |  | 
|  | int unbindonclose;	/* if non-zero, unbind on last close */ | 
|  | }; | 
|  |  | 
|  | /* logical interface associated with a physical one */ | 
|  | struct Iplifc { | 
|  | uint8_t local[IPaddrlen]; | 
|  | uint8_t mask[IPaddrlen]; | 
|  | uint8_t remote[IPaddrlen]; | 
|  | uint8_t net[IPaddrlen]; | 
|  | uint8_t tentative; /* =1 => v6 dup disc on, =0 => confirmed unique */ | 
|  | uint8_t onlink;			/* =1 => onlink, =0 offlink. */ | 
|  | uint8_t autoflag;		/* v6 autonomous flag */ | 
|  | uint64_t validlt;		/* v6 valid lifetime */ | 
|  | uint64_t preflt;		/* v6 preferred lifetime */ | 
|  | uint64_t origint;		/* time when addr was added */ | 
|  | struct Iplink *link;		/* addresses linked to this lifc */ | 
|  | struct Iplifc *next; | 
|  | }; | 
|  |  | 
|  | /* binding twixt Ipself and Iplifc */ | 
|  | struct Iplink { | 
|  | struct Ipself *self; | 
|  | struct Iplifc *lifc; | 
|  | struct Iplink *selflink;	/* next link for this local address */ | 
|  | struct Iplink *lifclink;	/* next link for this ifc */ | 
|  | uint64_t expire; | 
|  | struct Iplink *next;		/* free list */ | 
|  | struct kref ref; | 
|  | }; | 
|  |  | 
|  | /* rfc 2461, pp.40--43. */ | 
|  |  | 
|  | /* default values, one per stack */ | 
|  | struct routerparams { | 
|  | int mflag; | 
|  | int oflag; | 
|  | int maxraint; | 
|  | int minraint; | 
|  | int linkmtu; | 
|  | int reachtime; | 
|  | int rxmitra; | 
|  | int ttl; | 
|  | int routerlt; | 
|  | }; | 
|  |  | 
|  | struct Ipifc { | 
|  | rwlock_t rwlock; | 
|  |  | 
|  | struct conv *conv;	/* link to its conversation structure */ | 
|  | char dev[64];		/* device we're attached to */ | 
|  | struct medium *m;	/* Media pointer */ | 
|  | int maxtu;		/* Maximum transfer unit */ | 
|  | int mintu;		/* Minumum tranfer unit */ | 
|  | unsigned int feat;	/* Offload features */ | 
|  | void *arg;		/* medium specific */ | 
|  | int reassemble;		/* reassemble IP packets before forwarding */ | 
|  |  | 
|  | /* these are used so that we can unbind on the fly */ | 
|  | spinlock_t idlock; | 
|  | uint8_t ifcid;		/* incremented each 'bind/unbind/add/remove' */ | 
|  | int ref;		/* number of proc's using this Ipifc */ | 
|  | struct rendez wait;	/* where unbinder waits for ref == 0 */ | 
|  | int unbinding; | 
|  |  | 
|  | uint8_t mac[MAClen];	/* MAC address */ | 
|  |  | 
|  | struct Iplifc *lifc;	/* logical interfaces on this physical one */ | 
|  |  | 
|  | uint32_t in, out;	/* message statistics */ | 
|  | uint32_t inerr, outerr;	/* ... */ | 
|  | uint32_t tracedrop; | 
|  |  | 
|  | uint8_t sendra6;	/* == 1 => send router advs on this ifc */ | 
|  | uint8_t recvra6;	/* == 1 => recv router advs on this ifc */ | 
|  | struct routerparams rp;	/* router parameters as in RFC 2461, pp.40--43. | 
|  | used only if node is router */ | 
|  | }; | 
|  |  | 
|  | /* | 
|  | *  one per multicast-lifc pair used by a struct conv | 
|  | */ | 
|  | struct Ipmulti { | 
|  | uint8_t ma[IPaddrlen]; | 
|  | uint8_t ia[IPaddrlen]; | 
|  | struct Ipmulti *next; | 
|  | }; | 
|  |  | 
|  | /* | 
|  | *  hash table for 2 ip addresses + 2 ports | 
|  | */ | 
|  | enum { | 
|  | Nipht = 521,		/* convenient prime */ | 
|  |  | 
|  | IPmatchexact = 0,	/* match on 4 tuple */ | 
|  | IPmatchany,	/* *!* */ | 
|  | IPmatchport,	/* *!port */ | 
|  | IPmatchaddr,	/* addr!* */ | 
|  | IPmatchpa,	/* addr!port */ | 
|  | }; | 
|  | struct Iphash { | 
|  | struct Iphash *next; | 
|  | struct conv *c; | 
|  | int match; | 
|  | }; | 
|  |  | 
|  | struct Iphash; | 
|  | struct Ipht { | 
|  | spinlock_t lock; | 
|  | struct Iphash *tab[Nipht]; | 
|  | }; | 
|  | void iphtadd(struct Ipht *, struct conv *); | 
|  | void iphtrem(struct Ipht *, struct conv *); | 
|  | struct conv *iphtlook(struct Ipht *ht, uint8_t * sa, uint16_t sp, uint8_t * da, | 
|  | uint16_t dp); | 
|  | void dump_ipht(struct Ipht *ht); | 
|  |  | 
|  | /* | 
|  | *  one per multiplexed Protocol | 
|  | */ | 
|  | struct Proto { | 
|  | qlock_t qlock; | 
|  | char *name;		/* protocol name */ | 
|  | int x;			/* protocol index */ | 
|  | int ipproto;		/* ip protocol type */ | 
|  |  | 
|  | void (*connect)(struct conv *, char **, int); | 
|  | void (*announce)(struct conv *, char **, int); | 
|  | void (*bind)(struct conv *, char **, int); | 
|  | void (*bypass)(struct conv *, char **, int); | 
|  | int (*state) (struct conv *, char *unused_char_p_t, int); | 
|  | void (*create) (struct conv *); | 
|  | void (*close) (struct conv *); | 
|  | void (*shutdown)(struct conv *, int); | 
|  | void (*rcv) (struct Proto *, struct Ipifc *, struct block *); | 
|  | void (*ctl)(struct conv *, char **, int); | 
|  | void (*advise) (struct Proto *, struct block *, char *unused_char_p_t); | 
|  | int (*stats) (struct Proto *, char *unused_char_p_t, int); | 
|  | int (*local) (struct conv *, char *unused_char_p_t, int); | 
|  | int (*remote) (struct conv *, char *unused_char_p_t, int); | 
|  | int (*inuse) (struct conv *); | 
|  | /* returns true if any conversations are freed */ | 
|  | int (*gc) (struct Proto *); | 
|  |  | 
|  | struct Fs *f;		/* file system this proto is part of */ | 
|  | struct conv **conv;	/* array of conversations */ | 
|  | int ptclsize;		/* size of per protocol ctl block */ | 
|  | int nc;			/* number of conversations */ | 
|  | int ac; | 
|  | struct qid qid;		/* qid for protocol directory */ | 
|  | uint16_t nextport; | 
|  | uint16_t nextrport; | 
|  |  | 
|  | void *priv; | 
|  | }; | 
|  |  | 
|  | /* | 
|  | *  Stream for sending packets to user level | 
|  | */ | 
|  | struct IProuter { | 
|  | qlock_t qlock; | 
|  | int opens; | 
|  | struct queue *q; | 
|  | }; | 
|  |  | 
|  | /* | 
|  | *  one per IP protocol stack | 
|  | */ | 
|  | struct Fs { | 
|  | rwlock_t rwlock; | 
|  | int dev; | 
|  |  | 
|  | int np; | 
|  | struct Proto *p[Maxproto + 1];	/* list of supported protocols */ | 
|  | struct Proto *t2p[256];		/* vector of all protocols */ | 
|  | struct Proto *ipifc;	/* kludge for ipifcremroute & ipifcaddroute */ | 
|  | struct Proto *ipmux;	/* kludge for finding an ip multiplexor */ | 
|  |  | 
|  | struct IP *ip; | 
|  | struct Ipselftab *self; | 
|  | struct arp *arp; | 
|  | struct V6params *v6p; | 
|  | struct IProuter iprouter; | 
|  |  | 
|  | struct route *v4root[1 << Lroot];	/* v4 routing forest */ | 
|  | struct route *v6root[1 << Lroot];	/* v6 routing forest */ | 
|  | struct route *queue;	/* used as temp when reinjecting routes */ | 
|  |  | 
|  | struct Netlog *alog; | 
|  | struct Ifclog *ilog; | 
|  |  | 
|  | char ndb[1024];		/* an ndb entry for this interface */ | 
|  | int ndbvers; | 
|  | long ndbmtime; | 
|  | }; | 
|  |  | 
|  | /* one per default router known to host */ | 
|  | struct V6router { | 
|  | uint8_t inuse; | 
|  | struct Ipifc *ifc; | 
|  | int ifcid; | 
|  | uint8_t routeraddr[IPaddrlen]; | 
|  | long ltorigin; | 
|  | struct routerparams rp; | 
|  | }; | 
|  |  | 
|  | struct hostparams { | 
|  | int rxmithost; | 
|  | }; | 
|  |  | 
|  | struct V6params { | 
|  | struct routerparams rp;		/* v6 params, one copy per node now */ | 
|  | struct hostparams hp; | 
|  | struct V6router v6rlist[3];	/* max 3 default routers, currently */ | 
|  | int cdrouter;			/* uses only v6rlist[cdrouter] if   */ | 
|  | /* cdrouter >= 0. */ | 
|  | }; | 
|  |  | 
|  | int Fsconnected(struct conv *, char *unused_char_p_t); | 
|  | struct conv *Fsnewcall(struct conv *, uint8_t * unused_uint8_p_t, uint16_t, | 
|  | uint8_t *, uint16_t, uint8_t unused_uint8_t); | 
|  | int Fspcolstats(char *unused_char_p_t, int); | 
|  | int Fsproto(struct Fs *, struct Proto *); | 
|  | int Fsbuiltinproto(struct Fs *, uint8_t unused_uint8_t); | 
|  | struct conv *Fsprotoclone(struct Proto *, char *unused_char_p_t); | 
|  | struct Proto *Fsrcvpcol(struct Fs *, uint8_t unused_uint8_t); | 
|  | struct Proto *Fsrcvpcolx(struct Fs *, uint8_t unused_uint8_t); | 
|  | void Fsstdconnect(struct conv *, char **, int); | 
|  | void Fsstdannounce(struct conv *, char **, int); | 
|  | void Fsstdbypass(struct conv *, char **, int); | 
|  | void Fsstdbind(struct conv *, char **, int); | 
|  | uint32_t scalednconv(void); | 
|  | void bypass_or_drop(struct conv *cv, struct block *bp); | 
|  |  | 
|  | /* | 
|  | *  logging | 
|  | */ | 
|  | enum { | 
|  | Logip = 1 << 1, | 
|  | Logtcp = 1 << 2, | 
|  | Logfs = 1 << 3, | 
|  | Logil = 1 << 4, | 
|  | Logicmp = 1 << 5, | 
|  | Logudp = 1 << 6, | 
|  | Logcompress = 1 << 7, | 
|  | Logilmsg = 1 << 8, | 
|  | Loggre = 1 << 9, | 
|  | Logppp = 1 << 10, | 
|  | Logtcprxmt = 1 << 11, | 
|  | Logigmp = 1 << 12, | 
|  | Logudpmsg = 1 << 13, | 
|  | Logipmsg = 1 << 14, | 
|  | Logrudp = 1 << 15, | 
|  | Logrudpmsg = 1 << 16, | 
|  | Logesp = 1 << 17, | 
|  | Logtcpreset = 1 << 18, | 
|  | Logtcpverbose = 1 << 19, | 
|  | }; | 
|  |  | 
|  | void netloginit(struct Fs *); | 
|  | void netlogopen(struct Fs *); | 
|  | void netlogclose(struct Fs *); | 
|  | void netlogctl(struct Fs *, char *unused_char_p_t, size_t); | 
|  | long netlogread(struct Fs *, void *, uint32_t, long); | 
|  | void netlog(struct Fs *, int unused_int, char *unused_char_p_t, ...); | 
|  | void ifcloginit(struct Fs *); | 
|  | long ifclogread(struct Fs *, struct chan *, void *, uint32_t, long); | 
|  | void ifclog(struct Fs *, uint8_t *, int); | 
|  | void ifclogopen(struct Fs *, struct chan *); | 
|  | void ifclogclose(struct Fs *, struct chan *); | 
|  |  | 
|  | /* | 
|  | *  iproute.c | 
|  | */ | 
|  |  | 
|  | enum { | 
|  |  | 
|  | /* type bits */ | 
|  | Rv4 = (1 << 0),		/* this is a version 4 route */ | 
|  | Rifc = (1 << 1),	/* route is a directly connected interface */ | 
|  | Rptpt = (1 << 2),	/* this route is a pt to pt interface */ | 
|  | Runi = (1 << 3),	/* a unicast self address */ | 
|  | Rbcast = (1 << 4),	/* a broadcast self address */ | 
|  | Rmulti = (1 << 5),	/* a multicast self address */ | 
|  | Rproxy = (1 << 6),	/* this route should be proxied */ | 
|  | }; | 
|  |  | 
|  | struct routewalk { | 
|  | int o; | 
|  | int h; | 
|  | char *p; | 
|  | char *e; | 
|  | void *state; | 
|  | void (*walk) (struct route *, struct routewalk *); | 
|  | }; | 
|  |  | 
|  | struct RouteTree { | 
|  | struct route *right; | 
|  | struct route *left; | 
|  | struct route *mid; | 
|  | uint8_t depth; | 
|  | uint8_t type; | 
|  | uint8_t ifcid;		/* must match ifc->id */ | 
|  | struct Ipifc *ifc; | 
|  | char tag[4]; | 
|  | struct kref kref; | 
|  | }; | 
|  |  | 
|  | struct V4route { | 
|  | uint32_t address; | 
|  | uint32_t endaddress; | 
|  | uint8_t gate[IPv4addrlen]; | 
|  | }; | 
|  |  | 
|  | struct V6route { | 
|  | uint32_t address[IPllen]; | 
|  | uint32_t endaddress[IPllen]; | 
|  | uint8_t gate[IPaddrlen]; | 
|  | }; | 
|  |  | 
|  | struct route { | 
|  | struct RouteTree rt; | 
|  |  | 
|  | union { | 
|  | struct V6route v6; | 
|  | struct V4route v4; | 
|  | }; | 
|  | }; | 
|  | extern void v4addroute(struct Fs *f, char *tag, uint8_t * a, uint8_t * mask, | 
|  | uint8_t * gate, int type); | 
|  | extern void v6addroute(struct Fs *f, char *tag, uint8_t * a, uint8_t * mask, | 
|  | uint8_t * gate, int type); | 
|  | extern void v4delroute(struct Fs *f, uint8_t * a, uint8_t * mask, int dolock); | 
|  | extern void v6delroute(struct Fs *f, uint8_t * a, uint8_t * mask, int dolock); | 
|  | extern struct route *v4lookup(struct Fs *f, uint8_t * a, struct conv *c); | 
|  | extern struct route *v6lookup(struct Fs *f, uint8_t * a, struct conv *c); | 
|  | extern long routeread(struct Fs *f, char *unused_char_p_t, uint32_t, int); | 
|  | extern long routewrite(struct Fs *f, struct chan *, char *unused_char_p_t, | 
|  | size_t); | 
|  | extern void routetype(int unused_int, char *unused_char_p_t); | 
|  | extern void ipwalkroutes(struct Fs *, struct routewalk *); | 
|  | extern void convroute(struct route *r, uint8_t * u8pt, uint8_t * u8pt1, | 
|  | uint8_t * u8pt2, char *unused_char_p_t, int *intp); | 
|  |  | 
|  | /* | 
|  | *  devip.c | 
|  | */ | 
|  |  | 
|  | /* | 
|  | *  Hanging off every ip channel's ->aux is the following structure. | 
|  | *  It maintains the state used by devip and iproute. | 
|  | */ | 
|  | struct IPaux { | 
|  | char *owner;		/* the user that did the attach */ | 
|  | char tag[4]; | 
|  | }; | 
|  |  | 
|  | extern struct IPaux *newipaux(char *unused_char_p_t, char *); | 
|  |  | 
|  | /* | 
|  | *  arp.c | 
|  | */ | 
|  | struct arpent { | 
|  | uint8_t ip[IPaddrlen]; | 
|  | uint8_t mac[MAClen]; | 
|  | struct medium *type;	/* media type */ | 
|  | struct arpent *hash; | 
|  | struct block *hold; | 
|  | struct block *last; | 
|  | uint64_t ctime;		/* time entry was created or refreshed */ | 
|  | uint64_t utime;		/* time entry was last used */ | 
|  | uint8_t state; | 
|  | struct arpent *nextrxt;	/* re-transmit chain */ | 
|  | uint64_t rtime;		/* time for next retransmission */ | 
|  | uint8_t rxtsrem; | 
|  | struct Ipifc *ifc; | 
|  | uint8_t ifcid;		/* must match ifc->id */ | 
|  | }; | 
|  |  | 
|  | extern void arpinit(struct Fs *); | 
|  | extern int arpread(struct arp *, char *unused_char_p_t, uint32_t, int); | 
|  | extern int arpwrite(struct Fs *, char *unused_char_p_t, long); | 
|  | extern struct arpent *arpget(struct arp *, struct block *bp, int version, | 
|  | struct Ipifc *ifc, uint8_t * ip, uint8_t * h); | 
|  | extern void arprelease(struct arp *, struct arpent *a); | 
|  | extern struct block *arpresolve(struct arp *, struct arpent *a, | 
|  | struct medium *type, uint8_t * mac); | 
|  | extern void arpenter(struct Fs *, int version, uint8_t * ip, uint8_t * mac, | 
|  | int len, int norefresh); | 
|  |  | 
|  | /* | 
|  | * ipaux.c | 
|  | */ | 
|  |  | 
|  | extern int myetheraddr(uint8_t * unused_uint8_p_t, char *unused_char_p_t); | 
|  | extern uint32_t parseip(uint8_t * unused_uint8_p_t, char *unused_char_p_t); | 
|  | extern uint32_t parseipmask(uint8_t * unused_uint8_p_t, char *unused_char_p_t); | 
|  | extern char *v4parseip(uint8_t * unused_uint8_p_t, char *unused_char_p_t); | 
|  | extern void maskip(uint8_t * from, uint8_t * mask, uint8_t * to); | 
|  | extern int parsemac(uint8_t * to, char *from, int len); | 
|  | extern uint8_t *defmask(uint8_t * unused_uint8_p_t); | 
|  | extern int isv4(uint8_t * unused_uint8_p_t); | 
|  | extern void v4tov6(uint8_t * v6, uint8_t * v4); | 
|  | extern int v6tov4(uint8_t * v4, uint8_t * v6); | 
|  | //extern int    eipfmt(Fmt*); | 
|  |  | 
|  |  | 
|  | #ifdef CONFIG_RISCV | 
|  | #warning "Potentially unaligned IP addrs!" | 
|  | #endif | 
|  | static inline void ipmove(unsigned char *x, unsigned char *y) | 
|  | { | 
|  | uint32_t *a = (uint32_t *)x; | 
|  | uint32_t *b = (uint32_t *)y; | 
|  |  | 
|  | a[0] = b[0]; | 
|  | a[1] = b[1]; | 
|  | a[2] = b[2]; | 
|  | a[3] = b[3]; | 
|  | } | 
|  |  | 
|  | static inline long ipcmp(unsigned char *x, unsigned char *y) | 
|  | { | 
|  | uint32_t *a = (uint32_t *)x; | 
|  | uint32_t *b = (uint32_t *)y; | 
|  |  | 
|  | return (a[0] ^ b[0]) | (a[1] ^ b[1]) | | 
|  | (a[2] ^ b[2]) | (a[3] ^ b[3]); | 
|  | } | 
|  |  | 
|  |  | 
|  | extern uint8_t IPv4_loopback[IPaddrlen]; | 
|  | extern uint8_t IPv4_zeroes[IPaddrlen]; | 
|  | extern uint8_t IPv4bcast[IPaddrlen]; | 
|  | extern uint8_t IPv4bcastobs[IPaddrlen]; | 
|  | extern uint8_t IPv4allsys[IPaddrlen]; | 
|  | extern uint8_t IPv4allrouter[IPaddrlen]; | 
|  | extern uint8_t IPnoaddr[IPaddrlen]; | 
|  | extern uint8_t v4prefix[IPaddrlen]; | 
|  | extern uint8_t IPallbits[IPaddrlen]; | 
|  |  | 
|  | /* | 
|  | *  media | 
|  | */ | 
|  | extern struct medium ethermedium; | 
|  | extern struct medium nullmedium; | 
|  | extern struct medium pktmedium; | 
|  | extern struct medium tripmedium; | 
|  |  | 
|  | /* | 
|  | *  ipifc.c | 
|  | */ | 
|  | extern struct medium *ipfindmedium(char *name); | 
|  | extern void addipmedium(struct medium *med); | 
|  | extern int ipforme(struct Fs *, uint8_t * addr); | 
|  | extern int iptentative(struct Fs *, uint8_t * addr); | 
|  | extern int ipisbm(uint8_t *); | 
|  | extern int ipismulticast(uint8_t *); | 
|  | extern struct Ipifc *findipifc(struct Fs *, uint8_t * remote, int type); | 
|  | extern void findprimaryip(struct Fs *, uint8_t * unused_uint8_p_t); | 
|  | extern void findlocalip(struct Fs *, uint8_t * local, uint8_t * remote); | 
|  | extern int ipv4local(struct Ipifc *ifc, uint8_t * addr); | 
|  | extern int ipv6local(struct Ipifc *ifc, uint8_t * addr); | 
|  | extern int ipv6anylocal(struct Ipifc *ifc, uint8_t * addr); | 
|  | extern struct Iplifc *iplocalonifc(struct Ipifc *ifc, uint8_t * ip); | 
|  | extern int ipproxyifc(struct Fs *f, struct Ipifc *ifc, uint8_t * ip); | 
|  | extern int ipismulticast(uint8_t * ip); | 
|  | extern int ipisbooting(void); | 
|  | extern int ipifccheckin(struct Ipifc *ifc, struct medium *med); | 
|  | extern void ipifccheckout(struct Ipifc *ifc); | 
|  | extern int ipifcgrab(struct Ipifc *ifc); | 
|  | extern void ipifcaddroute(struct Fs *, int unused_int, | 
|  | uint8_t * unused_uint8_p_t, uint8_t *, uint8_t *, | 
|  | int); | 
|  | extern void ipifcremroute(struct Fs *, int unused_int, uint8_t * u8pt, | 
|  | uint8_t * u8pt2); | 
|  | extern void ipifcremmulti(struct conv *c, uint8_t * ma, uint8_t * ia); | 
|  | extern void ipifcaddmulti(struct conv *c, uint8_t * ma, uint8_t * ia); | 
|  | extern void ipifc_trace_block(struct Ipifc *ifc, struct block *bp); | 
|  | extern long ipselftabread(struct Fs *, char *a, uint32_t offset, int n); | 
|  | extern void ipsendra6(struct Fs *f, int on); | 
|  |  | 
|  | /* | 
|  | *  ip.c | 
|  | */ | 
|  | extern void iprouting(struct Fs *, int); | 
|  | extern void icmpnoconv(struct Fs *, struct block *); | 
|  | extern void icmpcantfrag(struct Fs *, struct block *, int); | 
|  | extern void icmpttlexceeded(struct Fs *, uint8_t * unused_uint8_p_t, | 
|  | struct block *); | 
|  |  | 
|  | uint16_t ipchecksum(uint8_t *addr, int len); | 
|  | extern uint16_t ipcsum(uint8_t * unused_uint8_p_t); | 
|  | extern void ipiput4(struct Fs *, struct Ipifc *unused_ipifc, struct block *); | 
|  | extern void ipiput6(struct Fs *, struct Ipifc *unused_ipifc, struct block *); | 
|  | extern int ipoput4(struct Fs *, struct block *, int unused_int, int, int, | 
|  | struct conv *); | 
|  | extern int ipoput6(struct Fs *, struct block *, int unused_int, int, int, | 
|  | struct conv *); | 
|  | extern int ipstats(struct Fs *, char *unused_char_p_t, int); | 
|  | extern uint16_t ptclbsum(uint8_t * unused_uint8_p_t, int); | 
|  | extern uint16_t ptclcsum(struct block *, int unused_int, int); | 
|  | extern void ip_init(struct Fs *); | 
|  | extern void update_mtucache(uint8_t * unused_uint8_p_t, uint32_t); | 
|  | extern uint32_t restrict_mtu(uint8_t * unused_uint8_p_t, uint32_t); | 
|  |  | 
|  | /* We support transport layer checksum offloading.  If a NIC doesn't support | 
|  | * it, we'll finish it in software here. | 
|  | * | 
|  | * We've checksummed pseudo header in advance.  The remaining bits that need to | 
|  | * be csummed is the entire transport layer (header + data).  The NICs (and | 
|  | * this function) expect the PH to be done already and stored in the transport | 
|  | * layer's csum location.  This function wants to know where that is in a | 
|  | * protocol-independent manner, hence the tx_csum_offset. */ | 
|  | static inline void ptclcsum_finalize(struct block *bp, unsigned int feat) | 
|  | { | 
|  | unsigned int flag = bp->flag & BLOCK_TRANS_TX_CSUM; | 
|  | uint8_t *csum_store; | 
|  |  | 
|  | if (flag && (flag & feat) != flag) { | 
|  | csum_store = bp->rp + bp->transport_offset + bp->tx_csum_offset; | 
|  | /* NOTE pseudo-header partial checksum (if any) is already | 
|  | * placed at csum_store (e.g. tcpcksum), and the ptclcsum() | 
|  | * below will include that partial checksum as part of the | 
|  | * calculation. | 
|  | */ | 
|  | hnputs((uint16_t *)csum_store, | 
|  | ptclcsum(bp, bp->transport_offset, | 
|  | BLEN(bp) - bp->transport_offset)); | 
|  | bp->flag &= ~BLOCK_TRANS_TX_CSUM; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* | 
|  | *  iprouter.c | 
|  | */ | 
|  | void useriprouter(struct Fs *, struct Ipifc *unused_ipifc, struct block *); | 
|  | void iprouteropen(struct Fs *); | 
|  | void iprouterclose(struct Fs *); | 
|  | long iprouterread(struct Fs *, void *, int); | 
|  |  | 
|  | /* | 
|  | *  resolving inferno/plan9 differences | 
|  | */ | 
|  | struct chan *commonfdtochan(int unused_int, int, int, int); | 
|  | char *commonuser(void); | 
|  | char *commonerror(void); | 
|  |  | 
|  | /* | 
|  | * chandial.c | 
|  | */ | 
|  | extern struct chan *chandial(char *u1, char *u2, char *u3, struct chan **c); | 
|  |  | 
|  | /* | 
|  | *  global to all of the stack | 
|  | */ | 
|  | extern void (*igmpreportfn) (struct Ipifc * unused_ipifc, | 
|  | uint8_t * unused_uint8_p_t); | 
|  |  | 
|  | /* IPV6 */ | 
|  | /* rfc 3513 defines the address prefices */ | 
|  | #define isv6mcast(addr)	  ((addr)[0] == 0xff) | 
|  | #define islinklocal(addr) ((addr)[0] == 0xfe && ((addr)[1] & 0xc0) == 0x80) | 
|  | #define issitelocal(addr) ((addr)[0] == 0xfe && ((addr)[1] & 0xc0) == 0xc0) | 
|  | #define isv6global(addr) (((addr)[0] & 0xe0) == 0x20) | 
|  |  | 
|  | #define optexsts(np) (nhgets((np)->ploadlen) > 24) | 
|  | #define issmcast(addr) (memcmp((addr), v6solicitednode, 13) == 0) | 
|  |  | 
|  | /* from RFC 2460 */ | 
|  |  | 
|  | typedef struct Ip4hdr Ip4hdr; | 
|  | typedef struct ip6hdr Ip6hdr; | 
|  | typedef struct Opthdr Opthdr; | 
|  | typedef struct Routinghdr Routinghdr; | 
|  | typedef struct Fraghdr6 Fraghdr6; | 
|  |  | 
|  | 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 */ | 
|  | }; | 
|  |  | 
|  | struct ip6hdr { | 
|  | uint8_t vcf[4];		// version:4, traffic class:8, flow label:20 | 
|  | uint8_t ploadlen[2];	// payload length: packet length - 40 | 
|  | uint8_t proto;		// next header type | 
|  | uint8_t ttl;		// hop limit | 
|  | uint8_t src[IPaddrlen]; | 
|  | uint8_t dst[IPaddrlen]; | 
|  | }; | 
|  |  | 
|  | struct Opthdr { | 
|  | uint8_t nexthdr; | 
|  | uint8_t len; | 
|  | }; | 
|  |  | 
|  | struct Routinghdr { | 
|  | uint8_t nexthdr; | 
|  | uint8_t len; | 
|  | uint8_t rtetype; | 
|  | uint8_t segrem; | 
|  | }; | 
|  |  | 
|  | struct fraghdr6 { | 
|  | uint8_t nexthdr; | 
|  | uint8_t res; | 
|  | uint8_t offsetRM[2];		// Offset, Res, M flag | 
|  | uint8_t id[4]; | 
|  | }; | 
|  |  | 
|  | enum {					/* Header Types */ | 
|  | HBH = 0, | 
|  | ICMP = 1, | 
|  | IGMP = 2, | 
|  | GGP = 3, | 
|  | IPINIP = 4, | 
|  | ST = 5, | 
|  | TCP = 6, | 
|  | UDP = 17, | 
|  | ISO_TP4 = 29, | 
|  | RH = 43, | 
|  | FH = 44, | 
|  | IDRP = 45, | 
|  | RSVP = 46, | 
|  | AH = 51, | 
|  | ESP = 52, | 
|  | ICMPv6 = 58, | 
|  | NNH = 59, | 
|  | DOH = 60, | 
|  | ISO_IP = 80, | 
|  | IGRP = 88, | 
|  | OSPF = 89, | 
|  |  | 
|  | Maxhdrtype = 256, | 
|  | }; | 
|  |  | 
|  | enum { | 
|  | //  multicast flgs and scop | 
|  |  | 
|  | well_known_flg = 0, | 
|  | transient_flg = 1, | 
|  |  | 
|  | node_local_scop = 1, | 
|  | link_local_scop = 2, | 
|  | site_local_scop = 5, | 
|  | org_local_scop = 8, | 
|  | global_scop = 14, | 
|  |  | 
|  | //  various prefix lengths | 
|  |  | 
|  | SOLN_PREF_LEN = 13, | 
|  |  | 
|  | //  icmpv6 unreach codes | 
|  | icmp6_no_route = 0, | 
|  | icmp6_ad_prohib = 1, | 
|  | icmp6_unassigned = 2, | 
|  | icmp6_adr_unreach = 3, | 
|  | icmp6_port_unreach = 4, | 
|  | icmp6_unkn_code = 5, | 
|  |  | 
|  | //  various flags & constants | 
|  |  | 
|  | v6MINTU = 1280, | 
|  | HOP_LIMIT = 255, | 
|  | ETHERHDR_LEN = 14, | 
|  | IPV6HDR_LEN = 40, | 
|  | IPV4HDR_LEN = 20, | 
|  |  | 
|  | //  option types | 
|  |  | 
|  | SRC_LLADDRESS = 1, | 
|  | TARGET_LLADDRESS = 2, | 
|  | PREFIX_INFO = 3, | 
|  | REDIR_HEADER = 4, | 
|  | MTU_OPTION = 5, | 
|  |  | 
|  | SRC_UNSPEC = 0, | 
|  | SRC_UNI = 1, | 
|  | TARG_UNI = 2, | 
|  | TARG_MULTI = 3, | 
|  |  | 
|  | t_unitent = 1, | 
|  | t_uniproxy = 2, | 
|  | t_unirany = 3, | 
|  |  | 
|  | //  Router constants (all times in milliseconds) | 
|  |  | 
|  | MAX_INITIAL_RTR_ADVERT_INTERVAL = 16000, | 
|  | MAX_INITIAL_RTR_ADVERTISEMENTS = 3, | 
|  | MAX_FINAL_RTR_ADVERTISEMENTS = 3, | 
|  | MIN_DELAY_BETWEEN_RAS = 3000, | 
|  | MAX_RA_DELAY_TIME = 500, | 
|  |  | 
|  | //  Host constants | 
|  |  | 
|  | MAX_RTR_SOLICITATION_DELAY = 1000, | 
|  | RTR_SOLICITATION_INTERVAL = 4000, | 
|  | MAX_RTR_SOLICITATIONS = 3, | 
|  |  | 
|  | //  Node constants | 
|  |  | 
|  | MAX_MULTICAST_SOLICIT = 3, | 
|  | MAX_UNICAST_SOLICIT = 3, | 
|  | MAX_ANYCAST_DELAY_TIME = 1000, | 
|  | MAX_NEIGHBOR_ADVERTISEMENT = 3, | 
|  | REACHABLE_TIME = 30000, | 
|  | RETRANS_TIMER = 1000, | 
|  | DELAY_FIRST_PROBE_TIME = 5000, | 
|  |  | 
|  | }; | 
|  |  | 
|  | static inline struct Ip4hdr *ipv4_hdr(struct block *bp) | 
|  | { | 
|  | return (struct Ip4hdr*)(bp->rp + bp->network_offset); | 
|  | } | 
|  |  | 
|  | static inline struct ip6hdr *ipv6_hdr(struct block *bp) | 
|  | { | 
|  | return (struct ip6hdr*)(bp->rp + bp->network_offset); | 
|  | } | 
|  |  | 
|  | static inline unsigned int ip_version(struct block *bp) | 
|  | { | 
|  | struct Ip4hdr *hdr = ipv4_hdr(bp); | 
|  |  | 
|  | return hdr->vihl >> 4; | 
|  | } | 
|  |  | 
|  | extern void ipv62smcast(uint8_t *, uint8_t *); | 
|  | extern void icmpns(struct Fs *f, uint8_t * src, int suni, uint8_t * targ, | 
|  | int tuni, uint8_t * mac); | 
|  | extern void icmpna(struct Fs *f, uint8_t * src, uint8_t * dst, uint8_t * targ, | 
|  | uint8_t * mac, uint8_t flags); | 
|  | extern void icmpttlexceeded6(struct Fs *f, struct Ipifc *ifc, struct block *bp); | 
|  | extern void icmppkttoobig6(struct Fs *f, struct Ipifc *ifc, struct block *bp); | 
|  | extern void icmphostunr(struct Fs *f, struct Ipifc *ifc, struct block *bp, | 
|  | int code, int free); | 
|  |  | 
|  | extern uint8_t v6allnodesN[IPaddrlen]; | 
|  | extern uint8_t v6allnodesL[IPaddrlen]; | 
|  | extern uint8_t v6allroutersN[IPaddrlen]; | 
|  | extern uint8_t v6allroutersL[IPaddrlen]; | 
|  | extern uint8_t v6allnodesNmask[IPaddrlen]; | 
|  | extern uint8_t v6allnodesLmask[IPaddrlen]; | 
|  | extern uint8_t v6allroutersS[IPaddrlen]; | 
|  | extern uint8_t v6solicitednode[IPaddrlen]; | 
|  | extern uint8_t v6solicitednodemask[IPaddrlen]; | 
|  | extern uint8_t v6Unspecified[IPaddrlen]; | 
|  | extern uint8_t v6loopback[IPaddrlen]; | 
|  | extern uint8_t v6loopbackmask[IPaddrlen]; | 
|  | extern uint8_t v6linklocal[IPaddrlen]; | 
|  | extern uint8_t v6linklocalmask[IPaddrlen]; | 
|  | extern uint8_t v6sitelocal[IPaddrlen]; | 
|  | extern uint8_t v6sitelocalmask[IPaddrlen]; | 
|  | extern uint8_t v6glunicast[IPaddrlen]; | 
|  | extern uint8_t v6multicast[IPaddrlen]; | 
|  | extern uint8_t v6multicastmask[IPaddrlen]; | 
|  |  | 
|  | extern int v6llpreflen; | 
|  | extern int v6slpreflen; | 
|  | extern int v6lbpreflen; | 
|  | extern int v6mcpreflen; | 
|  | extern int v6snpreflen; | 
|  | extern int v6aNpreflen; | 
|  | extern int v6aLpreflen; | 
|  |  | 
|  | extern int ReTransTimer; | 
|  |  | 
|  | int kdial(char *dest, char *local, char *dir, int *cfdp); | 
|  |  | 
|  | /* network interfaces and ethernet */ | 
|  |  | 
|  | enum { | 
|  | Nmaxaddr = 64, | 
|  | Nmhash = 31, | 
|  |  | 
|  | Ncloneqid = 1, | 
|  | Naddrqid, | 
|  | N2ndqid, | 
|  | N3rdqid, | 
|  | Ndataqid, | 
|  | Nctlqid, | 
|  | Nstatqid, | 
|  | Ntypeqid, | 
|  | Nifstatqid, | 
|  | }; | 
|  |  | 
|  | /* | 
|  | *  Macros to manage Qid's used for multiplexed devices | 
|  | */ | 
|  | #define NETTYPE(x)	(((uint32_t)x)&0x1f) | 
|  | /* The net's ID + 1 is stored starting at 1 << 5.  So ID 0 = 32, ID 1 = 64, and | 
|  | * NETID == -1 means no netid */ | 
|  | #define NETID(x)	(((uint32_t)(x) >> 5) - 1) | 
|  | #define NETQID(i,t)	((((uint32_t)(i) + 1) << 5) | (t)) | 
|  |  | 
|  | /* | 
|  | *  one per multiplexed connection | 
|  | */ | 
|  | struct netfile { | 
|  | qlock_t qlock; | 
|  |  | 
|  | int inuse; | 
|  | uint32_t mode; | 
|  | char owner[KNAMELEN]; | 
|  |  | 
|  | int type;		/* multiplexor type */ | 
|  | int prom;		/* promiscuous mode */ | 
|  | int scan;		/* base station scanning interval */ | 
|  | int bridge;		/* bridge mode */ | 
|  | int headersonly;	/* headers only - no data */ | 
|  | uint8_t maddr[8];	/* bitmask of multicast addresses requested */ | 
|  | int nmaddr;		/* number of multicast addresses */ | 
|  |  | 
|  | struct queue *in;	/* input buffer */ | 
|  | }; | 
|  |  | 
|  | /* | 
|  | *  a network address | 
|  | */ | 
|  | struct netaddr { | 
|  | struct netaddr *next;	/* allocation chain */ | 
|  | struct netaddr *hnext; | 
|  | uint8_t addr[Nmaxaddr]; | 
|  | int ref; /* leaving this as an int, not a kref.  no reaping, yet. */ | 
|  | }; | 
|  |  | 
|  | /* | 
|  | * These flags overlap with block flags, to make detecting unsupported | 
|  | * offloads efficient. | 
|  | */ | 
|  | #define NETF_BASE_SHIFT		(NS_SHIFT_MAX + 1) | 
|  | #define NETF_PADMIN_SHIFT	(NETF_BASE_SHIFT + 0) | 
|  | #define NETF_SG_SHIFT		(NETF_BASE_SHIFT + 1) | 
|  | #define NETF_LRO_SHIFT		(NETF_BASE_SHIFT + 2) | 
|  | #define NETF_RXCSUM_SHIFT	(NETF_BASE_SHIFT + 3) | 
|  | enum { | 
|  | NETF_IPCK = (1 << NS_IPCK_SHIFT),	/* xmit ip checksum */ | 
|  | NETF_UDPCK = (1 << NS_UDPCK_SHIFT),	/* xmit udp checksum */ | 
|  | NETF_TCPCK = (1 << NS_TCPCK_SHIFT),	/* xmit tcp checksum */ | 
|  | NETF_PADMIN = (1 << NETF_PADMIN_SHIFT),	/* device pads to mintu */ | 
|  | NETF_SG	= (1 << NETF_SG_SHIFT),		/* can do scatter/gather */ | 
|  | NETF_TSO = (1 << NS_TSO_SHIFT),		/* device can do TSO */ | 
|  | NETF_LRO = (1 << NETF_LRO_SHIFT),	/* device can do LRO */ | 
|  | NETF_RXCSUM = (1 << NETF_RXCSUM_SHIFT),	/* device can do rx checksums */ | 
|  | }; | 
|  |  | 
|  | /* Linux's rtnl_link_stats64 */ | 
|  | struct netif_stats { | 
|  | uint64_t		rx_packets;	/* total packets received */ | 
|  | uint64_t		tx_packets;	/* total packets transmitted */ | 
|  | uint64_t		rx_bytes;	/* total bytes received */ | 
|  | uint64_t		tx_bytes;	/* total bytes transmitted */ | 
|  | uint64_t		rx_errors;	/* bad packets received */ | 
|  | uint64_t		tx_errors;	/* packet transmit problems */ | 
|  | uint64_t		rx_dropped;	/* no space in linux buffers */ | 
|  | uint64_t		tx_dropped;	/* no space available in linux*/ | 
|  | uint64_t		multicast;	/* multicast packets received */ | 
|  | uint64_t		collisions; | 
|  |  | 
|  | /* detailed rx_errors: */ | 
|  | uint64_t		rx_length_errors; | 
|  | uint64_t		rx_over_errors;	/* recv'r ring buff overflow */ | 
|  | uint64_t		rx_crc_errors;	/* recv'd pkt with crc error */ | 
|  | uint64_t		rx_frame_errors;/* recv'd frame alignment err */ | 
|  | uint64_t		rx_fifo_errors;	/* recv'r fifo overrun */ | 
|  | uint64_t		rx_missed_errors; /* receiver missed packet */ | 
|  |  | 
|  | /* detailed tx_errors */ | 
|  | uint64_t		tx_aborted_errors; | 
|  | uint64_t		tx_carrier_errors; | 
|  | uint64_t		tx_fifo_errors; | 
|  | uint64_t		tx_heartbeat_errors; | 
|  | uint64_t		tx_window_errors; | 
|  |  | 
|  | /* for cslip etc */ | 
|  | uint64_t		rx_compressed; | 
|  | uint64_t		tx_compressed; | 
|  | uint64_t		rx_nohandler;	/* dropped, no handler found */ | 
|  | }; | 
|  |  | 
|  | /* | 
|  | *  a network interface | 
|  | */ | 
|  | struct ether; | 
|  | struct netif { | 
|  | qlock_t qlock; | 
|  |  | 
|  | /* multiplexing */ | 
|  | char name[KNAMELEN];	/* for top level directory */ | 
|  | char drv_name[KNAMELEN];/* device driver name */ | 
|  | int nfile;		/* max number of Netfiles */ | 
|  | struct netfile **f; | 
|  |  | 
|  | /* about net */ | 
|  | int limit;		/* flow control */ | 
|  | int alen;		/* address length */ | 
|  | int mbps;		/* megabits per sec */ | 
|  | int link;		/* link status (seems to be driver specific) */ | 
|  | struct rendez link_rz; | 
|  | bool link_is_up; | 
|  | unsigned int feat;	/* dev features turned on */ | 
|  | unsigned int hw_features;	/* dev features available */ | 
|  | uint8_t addr[Nmaxaddr]; | 
|  | uint8_t bcast[Nmaxaddr]; | 
|  | struct netaddr *maddr;	/* known multicast addresses */ | 
|  | int nmaddr;		/* number of known multicast addresses */ | 
|  | struct netaddr *mhash[Nmhash];	/* hash table of multicast addresses */ | 
|  | int prom;		/* number of promiscuous opens */ | 
|  | int scan;		/* number of base station scanners */ | 
|  | int all;		/* number of -1 multiplexors */ | 
|  | /* Analogous to linux's IFF_PROMISC flags, currently used by linux | 
|  | * drivers, pending a rewrite of ow promiscuous works */ | 
|  | int rx_mode; | 
|  |  | 
|  | /* 9ns statistics */ | 
|  | int misses; | 
|  | int inpackets; | 
|  | int outpackets; | 
|  | int crcs;			/* input crc errors */ | 
|  | int oerrs;			/* output errors */ | 
|  | int frames;			/* framing errors */ | 
|  | int overflows;			/* packet overflows */ | 
|  | int buffs;			/* buffering errors */ | 
|  | int soverflows;			/* software overflow */ | 
|  | /* Linux-style statistics */ | 
|  | struct netif_stats stats; | 
|  |  | 
|  | /* routines for touching the hardware */ | 
|  | void *arg; | 
|  | void (*promiscuous) (void *, int); | 
|  | void (*multicast) (void *, uint8_t * unused_uint8_p_t, int); | 
|  | void (*scanbs) (void *, unsigned nt);	/* scan for base stations */ | 
|  | }; | 
|  |  | 
|  | void netifinit(struct ether *, char *, int, uint32_t); | 
|  | struct walkqid *netifwalk(struct ether *, struct chan *, struct chan *, char **, | 
|  | int); | 
|  | struct chan *netifopen(struct ether *, struct chan *, int); | 
|  | void netifclose(struct ether *, struct chan *); | 
|  | long netifread(struct ether *, struct chan *, void *, long, uint32_t); | 
|  | struct block *netifbread(struct ether *, struct chan *, long, uint32_t); | 
|  | long netifwrite(struct ether *, struct chan *, void *, long); | 
|  | int netifwstat(struct ether *, struct chan *, uint8_t *, int); | 
|  | int netifstat(struct ether *, struct chan *, uint8_t *, int); | 
|  | ssize_t linux_ifstat(struct netif_stats *stats, void *va, size_t amt, | 
|  | off_t offset); | 
|  | int activemulti(struct ether *, uint8_t *, int); | 
|  |  | 
|  | /* | 
|  | *  Ethernet specific | 
|  | */ | 
|  | enum { | 
|  | Eaddrlen = 6, | 
|  | ETHERMINTU = 60,	/* minimum transmit size */ | 
|  | ETHERMAXTU = 1500,	/* maximum transmit size */ | 
|  | ETHERHDRSIZE = 14,	/* size of an ethernet header */ | 
|  | }; | 
|  |  | 
|  | struct etherpkt { | 
|  | uint8_t d[Eaddrlen]; | 
|  | uint8_t s[Eaddrlen]; | 
|  | uint8_t type[2]; | 
|  | uint8_t data[1500]; | 
|  | }; | 
|  | enum { | 
|  | MaxEther = 32, | 
|  | MaxFID = 16, | 
|  | Ntypes = 8, | 
|  | }; | 
|  |  | 
|  | struct ether { | 
|  | rwlock_t rwlock; | 
|  | int ctlrno; | 
|  | char *type; | 
|  | int irq; | 
|  | unsigned int tbdf; | 
|  | int port; | 
|  | int mtu; | 
|  | int min_mtu; | 
|  | int max_mtu; | 
|  | uint8_t ea[Eaddrlen]; | 
|  | int encry; | 
|  |  | 
|  | void (*attach) (struct ether *);	/* filled in by reset routine */ | 
|  | void (*closed) (struct ether *); | 
|  | void (*detach) (struct ether *); | 
|  | void (*transmit) (struct ether *); | 
|  | long (*ifstat) (struct ether *, void *, long, uint32_t); | 
|  | long (*ctl) (struct ether *, void *, size_t); /* custom ctl messages */ | 
|  | void (*power) (struct ether *, int);	/* power on/off */ | 
|  | void (*shutdown) (struct ether *); /* shutdown hardware before reboot */ | 
|  | void *ctlr; | 
|  | int pcmslot;				/* PCMCIA */ | 
|  | int fullduplex;				/* non-zero if full duplex */ | 
|  | int vlanid;				/* non-zero if vlan */ | 
|  |  | 
|  | struct queue *oq; | 
|  |  | 
|  | qlock_t vlq;				/* array change */ | 
|  | int nvlan; | 
|  | struct ether *vlans[MaxFID]; | 
|  |  | 
|  | struct netif; | 
|  | }; | 
|  |  | 
|  | static inline void netif_carrier_on(struct ether *edev) | 
|  | { | 
|  | edev->link_is_up = TRUE; | 
|  | rendez_wakeup(&edev->link_rz); | 
|  | } | 
|  |  | 
|  | static inline bool netif_carrier_ok(struct ether *edev) | 
|  | { | 
|  | return edev->link_is_up; | 
|  | } | 
|  |  | 
|  | static inline void netif_carrier_off(struct ether *edev) | 
|  | { | 
|  | edev->link_is_up = FALSE; | 
|  | } | 
|  |  | 
|  | static void netif_wait_for_carrier(struct ether *edev) | 
|  | { | 
|  | rendez_sleep(&edev->link_rz, (rendez_cond_t)netif_carrier_ok, edev); | 
|  | } | 
|  |  | 
|  | extern struct block *etheriq(struct ether *, struct block *, int); | 
|  | extern void addethercard(char *unused_char_p_t, int (*)(struct ether *)); | 
|  | extern int archether(int unused_int, struct ether *); | 
|  |  | 
|  | #define NEXT_RING(x, len) (((x) + 1) % (len)) | 
|  | #define PREV_RING(x, len) (((x) == 0) ? (len) - 1: (x) - 1) |