Remove support for Solaris pre-8
[openafs.git] / src / rx / SOLARIS / rx_knet.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afsconfig.h>
11 #include "afs/param.h"
12
13
14 #ifdef AFS_SUN5_ENV
15 #include "rx/rx_kcommon.h"
16
17
18 #include "inet/common.h"
19 #include "sys/tiuser.h"
20 #include "sys/t_kuser.h"
21 #include "sys/stropts.h"
22 #include "sys/stream.h"
23 #include "sys/tihdr.h"
24 #include "sys/fcntl.h"
25 #include "netinet/ip6.h"
26 #define ipif_local_addr ipif_lcl_addr
27 #ifndef V4_PART_OF_V6
28 #define V4_PART_OF_V6(v6)       v6.s6_addr32[3]
29 #endif
30 #include "inet/ip.h"
31 #include "inet/ip_if.h"
32 #include "netinet/udp.h"
33 #ifdef AFS_SUN510_ENV
34 #include "h/ddi.h"
35 #include "h/ksynch.h"
36 #include "h/sunddi.h"
37 #include "h/sunldi.h"
38 #include "h/sockio.h"
39 #include "h/cmn_err.h"
40 #include "h/socket.h"
41 #include "netinet/in.h"
42 #endif
43
44 /*
45  * Function pointers for kernel socket routines
46  */
47 #ifdef SOLOOKUP_TAKES_SOCKPARAMS
48 struct sonode *(*sockfs_socreate)
49   (struct sockparams *, int, int, int, int, int *) = NULL;
50 int (*sockfs_solookup)
51   (int, int, int, struct sockparams **) = NULL;
52 #else
53 struct sonode *(*sockfs_socreate)
54   (vnode_t *, int, int, int, int, struct sonode *, int *) = NULL;
55 struct vnode *(*sockfs_solookup)
56   (int, int, int, char *, int *) = NULL;
57 #endif /* SOLOOKUP_TAKES_SOCKPARAMS */
58 int (*sockfs_sobind)
59   (struct sonode *, struct sockaddr *, int, int, int) = NULL;
60 int (*sockfs_sorecvmsg)
61   (struct sonode *, struct nmsghdr *, struct uio *) = NULL;
62 int (*sockfs_sosendmsg)
63   (struct sonode *, struct nmsghdr *, struct uio *) = NULL;
64 int (*sockfs_sosetsockopt)
65   (struct sonode *, int, int, void *, int) = NULL;
66 #ifndef AFS_SUN510_ENV
67 int (*sockfs_sounbind)
68   (struct sonode *, int);
69 void (*sockfs_sockfree)
70   (struct sonode *);
71 #endif
72
73 #ifndef UDP_MOD_NAME
74 #define UDP_MOD_NAME "udp"
75 #endif
76
77 static afs_uint32 myNetAddrs[ADDRSPERSITE];
78 static int myNetMTUs[ADDRSPERSITE];
79 static int numMyNetAddrs = 0;
80
81 int
82 rxi_GetIFInfo()
83 {
84     int i = 0;
85     int different = 0;
86 #ifndef AFS_SUN510_ENV
87     ill_t *ill;
88     ipif_t *ipif;
89 #endif
90     int rxmtu, maxmtu;
91     int mtus[ADDRSPERSITE];
92     afs_uint32 addrs[ADDRSPERSITE];
93     afs_uint32 ifinaddr;
94
95     memset(mtus, 0, sizeof(mtus));
96     memset(addrs, 0, sizeof(addrs));
97
98 #ifdef AFS_SUN510_ENV
99     (void) rw_enter(&afsifinfo_lock, RW_READER);
100
101     for (i = 0; (afsifinfo[i].ipaddr != NULL) && (i < ADDRSPERSITE); i++) {
102
103              /* Ignore addresses which are down.. */
104             if (!(afsifinfo[i].flags & IFF_UP))
105                 continue;
106
107             /* Compute the Rx interface MTU */
108             rxmtu = (afsifinfo[i].mtu - RX_IPUDP_SIZE);
109
110             ifinaddr = afsifinfo[i].ipaddr;
111             if (myNetAddrs[i] != ifinaddr)
112                 different++;
113
114             /* Copy interface MTU and address; adjust maxmtu */
115             mtus[i] = rxmtu;
116             rxmtu = rxi_AdjustIfMTU(rxmtu);
117             maxmtu = rxmtu * rxi_nRecvFrags +
118                 ((rxi_nRecvFrags - 1) * UDP_HDR_SIZE);
119             maxmtu = rxi_AdjustMaxMTU(rxmtu, maxmtu);
120             addrs[i] = ifinaddr;
121
122             if (!rx_IsLoopbackAddr(ifinaddr) && maxmtu > rx_maxReceiveSize) {
123                 rx_maxReceiveSize = MIN(RX_MAX_PACKET_SIZE, maxmtu);
124                 rx_maxReceiveSize =
125                     MIN(rx_maxReceiveSize, rx_maxReceiveSizeUser);
126             }
127             
128     }
129     
130     (void) rw_exit(&afsifinfo_lock);
131
132     rx_maxJumboRecvSize =
133         RX_HEADER_SIZE + rxi_nDgramPackets * RX_JUMBOBUFFERSIZE +
134         (rxi_nDgramPackets - 1) * RX_JUMBOHEADERSIZE;
135     rx_maxJumboRecvSize = MAX(rx_maxJumboRecvSize, rx_maxReceiveSize);
136
137     if (different) {
138         int j;
139
140         for (j = 0; j < i; j++) {
141             myNetMTUs[j] = mtus[j];
142             myNetAddrs[j] = addrs[j];
143         }
144     }
145
146     return different;
147 }
148
149 #else
150     for (ill = ill_g_head; ill; ill = ill->ill_next) {
151         /* Make sure this is an IPv4 ILL */
152         if (ill->ill_isv6)
153             continue;
154
155         /* Iterate over all the addresses on this ILL */
156         for (ipif = ill->ill_ipif; ipif; ipif = ipif->ipif_next) {
157             if (i >= ADDRSPERSITE)
158                 break;
159
160             /* Ignore addresses which are down.. */
161             if (!(ipif->ipif_flags & IFF_UP))
162                 continue;
163
164             /* Compute the Rx interface MTU */
165             rxmtu = (ipif->ipif_mtu - RX_IPUDP_SIZE);
166
167             ifinaddr = ntohl(ipif->ipif_local_addr);
168             if (myNetAddrs[i] != ifinaddr)
169                 different++;
170
171             /* Copy interface MTU and address; adjust maxmtu */
172             mtus[i] = rxmtu;
173             rxmtu = rxi_AdjustIfMTU(rxmtu);
174             maxmtu =
175                 rxmtu * rxi_nRecvFrags +
176                 ((rxi_nRecvFrags - 1) * UDP_HDR_SIZE);
177             maxmtu = rxi_AdjustMaxMTU(rxmtu, maxmtu);
178             addrs[i] = ifinaddr;
179             i++;
180
181             if (!rx_IsLoopbackAddr(ifinaddr) && maxmtu > rx_maxReceiveSize) {
182                 rx_maxReceiveSize = MIN(RX_MAX_PACKET_SIZE, maxmtu);
183                 rx_maxReceiveSize =
184                     MIN(rx_maxReceiveSize, rx_maxReceiveSizeUser);
185             }
186         }
187     }
188
189     rx_maxJumboRecvSize =
190         RX_HEADER_SIZE + rxi_nDgramPackets * RX_JUMBOBUFFERSIZE +
191         (rxi_nDgramPackets - 1) * RX_JUMBOHEADERSIZE;
192     rx_maxJumboRecvSize = MAX(rx_maxJumboRecvSize, rx_maxReceiveSize);
193
194     if (different) {
195         int j;
196
197         for (j = 0; j < i; j++) {
198             myNetMTUs[j] = mtus[j];
199             myNetAddrs[j] = addrs[j];
200         }
201     }
202
203     return different;
204 }
205 #endif
206
207 int
208 rxi_FindIfMTU(afs_uint32 addr)
209 {
210     afs_uint32 myAddr, netMask;
211     int match_value = 0;
212     int mtu = -1;
213 #ifdef AFS_SUN510_ENV
214     int i = 0;
215 #else
216     ill_t *ill;
217     ipif_t *ipif;
218 #endif
219
220     if (numMyNetAddrs == 0)
221         rxi_GetIFInfo();
222     myAddr = ntohl(addr);
223
224     if (IN_CLASSA(myAddr))
225         netMask = IN_CLASSA_NET;
226     else if (IN_CLASSB(myAddr))
227         netMask = IN_CLASSB_NET;
228     else if (IN_CLASSC(myAddr))
229         netMask = IN_CLASSC_NET;
230     else
231         netMask = 0;
232
233 #ifdef AFS_SUN510_ENV
234     (void) rw_enter(&afsifinfo_lock, RW_READER);
235
236     for (i = 0; (afsifinfo[i].ipaddr != NULL) && (i < ADDRSPERSITE); i++) {
237         afs_uint32 thisAddr, subnetMask;
238         int thisMtu;
239
240         /* Ignore addresses which are down.. */
241         if ((afsifinfo[i].flags & IFF_UP) == 0)
242             continue;
243
244         thisAddr = afsifinfo[i].ipaddr;
245         subnetMask = afsifinfo[i].netmask;
246         thisMtu = afsifinfo[i].mtu;
247
248         if ((myAddr & netMask) == (thisAddr & netMask)) {
249            if ((myAddr & subnetMask) == (thisAddr & subnetMask)) {
250                 if (myAddr == thisAddr) {
251                     match_value = 4;
252                     mtu = thisMtu;
253                 }
254
255                 if (match_value < 3) {
256                     match_value = 3;
257                     mtu = thisMtu;
258                 }
259            }
260
261            if (match_value < 2) {
262                 match_value = 2;
263                 mtu = thisMtu;
264            }
265         }
266      }
267      
268      (void) rw_exit(&afsifinfo_lock);
269
270      return mtu;
271 }
272 #else
273     for (ill = ill_g_head; ill; ill = ill->ill_next) {
274         /* Make sure this is an IPv4 ILL */
275         if (ill->ill_isv6)
276             continue;
277
278         /* Iterate over all the addresses on this ILL */
279         for (ipif = ill->ill_ipif; ipif; ipif = ipif->ipif_next) {
280             afs_uint32 thisAddr, subnetMask;
281             int thisMtu;
282
283             thisAddr = ipif->ipif_local_addr;
284             subnetMask = ipif->ipif_net_mask;
285             thisMtu = ipif->ipif_mtu;
286
287             if ((myAddr & netMask) == (thisAddr & netMask)) {
288                 if ((myAddr & subnetMask) == (thisAddr & subnetMask)) {
289                     if (myAddr == thisAddr) {
290                         match_value = 4;
291                         mtu = thisMtu;
292                     }
293
294                     if (match_value < 3) {
295                         match_value = 3;
296                         mtu = thisMtu;
297                     }
298                 }
299
300                 if (match_value < 2) {
301                     match_value = 2;
302                     mtu = thisMtu;
303                 }
304             }
305         }
306     }
307
308     return mtu;
309 }
310 #endif
311
312 /* rxi_NewSocket, rxi_FreeSocket and osi_NetSend are from the now defunct
313  * afs_osinet.c. 
314  */
315
316 struct sockaddr_in rx_sockaddr;
317
318 /* Allocate a new socket at specified port in network byte order. */
319 osi_socket *
320 rxk_NewSocketHost(afs_uint32 ahost, short aport)
321 {
322     vnode_t *accessvp;
323     struct sonode *so;
324     struct sockaddr_in addr;
325     int error;
326     int len;
327 #ifdef SOLOOKUP_TAKES_SOCKPARAMS
328     struct sockparams *sp;
329 #endif
330
331     AFS_STATCNT(osi_NewSocket);
332
333     if (sockfs_solookup == NULL) {
334         sockfs_solookup =
335 #ifdef SOLOOKUP_TAKES_SOCKPARAMS
336             (int (*)())modlookup("sockfs", "solookup");
337 #else
338             (struct vnode * (*)())modlookup("sockfs", "solookup");
339 #endif
340         if (sockfs_solookup == NULL) {
341             return NULL;
342         }
343     }
344     if (sockfs_socreate == NULL) {
345         sockfs_socreate =
346             (struct sonode * (*)())modlookup("sockfs", "socreate");
347         if (sockfs_socreate == NULL) {
348             return NULL;
349         }
350     }
351     if (sockfs_sobind == NULL) {
352         sockfs_sobind = (int (*)())modlookup("sockfs", "sobind");
353         if (sockfs_sobind == NULL) {
354             return NULL;
355         }
356     }
357     if (sockfs_sosetsockopt == NULL) {
358         sockfs_sosetsockopt = (int (*)())modlookup("sockfs", "sosetsockopt");
359         if (sockfs_sosetsockopt == NULL) {
360             return NULL;
361         }
362     }
363     if (sockfs_sosendmsg == NULL) {
364         sockfs_sosendmsg = (int (*)())modlookup("sockfs", "sosendmsg");
365         if (sockfs_sosendmsg == NULL) {
366             return NULL;
367         }
368     }
369     if (sockfs_sorecvmsg == NULL) {
370         sockfs_sorecvmsg = (int (*)())modlookup("sockfs", "sorecvmsg");
371         if (sockfs_sorecvmsg == NULL) {
372             return NULL;
373         }
374     }
375 #ifndef AFS_SUN510_ENV
376     if (sockfs_sounbind == NULL) {
377         sockfs_sounbind = (int (*)())modlookup("sockfs", "sounbind");
378         if (sockfs_sounbind == NULL)
379             return NULL;
380     }
381     if (sockfs_sockfree == NULL) {
382         sockfs_sockfree = (void (*)())modlookup("sockfs", "sockfree");
383         if (sockfs_sockfree == NULL)
384             return NULL;
385     }
386 #endif
387
388 #ifdef SOLOOKUP_TAKES_SOCKPARAMS
389     error = sockfs_solookup(AF_INET, SOCK_DGRAM, 0, &sp);
390     if (error != 0) {
391         return NULL;
392     }
393
394     so = sockfs_socreate(sp, AF_INET, SOCK_DGRAM, 0, SOV_STREAM, &error);
395 #else
396     accessvp = sockfs_solookup(AF_INET, SOCK_DGRAM, 0, "/dev/udp", &error);
397     if (accessvp == NULL) {
398         return NULL;
399     }
400
401     so = sockfs_socreate(accessvp, AF_INET, SOCK_DGRAM, 0, SOV_STREAM, NULL,
402                          &error);
403 #endif /* SOLOOKUP_TAKES_SOCKPARAMS */
404
405     if (so == NULL) {
406         return NULL;
407     }
408
409     addr.sin_family = AF_INET;
410     addr.sin_port = aport;
411     addr.sin_addr.s_addr = ahost; /* I wonder what the odds are on
412                                      needing to unbyteswap this */
413     error = sockfs_sobind(so, (struct sockaddr *)&addr, sizeof(addr), 0, 0);
414     if (error != 0) {
415         return NULL;
416     }
417
418     len = rx_UdpBufSize;
419     error = sockfs_sosetsockopt(so, SOL_SOCKET, SO_SNDBUF, &len, sizeof(len));
420     if (error != 0) {
421         return NULL;
422     }
423
424     len = rx_UdpBufSize;
425     error = sockfs_sosetsockopt(so, SOL_SOCKET, SO_RCVBUF, &len, sizeof(len));
426     if (error != 0) {
427         return NULL;
428     }
429
430     return (osi_socket *)so;
431 }
432
433 osi_socket *
434 rxk_NewSocket(short aport)
435 {
436     return rxk_NewSocketHost(htonl(INADDR_ANY), aport);
437 }
438
439 int
440 osi_FreeSocket(osi_socket asocket)
441 {
442     extern int rxk_ListenerPid;
443     struct sonode *so = (struct sonode *)asocket;
444     struct sockaddr_in taddr;
445     struct iovec dvec;
446     char c;
447     vnode_t *vp;
448
449     AFS_STATCNT(osi_FreeSocket);
450
451     taddr.sin_family = AF_INET;
452     taddr.sin_port = rx_port;
453     taddr.sin_addr.s_addr = htonl(0x7f000001);
454
455     dvec.iov_base = &c;
456     dvec.iov_len = 1;
457
458     while (rxk_ListenerPid) {
459         osi_NetSend(rx_socket, &taddr, &dvec, 1, 1, 0);
460         afs_osi_Sleep(&rxk_ListenerPid);
461     }
462
463     /* Was sockfs_sounbind(so, 0); sockfs_sockfree(so); That's wrong */
464     vp = SOTOV(so);
465  #ifdef AFS_SUN511_ENV
466     VOP_CLOSE(vp, FREAD|FWRITE, 1, (offset_t)0, CRED(), NULL);
467  #else
468     VOP_CLOSE(vp, FREAD|FWRITE, 1, (offset_t)0, CRED());
469  #endif
470     VN_RELE(vp);
471
472     return 0;
473 }
474
475 int
476 osi_NetSend(osi_socket asocket, struct sockaddr_in *addr, struct iovec *dvec,
477             int nvecs, afs_int32 asize, int istack)
478 {
479     struct sonode *so = (struct sonode *)asocket;
480     struct nmsghdr msg;
481     struct uio uio;
482     struct iovec iov[RX_MAXIOVECS];
483     int error;
484     int i;
485
486     if (nvecs > RX_MAXIOVECS) {
487         osi_Panic("osi_NetSend: %d: Too many iovecs.\n", nvecs);
488     }
489
490     msg.msg_name = (struct sockaddr *)addr;
491     msg.msg_namelen = sizeof(struct sockaddr_in);
492     msg.msg_iov = dvec;
493     msg.msg_iovlen = nvecs;
494     msg.msg_control = NULL;
495     msg.msg_controllen = 0;
496     msg.msg_flags = 0;
497
498     for (i = 0; i < nvecs; i++) {
499         iov[i].iov_base = dvec[i].iov_base;
500         iov[i].iov_len = dvec[i].iov_len;
501     }
502     uio.uio_iov = &iov[0];
503     uio.uio_iovcnt = nvecs;
504     uio.uio_loffset = 0;
505     uio.uio_segflg = UIO_SYSSPACE;
506     uio.uio_fmode = FREAD | FWRITE;
507     uio.uio_limit = 0;
508     uio.uio_resid = asize;
509
510     error = sockfs_sosendmsg(so, &msg, &uio);
511
512     return error;
513 }
514
515 int
516 osi_NetReceive(osi_socket so, struct sockaddr_in *addr, struct iovec *dvec,
517                int nvecs, int *alength)
518 {
519     struct sonode *asocket = (struct sonode *)so;
520     struct nmsghdr msg;
521     struct uio uio;
522     struct iovec iov[RX_MAXIOVECS];
523     int error;
524     int i;
525
526     if (nvecs > RX_MAXIOVECS) {
527         osi_Panic("osi_NetSend: %d: Too many iovecs.\n", nvecs);
528     }
529
530     msg.msg_name = NULL;
531     msg.msg_namelen = sizeof(struct sockaddr_in);
532     msg.msg_iov = NULL;
533     msg.msg_iovlen = 0;
534     msg.msg_control = NULL;
535     msg.msg_controllen = 0;
536     msg.msg_flags = 0;
537
538     for (i = 0; i < nvecs; i++) {
539         iov[i].iov_base = dvec[i].iov_base;
540         iov[i].iov_len = dvec[i].iov_len;
541     }
542     uio.uio_iov = &iov[0];
543     uio.uio_iovcnt = nvecs;
544     uio.uio_loffset = 0;
545     uio.uio_segflg = UIO_SYSSPACE;
546     uio.uio_fmode = 0;
547     uio.uio_limit = 0;
548     uio.uio_resid = *alength;
549
550     error = sockfs_sorecvmsg(asocket, &msg, &uio);
551     if (error == 0) {
552         if (msg.msg_name == NULL) {
553             error = -1;
554         } else {
555             memcpy(addr, msg.msg_name, msg.msg_namelen);
556             kmem_free(msg.msg_name, msg.msg_namelen);
557             *alength = *alength - uio.uio_resid;
558         }
559     }
560
561     if (error == EINTR && ISSIG(curthread, FORREAL)) {
562         klwp_t *lwp = ttolwp(curthread);
563         proc_t *p = ttoproc(curthread);
564         int sig = lwp->lwp_cursig;
565
566         if (sig == SIGKILL) {
567             mutex_enter(&p->p_lock);
568             p->p_flag &= ~SKILLED;
569             mutex_exit(&p->p_lock);
570         }
571         lwp->lwp_cursig = 0;
572         if (lwp->lwp_curinfo) {
573             siginfofree(lwp->lwp_curinfo);
574             lwp->lwp_curinfo = NULL;
575         }
576     }
577
578     return error;
579 }
580
581 #if defined(AFS_SUN510_ENV)
582 /* How often afs collects interface info. Tunable via /etc/system:      */
583 /* set afs:afs_if_poll_interval = integer (value is in seconds)         */
584 static int afs_if_poll_interval = 30;
585
586 static timeout_id_t afs_if_poller_timeout = 0;
587
588 /* Global array which holds the interface info for consumers            */
589 struct afs_ifinfo afsifinfo[ADDRSPERSITE];
590
591 void
592 osi_StartNetIfPoller()
593 {
594     (void) ddi_taskq_dispatch(afs_taskq, (void(*) (void*)) osi_NetIfPoller,
595             NULL, DDI_SLEEP);
596 }
597
598 void
599 osi_NetIfPoller()
600 {
601     cred_t *cr;
602     ldi_ident_t li = NULL;
603     ldi_handle_t lh = NULL;
604     struct lifnum lifn;
605     struct lifconf lifc;
606     struct lifreq lifr;
607     struct lifreq *lifrp;
608     struct sockaddr_in *sin4_local;
609     struct sockaddr_in *sin4_dst;
610     major_t udpmajor;
611     caddr_t lifcbuf = NULL;
612     int i, count, error, rv;
613     int ifcount;
614     int metric;
615     int index;
616     uint_t mtu;
617     uint64_t flags;
618
619     /* Get our permissions */
620     cr = CRED();
621
622     /* Initialize and open /dev/udp for receiving ioctls */
623     udpmajor = ddi_name_to_major(UDP_MOD_NAME);
624
625     error = ldi_ident_from_major(udpmajor, &li);
626     if (error) {
627         cmn_err(CE_WARN, "osi_NetIfPoller: ldi_ident_from_major failed: %d",
628             error);
629         goto cleanup;
630     }
631
632     error = ldi_open_by_name(UDP_DEV_NAME, FREAD, cr, &lh, li);
633     if (error) {
634         cmn_err(CE_WARN,
635             "osi_NetIfPoller: ldi_open_by_name failed: %d", error);
636         goto cleanup;
637     }
638
639     /* First, how many interfaces do we have? */
640     (void) bzero((void *)&lifn, sizeof(struct lifnum));
641     lifn.lifn_family   = AF_INET;
642
643     error = ldi_ioctl(lh, SIOCGLIFNUM, (intptr_t)&lifn,
644         FKIOCTL, cr, &rv);
645     if (error) {
646         cmn_err(CE_WARN,
647                 "osi_NetIfPoller: ldi_ioctl: SIOCGLIFNUM failed: %d", error);
648         goto cleanup;
649     }
650     ifcount = lifn.lifn_count;
651
652     /* Set up some stuff for storing the results of SIOCGLIFCONF */
653     (void) bzero((void *)&lifc, sizeof(struct lifconf));
654
655     lifcbuf = kmem_zalloc(ifcount * sizeof(struct lifreq), KM_SLEEP);
656
657     lifc.lifc_family  = AF_INET;
658     lifc.lifc_flags   = IFF_UP;
659     lifc.lifc_len     = ifcount * sizeof(struct lifreq);
660     lifc.lifc_buf     = lifcbuf;
661
662     /* Get info on each of our available interfaces. */
663     error = ldi_ioctl(lh, SIOCGLIFCONF, (intptr_t)&lifc,
664         FKIOCTL, cr, &rv);
665     if (error) {
666         cmn_err(CE_WARN,
667                 "osi_NetIfPoller: ldi_ioctl: SIOCGLIFCONF failed: %d", error);
668         goto cleanup;
669     }
670     lifrp = lifc.lifc_req;
671
672     count = 0;
673
674     /* Loop through our interfaces and pick out the info we want */
675     for (i = lifc.lifc_len / sizeof(struct lifreq);
676         i > 0; i--, lifrp++) {
677                 
678         if (count >= ADDRSPERSITE)
679                 break;
680
681         (void) bzero((void *)&lifr, sizeof(struct lifreq));
682
683         (void) strncpy(lifr.lifr_name, lifrp->lifr_name,
684             sizeof(lifr.lifr_name));
685
686         /* Get this interface's Flags */
687         error = ldi_ioctl(lh, SIOCGLIFFLAGS, (intptr_t)&lifr,
688             FKIOCTL, cr, &rv);
689         if (error) {
690             cmn_err(CE_WARN,
691                     "osi_NetIfPoller: ldi_ioctl: SIOCGLIFFLAGS failed: %d",
692                     error);
693             goto cleanup;
694         }
695
696         /* Ignore plumbed but down interfaces. */
697         if ((lifr.lifr_flags & IFF_UP) == 0)
698             continue;
699
700         flags = lifr.lifr_flags;
701
702         /* Get this interface's MTU */
703         error = ldi_ioctl(lh, SIOCGLIFMTU, (intptr_t)&lifr,
704             FKIOCTL, cr, &rv);
705
706         if (error) {
707             mtu = 1125;
708         } else {
709             mtu = lifr.lifr_metric;
710         }
711
712         /* Get this interface's Metric */
713         error = ldi_ioctl(lh, SIOCGLIFMETRIC, (intptr_t)&lifr,
714             FKIOCTL, cr, &rv);
715
716         if (error) {
717             metric = 0;
718         } else {
719             metric = lifr.lifr_metric;
720         }
721
722         sin4_local = (struct sockaddr_in *) &lifrp->lifr_addr;
723         sin4_dst = (struct sockaddr_in *) &lifrp->lifr_dstaddr;
724
725         /* Acquire global array write lock */
726         (void) rw_enter(&afsifinfo_lock, RW_WRITER);
727
728         /* Copy our collected data into the global array */
729         (void) strncpy(afsifinfo[count].ifname, lifrp->lifr_name,
730             sizeof(afsifinfo[count].ifname));
731         afsifinfo[count].ipaddr     = ntohl(sin4_local->sin_addr.s_addr);
732         afsifinfo[count].mtu        = mtu;
733         afsifinfo[count].netmask    = lifrp->lifr_addrlen;
734         afsifinfo[count].flags      = flags;
735         afsifinfo[count].metric     = metric;
736         afsifinfo[count].dstaddr    = ntohl(sin4_dst->sin_addr.s_addr);
737
738         /* Release global array write lock */
739         (void) rw_exit(&afsifinfo_lock);
740
741         count++;
742
743     } /* Bottom of loop: for each interface ... */
744
745   cleanup:
746     /* End of thread. Time to clean up */
747     if (lifcbuf)
748         kmem_free(lifcbuf, ifcount * sizeof(struct lifreq));
749     if (lh)
750         (void) ldi_close(lh, FREAD, cr);
751     if (li)
752         (void) ldi_ident_release(li);
753
754     if (afs_shuttingdown) {
755         /* do not schedule to run again if we're shutting down */
756         return;
757     }
758
759     /* Schedule this to run again after afs_if_poll_interval seconds */
760     afs_if_poller_timeout = timeout((void(*) (void *)) osi_StartNetIfPoller,
761         NULL, drv_usectohz((clock_t)afs_if_poll_interval * MICROSEC));
762 }
763
764 void
765 osi_StopNetIfPoller(void)
766 {
767     /* it's okay if untimeout races with StartNetIfPoller/NetIfPoller;
768      * it can handle being passed invalid ids. If StartNetIfPoller is
769      * in the middle of running, untimeout will not return until
770      * StartNetIfPoller is done */
771     untimeout(afs_if_poller_timeout);
772
773     /* if NetIfPoller is queued or running, ddi_taskq_destroy will not
774      * return until it is done */
775     ddi_taskq_destroy(afs_taskq);
776
777     rw_destroy(&afsifinfo_lock);
778
779     if (afs_termState == AFSOP_STOP_NETIF) {
780         afs_termState = AFSOP_STOP_COMPLETE;
781         osi_rxWakeup(&afs_termState);
782     }
783 }
784 #endif /* AFS_SUN510_ENV */
785
786 void
787 shutdown_rxkernel(void)
788 {
789 }
790
791 void
792 osi_StopListener(void)
793 {
794     osi_FreeSocket(rx_socket);
795 }
796
797 #endif /* AFS_SUN5_ENV */