initial-solaris8-support-20001105
[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 "../afs/param.h"
11 #ifdef AFS_SUN5_ENV
12 #include "../rx/rx_kcommon.h"
13
14
15 #ifdef AFS_SUN56_ENV
16
17 #include "../inet/common.h"
18 #include "../sys/tiuser.h"
19 #include "../sys/t_kuser.h"
20 #include "../sys/stropts.h"
21 #include "../sys/stream.h"
22 #include "../sys/tihdr.h"
23 #include "../sys/fcntl.h"
24 #ifdef AFS_SUN58_ENV
25 #include "../netinet/ip6.h"
26 #endif
27 #include "../inet/ip.h"
28 #include "../netinet/udp.h"
29
30 /*
31  * Function pointers for kernel socket routines
32  */
33 struct sonode *(*sockfs_socreate)
34     (vnode_t *, int, int, int, int, struct sonode *, int *) = NULL;
35 struct vnode *(*sockfs_solookup)
36     (int, int, int, char *, int *) = NULL;
37 int (*sockfs_sobind)
38     (struct sonode *, struct sockaddr *, int, int, int) = NULL;
39 int (*sockfs_sorecvmsg)
40     (struct sonode *, struct nmsghdr *, struct uio *) = NULL;
41 int (*sockfs_sosendmsg)
42     (struct sonode *, struct nmsghdr *, struct uio *) = NULL;
43 int (*sockfs_sosetsockopt)
44     (struct sonode *, int, int, void *, int) = NULL;
45
46 int rxi_GetIFInfo()
47 {
48     return 0;
49 }
50
51 /* rxi_NewSocket, rxi_FreeSocket and osi_NetSend are from the now defunct
52  * afs_osinet.c. 
53  */
54
55 struct sockaddr_in rx_sockaddr;
56
57 /* Allocate a new socket at specified port in network byte order. */
58 struct osi_socket *rxk_NewSocket(short aport)
59 {
60     vnode_t *accessvp;
61     struct sonode *so;
62     struct sockaddr_in addr;
63     int error;
64     int len;
65
66     AFS_STATCNT(osi_NewSocket);
67
68     if (sockfs_solookup == NULL) {
69         sockfs_solookup = (struct vnode *(*)())modlookup("sockfs", "solookup");
70         if (sockfs_solookup == NULL) {
71             return NULL;
72         }
73     }
74     if (sockfs_socreate == NULL) {
75         sockfs_socreate = (struct sonode *(*)())modlookup("sockfs", "socreate");
76         if (sockfs_socreate == NULL) {
77             return NULL;
78         }
79     }
80     if (sockfs_sobind == NULL) {
81         sockfs_sobind = (int (*)())modlookup("sockfs", "sobind");
82         if (sockfs_sobind == NULL) {
83             return NULL;
84         }
85     }
86     if (sockfs_sosetsockopt == NULL) {
87         sockfs_sosetsockopt = (int (*)())modlookup("sockfs", "sosetsockopt");
88         if (sockfs_sosetsockopt == NULL) {
89             return NULL;
90         }
91     }
92     if (sockfs_sosendmsg == NULL) {
93         sockfs_sosendmsg = (int (*)())modlookup("sockfs", "sosendmsg");
94         if (sockfs_sosendmsg == NULL) {
95             return NULL;
96         }
97     }
98     if (sockfs_sorecvmsg == NULL) {
99         sockfs_sorecvmsg = (int (*)())modlookup("sockfs", "sorecvmsg");
100         if (sockfs_sorecvmsg == NULL) {
101             return NULL;
102         }
103     }
104
105     accessvp = sockfs_solookup(AF_INET, SOCK_DGRAM, 0, "/dev/udp", &error);
106     if (accessvp == NULL) {
107         return NULL;
108     }
109
110     so = sockfs_socreate(accessvp, AF_INET, SOCK_DGRAM, 0,
111                          SOV_STREAM, NULL, &error);
112     if (so == NULL) {
113         return NULL;
114     }
115
116     addr.sin_family = AF_INET;
117     addr.sin_port = aport;
118     addr.sin_addr.s_addr = INADDR_ANY;
119     error = sockfs_sobind(so, (struct sockaddr *)&addr, sizeof(addr), 0, 0);
120     if (error != 0) {
121         return NULL;
122     }
123
124     len = rx_UdpBufSize;
125     error = sockfs_sosetsockopt(so, SOL_SOCKET, SO_SNDBUF, &len, sizeof(len));
126     if (error != 0) {
127         return NULL;
128     }
129
130     len = rx_UdpBufSize;
131     error = sockfs_sosetsockopt(so, SOL_SOCKET, SO_RCVBUF, &len, sizeof(len));
132     if (error != 0) {
133         return NULL;
134     }
135
136     return (struct osi_socket *)so;
137 }
138
139 int osi_FreeSocket(asocket)
140     register struct osi_socket *asocket; 
141 {
142     extern int rxk_ListenerPid;
143     struct sonode *so = (struct sonode *)asocket;
144     vnode_t *vp = SOTOV(so);
145
146     AFS_STATCNT(osi_FreeSocket);
147     if (rxk_ListenerPid)
148         kill(rxk_ListenerPid, SIGUSR1);
149     return 0;
150 }
151
152 int osi_NetSend(asocket, addr, dvec, nvecs, asize, istack) 
153     struct osi_socket *asocket;
154     struct sockaddr_in *addr; 
155     struct iovec dvec[];
156     int nvecs;
157     afs_int32 asize;
158     int istack;
159 {
160     struct sonode *so = (struct sonode *)asocket;
161     struct nmsghdr msg;
162     struct uio uio;
163     struct iovec iov[RX_MAXIOVECS];
164     int error;
165     int i;
166  
167     if (nvecs > RX_MAXIOVECS) {
168         osi_Panic("osi_NetSend: %d: Too many iovecs.\n", nvecs);
169     }
170
171     msg.msg_name = (struct sockaddr *)addr;
172     msg.msg_namelen = sizeof(struct sockaddr_in);
173     msg.msg_iov = dvec;
174     msg.msg_iovlen = nvecs;
175     msg.msg_control = NULL;
176     msg.msg_controllen = 0;
177     msg.msg_flags = 0;
178
179     for (i = 0 ; i < nvecs ; i++) {
180         iov[i].iov_base = dvec[i].iov_base;
181         iov[i].iov_len = dvec[i].iov_len;
182     }
183     uio.uio_iov = &iov[0];
184     uio.uio_iovcnt = nvecs;
185     uio.uio_loffset = 0;
186     uio.uio_segflg = UIO_SYSSPACE;
187     uio.uio_fmode = FREAD|FWRITE;
188     uio.uio_limit = 0;
189     uio.uio_resid = asize;
190
191     error = sockfs_sosendmsg(so, &msg, &uio);
192
193     return error;
194 }
195
196 int osi_NetReceive(asocket, addr, dvec, nvecs, alength)
197     struct osi_socket *asocket;
198     struct sockaddr_in *addr;
199     struct iovec *dvec;
200     int nvecs;
201     int *alength;
202 {
203     struct sonode *so = (struct sonode *)asocket;
204     struct nmsghdr msg;
205     struct uio uio;
206     struct iovec iov[RX_MAXIOVECS];
207     int error;
208     int i;
209  
210     if (nvecs > RX_MAXIOVECS) {
211         osi_Panic("osi_NetSend: %d: Too many iovecs.\n", nvecs);
212     }
213
214     msg.msg_name = NULL;
215     msg.msg_namelen = sizeof(struct sockaddr_in);
216     msg.msg_iov = NULL;
217     msg.msg_iovlen = 0;
218     msg.msg_control = NULL;
219     msg.msg_controllen = 0;
220     msg.msg_flags = 0;
221
222     for (i = 0 ; i < nvecs ; i++) {
223         iov[i].iov_base = dvec[i].iov_base;
224         iov[i].iov_len = dvec[i].iov_len;
225     }
226     uio.uio_iov = &iov[0];
227     uio.uio_iovcnt = nvecs;
228     uio.uio_loffset = 0;
229     uio.uio_segflg = UIO_SYSSPACE;
230     uio.uio_fmode = 0;
231     uio.uio_limit = 0;
232     uio.uio_resid = *alength;
233
234     error = sockfs_sorecvmsg(so, &msg, &uio);
235     if (error == 0) {
236         if (msg.msg_name == NULL) {
237             error = -1;
238         } else {
239             bcopy(msg.msg_name, addr, msg.msg_namelen);
240             kmem_free(msg.msg_name, msg.msg_namelen);
241             *alength = *alength - uio.uio_resid;
242         }
243     }
244
245     if (error == EINTR && ISSIG(curthread, FORREAL)) {
246         klwp_t *lwp = ttolwp(curthread);
247         proc_t *p = ttoproc(curthread);
248         int sig = lwp->lwp_cursig;
249
250         if (sig == SIGKILL) {
251             mutex_enter(&p->p_lock);
252             p->p_flag &= ~SKILLED;
253             mutex_exit(&p->p_lock);
254         }
255         lwp->lwp_cursig = 0;
256         if (lwp->lwp_curinfo) {
257             siginfofree(lwp->lwp_curinfo);
258             lwp->lwp_curinfo = NULL;
259         }
260     }
261
262     return error;
263 }
264
265 void shutdown_rxkernel(void)
266 {
267 }
268
269 void osi_StopListener(void)
270 {
271     osi_FreeSocket(rx_socket);
272 }
273
274 #else /* AFS_SUN56_ENV */
275
276 #include "../inet/common.h"
277 #include "../sys/tiuser.h"
278 #include "../sys/t_kuser.h"
279 #include "../sys/ioctl.h"
280 #include "../sys/stropts.h"
281 #include "../sys/stream.h"
282 #include "../sys/strsubr.h"
283 #include "../sys/vnode.h"
284 #include "../sys/stropts.h"
285 #include "../sys/tihdr.h"
286 #include "../sys/timod.h"
287 #include "../sys/fcntl.h"
288 #include "../sys/debug.h"
289 #include "../inet/common.h"
290 #include "../inet/mi.h"
291 #include "../netinet/udp.h"
292
293 extern dev_t afs_udp_rdev;
294
295
296 int rxi_GetIFInfo()
297 {
298     return 0;
299 }
300
301
302 /* rxi_NewSocket, rxi_FreeSocket and osi_NetSend are from the now defunct
303  * afs_osinet.c. 
304  */
305
306 dev_t afs_udp_rdev = (dev_t)0;
307
308 /* Allocate a new socket at specified port in network byte order. */
309 struct osi_socket *rxk_NewSocket(short aport)
310 {
311     TIUSER *udp_tiptr;
312     struct t_bind *reqp, *rspp;
313     afs_int32 code;
314     struct sockaddr_in *myaddrp;
315     struct stdata *stp;
316     struct queue *q;
317
318     AFS_STATCNT(osi_NewSocket);
319     afs_udp_rdev = makedevice(11 /*CLONE*/, ddi_name_to_major("udp"));
320     code = t_kopen(NULL, afs_udp_rdev, FREAD|FWRITE, &udp_tiptr, CRED());
321     if (code) {
322         return (struct osi_socket *)0;
323     }
324
325     code = t_kalloc(udp_tiptr, T_BIND, T_ADDR, (char **)&reqp);
326     if (code) {
327         t_kclose(udp_tiptr, 0);
328     }
329     code = t_kalloc(udp_tiptr, T_BIND, T_ADDR, (char **)&rspp);
330     if (code) {
331         t_kfree(udp_tiptr, (char *)reqp, T_BIND);
332         t_kclose(udp_tiptr, 0);
333         return (struct osi_socket *)0;
334     }
335
336     reqp->addr.len = sizeof(struct sockaddr_in);
337     myaddrp = (struct sockaddr_in *) reqp->addr.buf;
338     myaddrp->sin_family = AF_INET;
339     myaddrp->sin_port = aport;
340     myaddrp->sin_addr.s_addr = INADDR_ANY;      /* XXX Was 0 XXX */
341
342     code = t_kbind(udp_tiptr, reqp, rspp);
343     if (code) {
344         t_kfree(udp_tiptr, (char *)reqp, T_BIND);
345         t_kfree(udp_tiptr, (char *)rspp, T_BIND);
346         t_kclose(udp_tiptr, 0);
347         return (struct osi_socket *)0;
348     }
349     if (bcmp(reqp->addr.buf, rspp->addr.buf, rspp->addr.len)) {
350         t_kfree(udp_tiptr, (char *)reqp, T_BIND);
351         t_kfree(udp_tiptr, (char *)rspp, T_BIND);
352         t_kclose(udp_tiptr, 0);
353         return (struct osi_socket *)0;
354     }
355     t_kfree(udp_tiptr, (char *)reqp, T_BIND);
356     t_kfree(udp_tiptr, (char *)rspp, T_BIND);
357
358     /*
359      * Set the send and receive buffer sizes.
360      */
361     stp = udp_tiptr->fp->f_vnode->v_stream;
362     q = stp->sd_wrq;
363     q->q_hiwat = rx_UdpBufSize;
364     q->q_next->q_hiwat = rx_UdpBufSize;
365     RD(q)->q_hiwat = rx_UdpBufSize;
366
367     return (struct osi_socket *) udp_tiptr;
368 }
369
370
371 int osi_FreeSocket(asocket)
372     register struct osi_socket *asocket; 
373 {
374     extern int rxk_ListenerPid;
375     TIUSER *udp_tiptr = (TIUSER *) asocket;    
376     AFS_STATCNT(osi_FreeSocket);
377
378     if (rxk_ListenerPid)
379         kill(rxk_ListenerPid, SIGUSR1);
380     return 0;
381 }
382
383
384 int osi_NetSend(asocket, addr, dvec, nvecs, asize, istack) 
385     register struct osi_socket *asocket;
386     struct iovec dvec[];
387     int nvecs;
388     register afs_int32 asize;
389     struct sockaddr_in *addr; 
390     int istack;
391 {
392     int i;
393     int code;
394     TIUSER *udp_tiptr = (TIUSER *) asocket;    
395     struct t_kunitdata *udreq;
396     struct sockaddr_in sin;
397     mblk_t *bp;
398     mblk_t *dbp;
399
400     /*
401      * XXX We don't do any checking on the family since it's assumed to be
402      * AF_INET XXX
403      */
404     sin.sin_family = AF_INET;
405     sin.sin_addr.s_addr = addr->sin_addr.s_addr;
406     sin.sin_port = addr->sin_port;
407
408     /*
409      * Get a buffer for the RX header
410      */
411     if (nvecs < 1) {
412         osi_Panic("osi_NetSend, nvecs=%d\n", nvecs);
413     }
414     while (!(bp = allocb(dvec[0].iov_len, BPRI_LO))) {
415         if (strwaitbuf(dvec[i].iov_len, BPRI_LO)) {
416             return (ENOSR);
417         }
418     }
419
420     /* Copy the data into the buffer */
421     bcopy((char *)dvec[0].iov_base, (char *)bp->b_wptr, dvec[0].iov_len);
422     bp->b_datap->db_type = M_DATA;
423     bp->b_wptr += dvec[0].iov_len;
424
425     /*
426      * Append each element in the iovec to the buffer
427      */
428     for (i = 1 ; i < nvecs ; i++) {
429         /* Get a buffer for the next chunk */
430         while (!(dbp = allocb(dvec[i].iov_len, BPRI_LO))) {
431             if (strwaitbuf(dvec[i].iov_len, BPRI_LO)) {
432                 freeb(bp);
433                 return (ENOSR);
434             }
435         }
436
437         /* Copy the data into the buffer */
438         bcopy((char *)dvec[i].iov_base, (char *)dbp->b_wptr, dvec[i].iov_len);
439         dbp->b_datap->db_type = M_DATA;
440         dbp->b_wptr += dvec[i].iov_len;
441
442         /* Append it to the message buffer */
443         linkb(bp, dbp);
444     }
445
446     /*
447      * Allocate and format the unitdata structure.
448      */
449     code = t_kalloc(udp_tiptr, T_UNITDATA, T_UDATA, (char **)&udreq);
450     if (code) {
451         freeb(bp);
452         printf("osi_NetSend: t_kalloc failed %d\n", code);
453         return code;
454     }
455     udreq->addr.len = sizeof(struct sockaddr_in);
456     udreq->addr.maxlen = sizeof(struct sockaddr_in);
457     udreq->addr.buf = (char *)kmem_alloc(sizeof(struct sockaddr_in), KM_SLEEP);
458     udreq->opt.len = 0;
459     udreq->opt.maxlen = 0;
460     bcopy((char *)&sin, udreq->addr.buf, sizeof(struct sockaddr_in));
461     udreq->udata.udata_mp = bp;
462     udreq->udata.len = asize;
463
464     code = t_ksndudata(udp_tiptr, udreq, NULL);
465     if (code) {
466         printf("osi_NetSend: t_ksndudata failed %d\n", code);
467     }
468
469     t_kfree(udp_tiptr, (caddr_t)udreq, T_UNITDATA);
470     return code;
471 }
472
473
474 int osi_NetReceive(asocket, addr, dvec, nvecs, alength)
475     struct osi_socket *asocket;
476     struct sockaddr_in *addr;
477     struct iovec *dvec;
478     int nvecs;
479     int *alength;
480 {
481     int i;
482     TIUSER *udp_tiptr = (TIUSER *) asocket;    
483     struct t_kunitdata *udreq;
484     mblk_t *dbp;
485     char *phandle;
486     short sport;
487     int code = 0;
488     int length;
489     int tlen;
490     int blen;
491     char *tbase;
492     int type;
493     int error;
494     int events;
495
496     /*
497      * Allocate the unitdata structure.
498      */
499     code = t_kalloc(udp_tiptr, T_UNITDATA, T_UDATA, (char **)&udreq);
500     if (code) {
501         printf("osi_NetReceive: t_kalloc failed %d\n", code);
502         return code;
503     }
504     udreq->addr.len = sizeof(struct sockaddr_in);
505     udreq->addr.maxlen = sizeof(struct sockaddr_in);
506     udreq->addr.buf = (char *)kmem_alloc(sizeof(struct sockaddr_in), KM_SLEEP);
507     udreq->opt.len = 0;
508     udreq->opt.maxlen = 0;
509
510     /*
511      * Loop until we get an error or receive some data.
512      */
513     while(1) {
514         /*
515          * Wait until there is something to do
516          */
517         code = t_kspoll(udp_tiptr, -1, READWAIT, &events);
518         if (events == 0) {
519             osi_Panic("osi_NetReceive, infinite t_kspoll timed out\n");
520         }
521         /*
522          * If there is a message then read it in
523          */
524         if (code == 0) {
525             code = t_krcvudata(udp_tiptr, udreq, &type, &error);
526         }
527
528         /*
529          * Block attempts to kill this thread
530          */
531         if (code == EINTR && ISSIG(curthread, FORREAL)) {
532             klwp_t *lwp = ttolwp(curthread);
533             proc_t *p = ttoproc(curthread);
534             int sig = lwp->lwp_cursig;
535
536             if (sig == SIGKILL) {
537                 mutex_enter(&p->p_lock);
538                 p->p_flag &= ~SKILLED;
539                 mutex_exit(&p->p_lock);
540             }
541             lwp->lwp_cursig = 0;
542             if (lwp->lwp_curinfo) {
543                 kmem_free((caddr_t)lwp->lwp_curinfo, sizeof(*lwp->lwp_curinfo));
544                 lwp->lwp_curinfo = NULL;
545             }
546         }
547
548         if (code) {
549             break;
550         }
551
552         /*
553          * Ignore non-data message types
554          */
555         if (type != T_DATA) {
556             continue;
557         }
558
559         /*
560          * Save the source address
561          */
562         bcopy(udreq->addr.buf, (char *)addr, sizeof(struct sockaddr_in));
563
564         /*
565          * Copy out the message buffers, take care not to overflow
566          * the I/O vector.
567          */
568         dbp = udreq->udata.udata_mp;
569         length = *alength;
570         for (i = 0 ; dbp != NULL && length > 0 && i < nvecs ; i++) {
571             tlen = dvec[i].iov_len;
572             tbase = dvec[i].iov_base;
573             if (tlen > length) {
574                 tlen = length;
575             }
576             while (dbp != NULL && tlen > 0) {
577                 blen = dbp->b_wptr - dbp->b_rptr;
578                 if (blen > tlen) {
579                     bcopy((char *)dbp->b_rptr, tbase, tlen);
580                     length -= tlen;
581                     dbp->b_rptr += tlen;
582                     tlen = 0;
583                 } else {
584                     bcopy((char *)dbp->b_rptr, tbase, blen);
585                     length -= blen;
586                     tlen -= blen;
587                     tbase += blen;
588                     dbp = dbp->b_cont;
589                 }
590             }
591         }
592         *alength = *alength - length;
593         break;
594     }
595
596     t_kfree(udp_tiptr, (caddr_t)udreq, T_UNITDATA);
597     return code;
598 }
599
600
601 void osi_StopListener(void)
602 {
603     osi_FreeSocket(rx_socket);
604 }
605
606
607 void shutdown_rxkernel(void)
608 {
609 }
610
611
612 #endif /* AFS_SUN56_ENV */
613 #endif /* AFS_SUN5_ENV */