2 #include "../port/lib.h"
6 #include "../port/error.h"
10 enum /* Connection state */
18 Ilopening, /* only for file server */
29 "Opening", /* only for file server */
32 enum /* Packet types */
57 Iltickms = 50, /* time base */
58 AckDelay = 2*Iltickms, /* max time twixt message rcvd & ack sent */
59 MaxTimeout = 30*Seconds, /* max time between rexmit */
60 QueryTime = 10*Seconds, /* time between subsequent queries */
61 DeathTime = 30*QueryTime,
63 MaxRexmit = 16, /* max retransmissions before hangup */
71 DefByteRate = 100, /* assume a megabit link */
72 DefRtt = 50, /* cross country on a great day */
82 typedef struct Ilcb Ilcb;
83 struct Ilcb /* Control block */
85 int state; /* Connection state */
87 QLock ackq; /* Unacknowledged queue */
91 QLock outo; /* Out of order packet queue */
93 ulong next; /* Id of next to send */
94 ulong recvd; /* Last packet received */
95 ulong acksent; /* Last packet acked */
96 ulong start; /* Local start id */
97 ulong rstart; /* Remote start id */
98 int window; /* Maximum receive window */
99 int rxquery; /* number of queries on this connection */
100 int rxtot; /* number of retransmits on this connection */
101 int rexmit; /* number of retransmits of *unacked */
102 ulong qt[Nqt+1]; /* state table for query messages */
103 int qtx; /* ... index into qt */
105 /* if set, fasttimeout causes a connection request to terminate after 4*Iltickms */
109 ulong lastxmit; /* time of last xmit */
110 ulong lastrecv; /* time of last recv */
111 ulong timeout; /* retransmission time for *unacked */
112 ulong acktime; /* time to send next ack */
113 ulong querytime; /* time to send next query */
115 /* adaptive measurements */
116 int delay; /* Average of the fixed rtt delay */
117 int rate; /* Average uchar rate */
118 int mdev; /* Mean deviation of rtt */
119 int maxrtt; /* largest rtt seen */
120 ulong rttack; /* The ack we are waiting for */
121 int rttlen; /* Length of rttack packet */
122 uvlong rttstart; /* Time we issued rttack packet */
134 typedef struct Ilhdr Ilhdr;
137 uchar vihl; /* Version and header length */
138 uchar tos; /* Type of service */
139 uchar length[2]; /* packet length */
140 uchar id[2]; /* Identification */
141 uchar frag[2]; /* Fragment information */
142 uchar ttl; /* Time to live */
143 uchar proto; /* Protocol */
144 uchar cksum[2]; /* Header checksum */
145 uchar src[4]; /* Ip source */
146 uchar dst[4]; /* Ip destination */
147 uchar ilsum[2]; /* Checksum including header */
148 uchar illen[2]; /* Packet length */
149 uchar iltype; /* Packet type */
150 uchar ilspec; /* Special */
151 uchar ilsrc[2]; /* Src port */
152 uchar ildst[2]; /* Dst port */
153 uchar ilid[4]; /* Sequence id */
154 uchar ilack[4]; /* Acked sequence */
161 CsumErrs, /* checksum errors */
162 HlenErrs, /* header length error */
163 LenErrs, /* short packet */
164 OutOfOrder, /* out of order */
165 Retrans, /* retransmissions */
173 static char *statnames[] =
177 [CsumErrs] "CsumErrs",
178 [HlenErrs] "HlenErr",
180 [OutOfOrder] "OutOfOrder",
183 [DupBytes] "DupBytes",
184 [DroppedMsgs] "DroppedMsgs",
187 typedef struct Ilpriv Ilpriv;
192 uvlong stats[Nstats];
194 ulong csumerr; /* checksum errors */
195 ulong hlenerr; /* header length error */
196 ulong lenerr; /* short packet */
197 ulong order; /* out of order */
198 ulong rexmit; /* retransmissions */
202 /* keeping track of the ack kproc */
207 /* state for query/dataquery messages */
210 void ilrcvmsg(Conv*, Block*);
211 void ilsendctl(Conv*, Ilhdr*, int, ulong, ulong, int);
212 void ilackq(Ilcb*, Block*);
213 void ilprocess(Conv*, Ilhdr*, Block*);
214 void ilpullup(Conv*);
215 void ilhangup(Conv*, char*);
217 void ilrexmit(Ilcb*);
218 void ilbackoff(Ilcb*);
219 void ilsettimeout(Ilcb*);
220 char* ilstart(Conv*, int, int);
221 void ilackproc(void*);
222 void iloutoforder(Conv*, Ilhdr*, Block*);
223 void iliput(Proto*, Ipifc*, Block*);
224 void iladvise(Proto*, Block*, char*);
226 void ilcbinit(Ilcb*);
227 int later(ulong, ulong, char*);
228 void ilreject(Fs*, Ilhdr*);
229 void illocalclose(Conv *c);
231 static int initseq = 25001;
232 static ulong scalediv, scalemul;
233 static char *etime = "connection timed out";
236 ilconnect(Conv *c, char **argv, int argc)
241 /* huge hack to quickly try an il connection */
244 p = strstr(argv[1], "!fasttimeout");
251 e = Fsstdconnect(c, argv, argc);
254 return ilstart(c, IL_CONNECT, fast);
258 ilstate(Conv *c, char *state, int n)
262 ic = (Ilcb*)(c->ptcl);
263 return snprint(state, n, "%s qin %d qout %d del %5.5d Br %5.5d md %5.5d una %5.5lud rex %5.5d rxq %5.5d max %5.5d\n",
265 c->rq ? qlen(c->rq) : 0,
266 c->wq ? qlen(c->wq) : 0,
267 ic->delay>>LogAGain, ic->rate>>LogAGain, ic->mdev>>LogDGain,
268 ic->unackedbytes, ic->rxtot, ic->rxquery, ic->maxrtt);
276 ic = (Ilcb*)(c->ptcl);
277 return ic->state != Ilclosed;
281 /* called with c locked */
283 ilannounce(Conv *c, char **argv, int argc)
287 e = Fsstdannounce(c, argv, argc);
290 e = ilstart(c, IL_LISTEN, 0);
299 illocalclose(Conv *c)
306 ic->state = Ilclosed;
307 iphtrem(&ipriv->ht, c);
308 ipmove(c->laddr, IPnoaddr);
330 ic->state = Ilclosing;
332 ilsendctl(c, nil, Ilclose, ic->next, ic->recvd, 0);
342 ilkick(void *x, Block *bp)
370 /* Make space to fit il & ip */
371 bp = padblock(bp, IL_IPSIZE+IL_HDRSIZE);
372 ih = (Ilhdr *)(bp->rp);
378 v6tov4(ih->dst, c->raddr);
379 v6tov4(ih->src, c->laddr);
380 ih->proto = IP_ILPROTO;
383 hnputs(ih->illen, dlen+IL_HDRSIZE);
384 hnputs(ih->ilsrc, c->lport);
385 hnputs(ih->ildst, c->rport);
389 hnputl(ih->ilid, id);
391 hnputl(ih->ilack, ack);
393 ic->acktime = NOW + AckDelay;
399 /* Checksum of ilheader plus data (not ip & no pseudo header) */
401 hnputs(ih->ilsum, ptclcsum(bp, IL_IPSIZE, dlen+IL_HDRSIZE));
406 /* Start the round trip timer for this packet if the timer is free */
407 if(ic->rttack == 0) {
409 ic->rttstart = fastticks(nil);
410 ic->rttlen = dlen + IL_IPSIZE + IL_HDRSIZE;
413 if(later(NOW, ic->timeout, nil))
415 ipoput4(f, bp, 0, c->ttl, c->tos, c);
416 priv->stats[OutMsgs]++;
422 c->rq = qopen(Maxrq, 0, 0, c);
423 c->wq = qbypass(ilkick, c);
427 ilxstats(Proto *il, char *buf, int len)
436 for(i = 0; i < Nstats; i++)
437 p = seprint(p, e, "%s: %llud\n", statnames[i], priv->stats[i]);
442 ilackq(Ilcb *ic, Block *bp)
449 /* Enqueue a copy on the unacked queue in case this one gets lost */
450 np = copyblock(bp, n);
452 ic->unackedtail->list = np;
455 ic->unackedtail = np;
457 ic->unackedbytes += n;
462 ilrttcalc(Ilcb *ic, Block *bp)
464 int rtt, tt, pt, delay, rate;
466 rtt = fastticks(nil) - ic->rttstart;
467 rtt = (rtt*scalemul)/scalediv;
471 /* Guard against zero wrap */
472 if(rtt > 120000 || rtt < 0)
475 /* this block had to be transmitted after the one acked so count its size */
476 ic->rttlen += blocklen(bp) + IL_IPSIZE + IL_HDRSIZE;
478 if(ic->rttlen < 256){
479 /* guess fixed delay as rtt of small packets */
480 delay += rtt - (delay>>LogAGain);
485 /* if packet took longer than avg rtt delay, recalc rate */
486 tt = rtt - (delay>>LogAGain);
488 rate += ic->rttlen/tt - (rate>>LogAGain);
496 pt = ic->rttlen/(rate>>LogAGain) + (delay>>LogAGain);
497 ic->mdev += abs(rtt-pt) - (ic->mdev>>LogDGain);
504 ilackto(Ilcb *ic, ulong ackto, Block *bp)
509 if(ic->rttack == ackto)
512 /* Cancel if we've passed the packet we were interested in */
513 if(ic->rttack <= ackto)
518 h = (Ilhdr *)ic->unacked->rp;
519 id = nhgetl(h->ilid);
524 ic->unacked = bp->list;
526 ic->unackedbytes -= blocklen(bp);
535 iliput(Proto *il, Ipifc*, Block *bp)
540 uchar raddr[IPaddrlen];
541 uchar laddr[IPaddrlen];
549 ih = (Ilhdr *)bp->rp;
551 if(plen < IL_IPSIZE+IL_HDRSIZE){
552 netlog(il->f, Logil, "il: hlenerr\n");
553 ipriv->stats[HlenErrs]++;
557 illen = nhgets(ih->illen);
558 if(illen+IL_IPSIZE > plen){
559 netlog(il->f, Logil, "il: lenerr\n");
560 ipriv->stats[LenErrs]++;
564 sp = nhgets(ih->ildst);
565 dp = nhgets(ih->ilsrc);
566 v4tov6(raddr, ih->src);
567 v4tov6(laddr, ih->dst);
569 if((csum = ptclcsum(bp, IL_IPSIZE, illen)) != 0) {
570 if(ih->iltype > Ilclose)
573 st = iltype[ih->iltype];
574 ipriv->stats[CsumErrs]++;
575 netlog(il->f, Logil, "il: cksum %ux %s, pkt(%ux id %ud ack %I/%d->%d)\n",
576 csum, st, nhgetl(ih->ilid), nhgetl(ih->ilack), raddr, sp, dp);
581 s = iphtlook(&ipriv->ht, raddr, dp, laddr, sp);
583 if(ih->iltype == Ilsync)
584 ilreject(il->f, ih); /* no listener */
590 if(ic->state == Illistening){
591 if(ih->iltype != Ilsync){
593 if(ih->iltype > Ilclose)
596 st = iltype[ih->iltype];
597 ilreject(il->f, ih); /* no channel and not sync */
598 netlog(il->f, Logil, "il: no channel, pkt(%s id %ud ack %ud %I/%ud->%ud)\n",
599 st, nhgetl(ih->ilid), nhgetl(ih->ilack), raddr, sp, dp);
603 new = Fsnewcall(s, raddr, dp, laddr, sp, V4);
606 netlog(il->f, Logil, "il: bad newcall %I/%ud->%ud\n", raddr, sp, dp);
607 ilsendctl(s, ih, Ilclose, 0, nhgetl(ih->ilid), 0);
615 ic->state = Ilsyncee;
617 ic->rstart = nhgetl(ih->ilid);
618 iphtadd(&ipriv->ht, s);
627 ilprocess(s, ih, bp);
636 _ilprocess(Conv *s, Ilhdr *h, Block *bp)
642 id = nhgetl(h->ilid);
643 ack = nhgetl(h->ilack);
648 ic->querytime = NOW + QueryTime;
650 priv->stats[InMsgs]++;
654 netlog(s->p->f, Logil, "il: unknown state %d\n", ic->state);
664 ilhangup(s, "connection rejected");
668 ilsendctl(s, nil, Ilack, ic->next, ic->recvd, 0);
669 ic->state = Ilestablished;
678 ilhangup(s, "connection rejected");
688 if(id != ic->rstart || ack != 0){
692 ilsendctl(s, nil, Ilsync, ic->start, ic->recvd, 0);
696 if(ack == ic->start) {
697 ic->state = Ilestablished;
704 if(ack == ic->start) {
705 ic->state = Ilestablished;
713 ilhangup(s, "remote close");
723 ilhangup(s, "remote close");
725 ilsendctl(s, nil, Ilack, ic->next, ic->rstart, 0);
730 * avoid consuming all the mount rpc buffers in the
731 * system. if the input queue is too long, drop this
734 if (s->rq && qlen(s->rq) >= Maxrq) {
735 priv->stats[DroppedMsgs]++;
740 ilackto(ic, ack, bp);
741 iloutoforder(s, h, bp);
745 ilackto(ic, ack, bp);
746 iloutoforder(s, h, bp);
748 ilsendctl(s, nil, Ilstate, ic->next, ic->recvd, h->ilspec);
751 ilackto(ic, ack, bp);
755 ilackto(ic, ack, bp);
756 ilsendctl(s, nil, Ilstate, ic->next, ic->recvd, h->ilspec);
760 if(ack >= ic->rttack)
762 ilackto(ic, ack, bp);
765 if(ic->qt[h->ilspec] > ack){
773 if(ack < ic->start || ack > ic->next)
776 ilsendctl(s, nil, Ilclose, ic->next, ic->recvd, 0);
777 ic->state = Ilclosing;
790 ilsendctl(s, nil, Ilclose, ic->next, ic->recvd, 0);
814 nb = copyblock(ic->unacked, blocklen(ic->unacked));
823 h->iltype = Ildataquery;
824 hnputl(h->ilack, ic->recvd);
825 h->ilspec = ilnextqt(ic);
828 hnputs(h->ilsum, ptclcsum(nb, IL_IPSIZE, nhgets(h->illen)));
831 id = nhgetl(h->ilid);
832 netlog(c->p->f, Logil, "il: rexmit %lud %lud: %d %lud: %I %d/%d\n", id, ic->recvd,
833 ic->rexmit, ic->timeout,
834 c->raddr, c->lport, c->rport);
838 ipoput4(c->p->f, nb, 0, c->ttl, c->tos, c);
848 ilprocess(Conv *s, Ilhdr *h, Block *bp)
855 netlog(s->p->f, Logilmsg, "%11s rcv %lud/%lud snt %lud/%lud pkt(%s id %d ack %ud %ud->%ud) ",
856 ilstates[ic->state], ic->rstart, ic->recvd, ic->start,
857 ic->next, iltype[h->iltype], nhgetl(h->ilid),
858 nhgetl(h->ilack), nhgets(h->ilsrc), nhgets(h->ildst));
860 _ilprocess(s, h, bp);
862 netlog(s->p->f, Logilmsg, "%11s rcv %lud snt %lud\n", ilstates[ic->state], ic->recvd, ic->next);
866 ilhangup(Conv *s, char *msg)
871 netlog(s->p->f, Logil, "il: hangup! %I %d/%d: %s\n", s->raddr,
872 s->lport, s->rport, msg?msg:"no reason");
875 callout = ic->state == Ilsyncer;
895 if(ic->state != Ilestablished)
899 while(ic->outoforder) {
902 oid = nhgetl(oh->ilid);
903 if(oid <= ic->recvd) {
904 ic->outoforder = bp->list;
908 if(oid != ic->recvd+1){
910 ipriv->stats[OutOfOrder]++;
915 ic->outoforder = bp->list;
918 dlen = nhgets(oh->illen)-IL_HDRSIZE;
919 bp = trimblock(bp, IL_IPSIZE+IL_HDRSIZE, dlen);
921 * Upper levels don't know about multiple-block
922 * messages so copy all into one (yick).
924 bp = concatblock(bp);
936 iloutoforder(Conv *s, Ilhdr *h, Block *bp)
948 id = nhgetl(h->ilid);
950 if(id <= ic->recvd || id > ic->recvd+ic->window) {
951 netlog(s->p->f, Logil, "il: message outside window %lud <%lud-%lud>: %I %d/%d\n",
952 id, ic->recvd, ic->recvd+ic->window, s->raddr, s->lport, s->rport);
957 /* Packet is acceptable so sort onto receive queue for pullup */
959 if(ic->outoforder == nil)
963 for(f = *l; f; f = f->list) {
964 lid = ((Ilhdr*)(f->rp))->ilid;
968 ipriv->stats[DupMsg]++;
969 ipriv->stats[DupBytes] += blocklen(bp);
987 ilsendctl(Conv *ipc, Ilhdr *inih, int type, ulong id, ulong ack, int ilspec)
994 bp = allocb(IL_IPSIZE+IL_HDRSIZE);
995 bp->wp += IL_IPSIZE+IL_HDRSIZE;
997 ih = (Ilhdr *)(bp->rp);
1001 ih->proto = IP_ILPROTO;
1002 hnputs(ih->illen, IL_HDRSIZE);
1006 hnputl(ih->dst, nhgetl(inih->src));
1007 hnputl(ih->src, nhgetl(inih->dst));
1008 hnputs(ih->ilsrc, nhgets(inih->ildst));
1009 hnputs(ih->ildst, nhgets(inih->ilsrc));
1010 hnputl(ih->ilid, nhgetl(inih->ilack));
1011 hnputl(ih->ilack, nhgetl(inih->ilid));
1016 v6tov4(ih->dst, ipc->raddr);
1017 v6tov4(ih->src, ipc->laddr);
1018 hnputs(ih->ilsrc, ipc->lport);
1019 hnputs(ih->ildst, ipc->rport);
1020 hnputl(ih->ilid, id);
1021 hnputl(ih->ilack, ack);
1022 ic = (Ilcb*)ipc->ptcl;
1029 ih->ilspec = ilspec;
1034 hnputs(ih->ilsum, ptclcsum(bp, IL_IPSIZE, IL_HDRSIZE));
1037 panic("ipc is nil caller is %#p", getcallerpc(&ipc));
1039 panic("ipc->p is nil");
1041 netlog(ipc->p->f, Logilmsg, "ctl(%s id %d ack %d %d->%d)\n",
1042 iltype[ih->iltype], nhgetl(ih->ilid), nhgetl(ih->ilack),
1043 nhgets(ih->ilsrc), nhgets(ih->ildst));
1045 ipoput4(ipc->p->f, bp, 0, ttl, tos, ipc);
1049 ilreject(Fs *f, Ilhdr *inih)
1054 bp = allocb(IL_IPSIZE+IL_HDRSIZE);
1055 bp->wp += IL_IPSIZE+IL_HDRSIZE;
1057 ih = (Ilhdr *)(bp->rp);
1061 ih->proto = IP_ILPROTO;
1062 hnputs(ih->illen, IL_HDRSIZE);
1065 hnputl(ih->dst, nhgetl(inih->src));
1066 hnputl(ih->src, nhgetl(inih->dst));
1067 hnputs(ih->ilsrc, nhgets(inih->ildst));
1068 hnputs(ih->ildst, nhgets(inih->ilsrc));
1069 hnputl(ih->ilid, nhgetl(inih->ilack));
1070 hnputl(ih->ilack, nhgetl(inih->ilid));
1071 ih->iltype = Ilclose;
1077 hnputs(ih->ilsum, ptclcsum(bp, IL_IPSIZE, IL_HDRSIZE));
1079 ipoput4(f, bp, 0, MAXTTL, DFLTTOS, nil);
1083 ilsettimeout(Ilcb *ic)
1087 pt = (ic->delay>>LogAGain)
1088 + ic->unackedbytes/(ic->rate>>LogAGain)
1089 + (ic->mdev>>(LogDGain-1))
1093 ic->timeout = NOW + pt;
1102 pt = (ic->delay>>LogAGain)
1103 + ic->unackedbytes/(ic->rate>>LogAGain)
1104 + (ic->mdev>>(LogDGain-1))
1106 for(i = 0; i < ic->rexmit; i++)
1110 ic->timeout = NOW + pt;
1113 ic->timeout = NOW+Iltickms;
1118 // complain if two numbers not within an hour of each other
1119 #define Tfuture (1000*60*60)
1121 later(ulong t1, ulong t2, char *x)
1127 if(x != nil && dt > Tfuture)
1128 print("%s: way future %d\n", x, dt);
1133 print("%s: way past %d\n", x, -dt);
1151 tsleep(&up->sleep, return0, 0, Iltickms);
1152 for(s = il->conv; s && *s; s++) {
1154 ic = (Ilcb*)p->ptcl;
1161 if(later(NOW, ic->timeout, "timeout0")) {
1162 if(ic->rexmit > MaxRexmit){
1166 ilsendctl(p, nil, Ilclose, ic->next, ic->recvd, 0);
1173 if(later(NOW, ic->timeout, "timeout1")) {
1174 if(ic->rexmit > MaxRexmit){
1178 ilsendctl(p, nil, Ilsync, ic->start, ic->recvd, 0);
1184 if(ic->recvd != ic->acksent)
1185 if(later(NOW, ic->acktime, "acktime"))
1186 ilsendctl(p, nil, Ilack, ic->next, ic->recvd, 0);
1188 if(later(NOW, ic->querytime, "querytime")){
1189 if(later(NOW, ic->lastrecv+DeathTime, "deathtime")){
1190 netlog(il->f, Logil, "il: hangup: deathtime\n");
1194 ilsendctl(p, nil, Ilquery, ic->next, ic->recvd, ilnextqt(ic));
1195 ic->querytime = NOW + QueryTime;
1198 if(ic->unacked != nil)
1199 if(later(NOW, ic->timeout, "timeout2")) {
1200 if(ic->rexmit > MaxRexmit){
1201 netlog(il->f, Logil, "il: hangup: too many rexmits\n");
1205 ilsendctl(p, nil, Ilquery, ic->next, ic->recvd, ilnextqt(ic));
1218 ic->start = nrand(0x1000000);
1219 ic->next = ic->start+1;
1221 ic->window = Defaultwin;
1222 ic->unackedbytes = 0;
1224 ic->outoforder = nil;
1229 ic->fasttimeout = 0;
1232 ic->delay = DefRtt<<LogAGain;
1233 ic->mdev = DefRtt<<LogDGain;
1234 ic->rate = DefByteRate<<LogAGain;
1235 ic->querytime = NOW + QueryTime;
1236 ic->lastrecv = NOW; /* or we'll timeout right away */
1241 ilstart(Conv *c, int type, int fasttimeout)
1245 char kpname[KNAMELEN];
1249 if(ipriv->ackprocstarted == 0){
1251 if(ipriv->ackprocstarted == 0){
1252 sprint(kpname, "#I%dilack", c->p->f->dev);
1253 kproc(kpname, ilackproc, c->p);
1254 ipriv->ackprocstarted = 1;
1256 qunlock(&ipriv->apl);
1259 ic = (Ilcb*)c->ptcl;
1262 if(ic->state != Ilclosed)
1268 /* timeout if we can't connect quickly */
1269 ic->fasttimeout = 1;
1270 ic->timeout = NOW+Iltickms;
1271 ic->rexmit = MaxRexmit - 4;
1276 netlog(c->p->f, Logil, "il: start: type %d\n", type);
1279 ic->state = Illistening;
1280 iphtadd(&ipriv->ht, c);
1283 ic->state = Ilsyncer;
1284 iphtadd(&ipriv->ht, c);
1285 ilsendctl(c, nil, Ilsync, ic->start, ic->recvd, 0);
1298 for(bp = ic->unacked; bp; bp = next) {
1306 for(bp = ic->outoforder; bp; bp = next) {
1310 ic->outoforder = nil;
1315 iladvise(Proto *il, Block *bp, char *msg)
1319 uchar source[IPaddrlen], dest[IPaddrlen];
1323 h = (Ilhdr*)(bp->rp);
1325 v4tov6(dest, h->dst);
1326 v4tov6(source, h->src);
1327 psource = nhgets(h->ilsrc);
1330 /* Look for a connection, unfortunately the destination port is missing */
1332 for(p = il->conv; *p; p++) {
1334 if(s->lport == psource)
1335 if(ipcmp(s->laddr, source) == 0)
1336 if(ipcmp(s->raddr, dest) == 0){
1338 ic = (Ilcb*)s->ptcl;
1362 ic->qt[x] = ic->next-1; /* highest xmitted packet */
1363 ic->qt[0] = ic->qt[x]; /* compatibility with old implementations */
1369 /* calculate scale constants that converts fast ticks to ms (more or less) */
1392 il = smalloc(sizeof(Proto));
1393 il->priv = smalloc(sizeof(Ilpriv));
1395 il->connect = ilconnect;
1396 il->announce = ilannounce;
1397 il->state = ilstate;
1398 il->create = ilcreate;
1399 il->close = ilclose;
1402 il->advise = iladvise;
1403 il->stats = ilxstats;
1404 il->inuse = ilinuse;
1406 il->ipproto = IP_ILPROTO;
1407 il->nc = scalednconv();
1408 il->ptclsize = sizeof(Ilcb);