| /* 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, int); |
| 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, int); |
| 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 *, long); /* 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) |