home *** CD-ROM | disk | FTP | other *** search
- /* Application programming interface routines - based loosely on the
- * "socket" model in Berkeley UNIX.
- *
- * Copyright 1991 Phil Karn, KA9Q
- */
- #include <stdio.h>
- #ifdef __STDC__
- #include <stdarg.h>
- #endif
- #include "global.h"
- #include "mbuf.h"
- #include "netuser.h"
- #include "timer.h"
- #include "iface.h"
- #include "ip.h"
- #include "tcp.h"
- #include "udp.h"
- #include "ax25.h"
- #include "lapb.h"
- #include "netrom.h"
- #include "nr4.h"
- #include "proc.h"
- #include "lzw.h"
- #include "usock.h"
- #include "socket.h"
- #include "config.h"
-
- static void autobind __ARGS((int s,int af));
- static int checkaddr __ARGS((int type,char *name,int namelen));
- static void rip_recv __ARGS((struct raw_ip *rp));
- static void s_trcall __ARGS((struct tcb *tcb,int cnt));
- static void s_tscall __ARGS((struct tcb *tcb,int old,int new));
- static void s_ttcall __ARGS((struct tcb *tcb,int cnt));
- static void s_urcall __ARGS((struct iface *iface,struct udp_cb *udp,int cnt));
- static void trdiscard __ARGS((struct tcb *tcb,int cnt));
- #ifdef NETROM
- static void s_nrcall __ARGS((struct nr4cb *cb,int cnt));
- static void s_nscall __ARGS((struct nr4cb *cb,int old,int new));
- static void s_ntcall __ARGS((struct nr4cb *cb,int cnt));
- #endif
-
- static int16 Lport = 1024;
-
- char *Socktypes[] = {
- "Not Used",
- "TCP",
- "UDP",
- "AX25 I",
- "AX25 UI",
- "Raw IP",
- "NETROM3",
- "NETROM",
- "Loc St",
- "Loc Dg"
- };
- char Badsocket[] = "Bad socket";
- struct usock *Usock; /* Socket entry array */
- int Nusock = DEFNSOCK; /* Number of socket entries */
-
- /* The following two variables are needed because there can be only one
- * socket listening on each of the AX.25 modes (I and UI)
- */
- #ifdef AX25
- int Axi_sock = -1; /* Socket number listening for AX25 connections */
- static int Axui_sock = -1; /* Socket number listening for AX25 UI frames */
- static struct mbuf *Bcq; /* Queue of incoming UI frames */
-
- /* Function that handles incoming UI frames from lapb.c */
- void
- beac_input(iface,src,bp)
- struct iface *iface;
- char *src;
- struct mbuf *bp;
- {
- struct mbuf *hdr;
- struct sockaddr_ax *sax;
-
- if(Axui_sock == -1){
- /* Nobody there to read it */
- free_p(bp);
- } else {
- if((hdr = pushdown(NULLBUF,sizeof(struct sockaddr_ax))) == NULLBUF){
- free_p(bp);
- return;
- }
- sax = (struct sockaddr_ax *)hdr->data;
- sax->sax_family = AF_AX25;
- memcpy(sax->ax25_addr,src,AXALEN);
- strncpy(sax->iface,iface->name,ILEN);
- hdr->next = bp;
- enqueue(&Bcq,hdr);
- }
- }
- #endif
-
- /* Initialize user socket array */
- void
- sockinit()
- {
- if(Usock != NULLUSOCK)
- return; /* Already initialized */
- Usock = (struct usock *)callocw(Nusock,sizeof(struct usock));
- }
-
- /* Create a user socket, return socket index
- * The mapping to actual protocols is as follows:
- *
- *
- * ADDRESS FAMILY Stream Datagram Raw Seq. Packet
- *
- * AF_INET TCP UDP IP
- * AF_AX25 I-frames UI-frames
- * AF_NETROM NET/ROM L3 NET/ROM L4
- * AF_LOCAL stream loopback packet loopback
- */
- int
- socket(af,type,protocol)
- int af; /* Address family */
- int type; /* Stream or datagram */
- int protocol; /* Used for raw IP sockets */
- {
- register struct usock *up;
- int s;
-
- for(up=Usock;up < &Usock[Nusock];up++)
- if(up->type == NOTUSED)
- break;
-
- if(up == &Usock[Nusock]){
- /* None left */
- errno = EMFILE;
- return -1;
- }
- up->refcnt = 1;
- s = up - Usock + SOCKBASE;
- errno = 0;
- up->noblock = 0;
- up->rdysock = -1;
- up->cb.p = NULLCHAR;
- up->peername = up->name = NULLCHAR;
- up->namelen = up->peernamelen = 0;
- up->owner = Curproc;
- up->obuf = NULLBUF;
- memset(up->errcodes,0,sizeof(up->errcodes));
- memset(up->eol,0,sizeof(up->eol));
- up->flush = '\n'; /* default is line buffered */
- switch(af){
- case AF_LOCAL:
- up->cb.local = (struct loc *) callocw(1,sizeof(struct loc));
- up->cb.local->peer = up; /* connect to self */
- switch(type){
- case SOCK_STREAM:
- up->type = TYPE_LOCAL_STREAM;
- up->cb.local->hiwat = LOCSFLOW;
- break;
- case SOCK_DGRAM:
- up->type = TYPE_LOCAL_DGRAM;
- up->cb.local->hiwat = LOCDFLOW;
- break;
- default:
- free(up->cb.local);
- errno = ESOCKTNOSUPPORT;
- break;
- }
- break;
- #ifdef AX25
- case AF_AX25:
- switch(type){
- case SOCK_STREAM:
- up->type = TYPE_AX25I;
- break;
- case SOCK_DGRAM:
- up->type = TYPE_AX25UI;
- break;
- default:
- errno = ESOCKTNOSUPPORT;
- break;
- }
- strcpy(up->eol,AX_EOL);
- break;
- #endif
- #ifdef NETROM
- case AF_NETROM:
- switch(type){
- case SOCK_RAW:
- up->type = TYPE_NETROML3;
- up->cb.rnr = raw_nr((char)protocol);
- break;
- case SOCK_SEQPACKET:
- up->type = TYPE_NETROML4;
- break;
- default:
- errno = ESOCKTNOSUPPORT;
- break;
- }
- strcpy(up->eol,AX_EOL);
- break;
- #endif
- case AF_INET:
- switch(type){
- case SOCK_STREAM:
- up->type = TYPE_TCP;
- strcpy(up->eol,INET_EOL);
- break;
- case SOCK_DGRAM:
- up->type = TYPE_UDP;
- break;
- case SOCK_RAW:
- up->type = TYPE_RAW;
- up->cb.rip = raw_ip(protocol,rip_recv);
- up->cb.rip->user = s;
- break;
- default:
- errno = ESOCKTNOSUPPORT;
- break;
- }
- break;
- default:
- errno = EAFNOSUPPORT;
- break;
- }
- if(errno)
- return -1;
-
- return s;
- }
-
- /* Attach a local address/port to a socket. If not issued before a connect
- * or listen, will be issued automatically
- */
- int
- bind(s,name,namelen)
- int s; /* Socket index */
- char *name; /* Local name */
- int namelen; /* Length of name */
- {
- register struct usock *up;
- union sp local;
- struct socket lsock;
-
- if((up = itop(s)) == NULLUSOCK){
- errno = EBADF;
- return -1;
- }
- if(up->type == TYPE_LOCAL_STREAM || up->type == TYPE_LOCAL_DGRAM){
- errno = EINVAL;
- return -1;
- }
- if(name == NULLCHAR){
- errno = EFAULT;
- return -1;
- }
- if(up->name != NULLCHAR){
- /* Bind has already been issued */
- errno = EINVAL;
- return -1;
- }
- if(checkaddr(up->type,name,namelen) == -1){
- /* Incorrect length or family for chosen protocol */
- errno = EAFNOSUPPORT;
- return -1;
- }
- /* Stash name in an allocated block */
- up->namelen = namelen;
- up->name = mallocw(namelen);
- memcpy(up->name,name,namelen);
- /* Create control block for datagram sockets */
- switch(up->type){
- case TYPE_UDP:
- local.in = (struct sockaddr_in *)up->name;
- lsock.address = local.in->sin_addr.s_addr;
- lsock.port = local.in->sin_port;
- up->cb.udp = open_udp(&lsock,s_urcall);
- up->cb.udp->user = s;
- break;
- #ifdef AX25
- case TYPE_AX25UI:
- if(Axui_sock != -1){
- errno = EADDRINUSE;
- return -1;
- }
- Axui_sock = s;
- break;
- #endif
- }
- return 0;
- }
- /* Post a listen on a socket */
- int
- listen(s,backlog)
- int s; /* Socket index */
- int backlog; /* 0 for a single connection, 1 for multiple connections */
- {
- register struct usock *up;
- union sp local;
- struct socket lsock;
-
- if((up = itop(s)) == NULLUSOCK){
- errno = EBADF;
- return -1;
- }
- if(up->type == TYPE_LOCAL_STREAM || up->type == TYPE_LOCAL_DGRAM){
- errno = EINVAL;
- return -1;
- }
- if(up->cb.p != NULLCHAR){
- errno = EISCONN;
- return -1;
- }
- switch(up->type){
- case TYPE_TCP:
- if(up->name == NULLCHAR)
- autobind(s,AF_INET);
-
- local.in = (struct sockaddr_in *)up->name;
- lsock.address = local.in->sin_addr.s_addr;
- lsock.port = local.in->sin_port;
- up->cb.tcb = open_tcp(&lsock,NULLSOCK,
- backlog ? TCP_SERVER:TCP_PASSIVE,0,
- s_trcall,s_ttcall,s_tscall,0,s);
- break;
- #ifdef AX25
- case TYPE_AX25I:
- if(up->name == NULLCHAR)
- autobind(s,AF_AX25);
- if(s != Axi_sock){
- errno = EOPNOTSUPP;
- return -1;
- }
- local.ax = (struct sockaddr_ax *)up->name;
- up->cb.ax25 = open_ax25(NULLIF,local.ax->ax25_addr,NULLCHAR,
- backlog ? AX_SERVER:AX_PASSIVE,0,
- s_arcall,s_atcall,s_ascall,s);
- break;
- #endif
- #ifdef NETROM
- case TYPE_NETROML4:
- if(up->name == NULLCHAR)
- autobind(s,AF_NETROM);
- local.nr = (struct sockaddr_nr *)up->name;
- up->cb.nr4 = open_nr4(&local.nr->nr_addr,NULLNRADDR,
- backlog ? AX_SERVER:AX_PASSIVE,
- s_nrcall,s_ntcall,s_nscall,s);
- break;
- #endif
- default:
- /* Listen not supported on datagram sockets */
- errno = EOPNOTSUPP;
- return -1;
- }
- return 0;
- }
- /* Initiate active open. For datagram sockets, merely bind the remote address. */
- int
- connect(s,peername,peernamelen)
- int s; /* Socket index */
- char *peername; /* Peer name */
- int peernamelen; /* Length of peer name */
- {
- register struct usock *up;
- union cb cb;
- union sp local,remote;
- struct socket lsock,fsock;
- #ifdef AX25
- struct iface *iface;
- #endif
-
- if((up = itop(s)) == NULLUSOCK){
- errno = EBADF;
- return -1;
- }
- if(up->type == TYPE_LOCAL_DGRAM || up->type == TYPE_LOCAL_STREAM){
- errno = EINVAL;
- return -1;
- }
- if(peername == NULLCHAR){
- /* Connect must specify a remote address */
- errno = EFAULT;
- return -1;
- }
- if(checkaddr(up->type,peername,peernamelen) == -1){
- errno = EAFNOSUPPORT;
- return -1;
- }
- /* Raw socket control blocks are created in socket() */
- if(up->type != TYPE_RAW && up->type != TYPE_NETROML3 &&
- up->cb.p != NULLCHAR){
- errno = EISCONN;
- return -1;
- }
- up->peername = mallocw(peernamelen);
- memcpy(up->peername,peername,peernamelen);
- up->peernamelen = peernamelen;
-
- /* Set up the local socket structures */
- if(up->name == NULLCHAR){
- switch(up->type){
- case TYPE_TCP:
- case TYPE_UDP:
- case TYPE_RAW:
- autobind(s,AF_INET);
- break;
- #ifdef AX25
- case TYPE_AX25I:
- case TYPE_AX25UI:
- autobind(s,AF_AX25);
- break;
- #endif
- #ifdef NETROM
- case TYPE_NETROML3:
- case TYPE_NETROML4:
- autobind(s,AF_NETROM);
- break;
- #endif
- }
- }
- switch(up->type){
- case TYPE_TCP:
- /* Construct the TCP-style ports from the sockaddr structs */
- local.in = (struct sockaddr_in *)up->name;
- remote.in = (struct sockaddr_in *)up->peername;
-
- if(local.in->sin_addr.s_addr == INADDR_ANY)
- /* Choose a local address */
- local.in->sin_addr.s_addr =
- locaddr(remote.in->sin_addr.s_addr);
-
- lsock.address = local.in->sin_addr.s_addr;
- lsock.port = local.in->sin_port;
- fsock.address = remote.in->sin_addr.s_addr;
- fsock.port = remote.in->sin_port;
-
- /* Open the TCB in active mode */
- up->cb.tcb = open_tcp(&lsock,&fsock,TCP_ACTIVE,0,
- s_trcall,s_ttcall,s_tscall,0,s);
-
- /* Wait for the connection to complete */
- while((cb.tcb = up->cb.tcb) != NULLTCB && cb.tcb->state != TCP_ESTABLISHED){
- if(up->noblock){
- errno = EWOULDBLOCK;
- return -1;
- } else if((errno = pwait(up)) != 0){
- return -1;
- }
- }
- if(cb.tcb == NULLTCB){
- /* Probably got refused */
- free(up->peername);
- up->peername = NULLCHAR;
- errno = ECONNREFUSED;
- return -1;
- }
- break;
- case TYPE_UDP:
- #ifdef AX25
- case TYPE_AX25UI:
- #endif
- #ifdef NETROM
- case TYPE_NETROML3:
- #endif
- case TYPE_RAW:
- /* Control block already created by bind() */
- break;
- #ifdef AX25
- case TYPE_AX25I:
- local.ax = (struct sockaddr_ax *)up->name;
- remote.ax = (struct sockaddr_ax *)up->peername;
- if((iface = if_lookup(remote.ax->iface)) == NULLIF){
- errno = EINVAL;
- return -1;
- }
- if(local.ax->ax25_addr[0] == '\0'){
- /* The local address was unspecified; set it from
- * the interface address
- */
- memcpy(local.ax->ax25_addr,iface->hwaddr,AXALEN);
- }
- /* If we already have an AX25 link we can use it */
- if((up->cb.ax25 = find_ax25(remote.ax->ax25_addr)) != NULLAX25
- && up->cb.ax25->state != LAPB_DISCONNECTED &&
- up->cb.ax25->user == -1) {
- up->cb.ax25->user = s;
- up->cb.ax25->r_upcall = s_arcall;
- up->cb.ax25->t_upcall = s_atcall;
- up->cb.ax25->s_upcall = s_ascall;
- if(up->cb.ax25->state == LAPB_CONNECTED
- || up->cb.ax25->state == LAPB_RECOVERY)
- return 0;
- } else
- up->cb.ax25 = open_ax25(iface,local.ax->ax25_addr,
- remote.ax->ax25_addr,AX_ACTIVE,
- Axwindow,s_arcall,s_atcall,s_ascall,s);
-
- /* Wait for the connection to complete */
- while((cb.ax25 = up->cb.ax25) != NULLAX25 && cb.ax25->state != LAPB_CONNECTED){
- if(up->noblock){
- errno = EWOULDBLOCK;
- return -1;
- } else if((errno = pwait(up)) != 0){
- return -1;
- }
- }
- if(cb.ax25 == NULLAX25){
- /* Connection probably already exists */
- free(up->peername);
- up->peername = NULLCHAR;
- errno = ECONNREFUSED;
- return -1;
- }
- break;
- #endif
- #ifdef NETROM
- case TYPE_NETROML4:
- local.nr = (struct sockaddr_nr *)up->name;
- remote.nr = (struct sockaddr_nr *)up->peername;
- up->cb.nr4 = open_nr4(&local.nr->nr_addr,&remote.nr->nr_addr,
- AX_ACTIVE,s_nrcall,s_ntcall,s_nscall,s);
-
- /* Wait for the connection to complete */
- while((cb.nr4 = up->cb.nr4) != NULLNR4CB && cb.nr4->state != NR4STCON){
- if(up->noblock){
- errno = EWOULDBLOCK;
- return -1;
- } else if((errno = pwait(up)) != 0){
- return -1;
- }
- }
- if(cb.nr4 == NULLNR4CB){
- /* Connection probably already exists */
- free(up->peername);
- up->peername = NULLCHAR;
- errno = ECONNREFUSED;
- return -1;
- }
- break;
- #endif
- }
- return 0;
- }
- /* Wait for a connection. Valid only for connection-oriented sockets. */
- int
- accept(s,peername,peernamelen)
- int s; /* Socket index */
- char *peername; /* Peer name */
- int *peernamelen; /* Length of peer name */
- {
- int i;
- register struct usock *up;
-
- if((up = itop(s)) == NULLUSOCK){
- errno = EBADF;
- return -1;
- }
- if(up->type == TYPE_LOCAL_DGRAM || up->type == TYPE_LOCAL_STREAM){
- errno = EINVAL;
- return -1;
- }
- if(up->cb.p == NULLCHAR){
- errno = EOPNOTSUPP;
- return -1;
- }
- /* Accept is valid only for stream sockets */
- switch(up->type){
- case TYPE_TCP:
- #ifdef AX25
- case TYPE_AX25I:
- #endif
- #ifdef NETROM
- case TYPE_NETROML4:
- #endif
- break;
- default:
- errno = EOPNOTSUPP;
- return -1;
- }
- /* Wait for the state-change upcall routine to signal us */
- while(up->cb.p != NULLCHAR && up->rdysock == -1){
- if(up->noblock){
- errno = EWOULDBLOCK;
- return -1;
- } else if((errno = pwait(up)) != 0){
- return -1;
- }
- }
- if(up->cb.p == NULLCHAR){
- /* Blown away */
- errno = EBADF;
- return -1;
- }
- i = up->rdysock;
- up->rdysock = -1;
-
- up = itop(i);
- if(peername != NULLCHAR && peernamelen != NULL){
- *peernamelen = min(up->peernamelen,*peernamelen);
- memcpy(peername,up->peername,*peernamelen);
- }
- return i;
- }
- /* Low-level receive routine. Passes mbuf back to user; more efficient than
- * higher-level functions recv() and recvfrom(). Datagram sockets ignore
- * the len parameter.
- */
- int
- recv_mbuf(s,bpp,flags,from,fromlen)
- int s; /* Socket index */
- struct mbuf **bpp; /* Place to stash receive buffer */
- int flags; /* Unused; will control out-of-band data, etc */
- char *from; /* Peer address (only for datagrams) */
- int *fromlen; /* Length of peer address */
- {
- register struct usock *up;
- int cnt;
- union cb cb;
- struct socket fsocket;
- #ifdef NETROM
- struct nr3hdr n3hdr;
- #endif
- union sp remote;
- struct ip ip;
- struct mbuf *bp;
-
- if((up = itop(s)) == NULLUSOCK){
- errno = EBADF;
- return -1;
- }
- if(up->ibuf != NULLBUF){
- /* Return input buffer */
- cnt = len_p(up->ibuf);
- if(bpp != NULLBUFP)
- *bpp = up->ibuf;
- else
- free_p(up->ibuf);
- up->ibuf = NULLBUF;
- return cnt;
- }
- switch(up->type){
- case TYPE_LOCAL_STREAM:
- case TYPE_LOCAL_DGRAM:
- while(up->cb.local != NULLLOC && up->cb.local->q == NULLBUF
- && up->cb.local->peer != NULLUSOCK){
- if(up->noblock){
- errno = EWOULDBLOCK;
- return -1;
- } else if((errno = pwait(up)) != 0){
- return -1;
- }
- }
- if(up->cb.local == NULLLOC){
- errno = EBADF;
- return -1;
- }
- if(up->cb.local->q == NULLBUF &&
- up->cb.local->peer == NULLUSOCK){
- errno = ENOTCONN;
- return -1;
- }
- /* For datagram sockets, this will return the
- * first packet on the queue. For stream sockets,
- * this will return everything.
- */
- bp = dequeue(&up->cb.local->q);
- if(up->cb.local->q == NULLBUF
- && (up->cb.local->flags & LOC_SHUTDOWN))
- close_s(s);
- psignal(up,0);
- cnt = len_p(bp);
- break;
- case TYPE_TCP:
- while((cb.tcb = up->cb.tcb) != NULLTCB
- && cb.tcb->r_upcall != trdiscard
- && (cnt = recv_tcp(cb.tcb,&bp,(int16)0)) == -1){
- if(up->noblock){
- errno = EWOULDBLOCK;
- return -1;
- } else if((errno = pwait(up)) != 0){
- return -1;
- }
- }
- if(cb.tcb == NULLTCB){
- /* Connection went away */
- errno = ENOTCONN;
- return -1;
- } else if(cb.tcb->r_upcall == trdiscard){
- /* Receive shutdown has been done */
- errno = ENOTCONN; /* CHANGE */
- return -1;
- }
- break;
- case TYPE_UDP:
- while((cb.udp = up->cb.udp) != NULLUDP
- && (cnt = recv_udp(cb.udp,&fsocket,&bp)) == -1){
- if(up->noblock){
- errno = EWOULDBLOCK;
- return -1;
- } else if((errno = pwait(up)) != 0){
- return -1;
- }
- }
- if(cb.udp == NULLUDP){
- /* Connection went away */
- errno = ENOTCONN;
- return -1;
- }
- if(from != NULLCHAR && fromlen != (int *)NULL && *fromlen >= SOCKSIZE){
- remote.in = (struct sockaddr_in *)from;
- remote.in->sin_family = AF_INET;
- remote.in->sin_addr.s_addr = fsocket.address;
- remote.in->sin_port = fsocket.port;
- *fromlen = SOCKSIZE;
- }
- break;
- case TYPE_RAW:
- while((cb.rip = up->cb.rip) != NULLRIP
- && cb.rip->rcvq == NULLBUF){
- if(up->noblock){
- errno = EWOULDBLOCK;
- return -1;
- } else if((errno = pwait(up)) != 0){
- return -1;
- }
- }
- if(cb.rip == NULLRIP){
- /* Connection went away */
- errno = ENOTCONN;
- return -1;
- }
- bp = dequeue(&cb.rip->rcvq);
- ntohip(&ip,&bp);
-
- cnt = len_p(bp);
- if(from != NULLCHAR && fromlen != (int *)NULL && *fromlen >= SOCKSIZE){
- remote.in = (struct sockaddr_in *)from;
- remote.in->sin_family = AF_INET;
- remote.in->sin_addr.s_addr = ip.source;
- remote.in->sin_port = 0;
- *fromlen = SOCKSIZE;
- }
- break;
- #ifdef AX25
- case TYPE_AX25I:
- while((cb.ax25 = up->cb.ax25) != NULLAX25
- && (bp = recv_ax25(cb.ax25,(int16)0)) == NULLBUF){
- if(up->noblock){
- errno = EWOULDBLOCK;
- return -1;
- } else if((errno = pwait(up)) != 0){
- return -1;
- }
- }
- if(cb.ax25 == NULLAX25){
- /* Connection went away */
- errno = ENOTCONN;
- return -1;
- }
- cnt = bp->cnt;
- break;
- case TYPE_AX25UI:
- while(s == Axui_sock && Bcq == NULLBUF){
- if(up->noblock){
- errno = EWOULDBLOCK;
- return -1;
- } else if((errno = pwait(&Bcq)) != 0){
- return -1;
- }
- }
- if(s != Axui_sock){
- errno = ENOTCONN;
- return -1;
- }
- bp = dequeue(&Bcq);
-
- if(from != NULLCHAR && fromlen != NULLINT
- && *fromlen >= sizeof(struct sockaddr_ax)){
- pullup(&bp,from,sizeof(struct sockaddr_ax));
- *fromlen = sizeof(struct sockaddr_ax);
- } else {
- pullup(&bp,NULLCHAR,sizeof(struct sockaddr_ax));
- }
- cnt = len_p(bp);
- break;
- #endif
- #ifdef NETROM
- case TYPE_NETROML3:
- while((cb.rnr = up->cb.rnr) != NULLRNR
- && cb.rnr->rcvq == NULLBUF){
- if(up->noblock){
- errno = EWOULDBLOCK;
- return -1;
- } else if((errno = pwait(up)) != 0){
- return -1;
- }
- }
- if(cb.rnr == NULLRNR){
- /* Connection went away */
- errno = ENOTCONN;
- return -1;
- }
- bp = dequeue(&cb.rnr->rcvq);
- ntohnr3(&n3hdr,&bp);
- cnt = len_p(bp);
- if(from != NULLCHAR && fromlen != NULLINT
- && *fromlen >= sizeof(struct sockaddr_nr)){
- remote.nr = (struct sockaddr_nr *)from;
- remote.nr->nr_family = AF_NETROM;
- /* The callsign of the local user is not part of
- NET/ROM level 3, so that field is not used here */
- memcpy(remote.nr->nr_addr.node,n3hdr.source,AXALEN);
- *fromlen = sizeof(struct sockaddr_nr);
- }
- break;
- case TYPE_NETROML4:
- while((cb.nr4 = up->cb.nr4) != NULLNR4CB
- && (bp = recv_nr4(cb.nr4,(int16)0)) == NULLBUF){
- if(up->noblock){
- errno = EWOULDBLOCK;
- return -1;
- } else if((errno = pwait(up)) != 0){
- return -1;
- }
- }
- if(cb.nr4 == NULLNR4CB){
- /* Connection went away */
- errno = ENOTCONN;
- return -1;
- }
- cnt = bp->cnt;
- break;
- #endif
- }
- if(bpp != NULLBUFP)
- *bpp = bp;
- else
- free_p(bp);
- return cnt;
- }
- /* Low level send routine; user supplies mbuf for transmission. More
- * efficient than send() or sendto(), the higher level interfaces.
- * The "to" and "tolen" parameters are ignored on connection-oriented
- * sockets.
- *
- * In case of error, bp is freed so the caller doesn't have to worry about it.
- */
- int
- send_mbuf(s,bp,flags,to,tolen)
- int s; /* Socket index */
- struct mbuf *bp; /* Buffer to send */
- int flags; /* not currently used */
- char *to; /* Destination, only for datagrams */
- int tolen; /* Length of destination */
- {
- register struct usock *up;
- union cb cb;
- union sp local,remote;
- struct socket lsock,fsock;
- int cnt;
-
- if((up = itop(s)) == NULLUSOCK){
- free_p(bp);
- errno = EBADF;
- return -1;
- }
- #ifndef notdef
- if(up->obuf != NULLBUF){
- /* If there's unflushed output, send it.
- * Note the importance of clearing up->obuf
- * before the recursive call!
- */
- struct mbuf *bp1;
-
- bp1 = up->obuf;
- up->obuf = NULLBUF;
- send_mbuf(s,bp1,flags,to,tolen);
- }
- #endif
- if(up->name == NULLCHAR){
- /* Automatic local name assignment for datagram sockets */
- switch(up->type){
- case TYPE_LOCAL_STREAM:
- case TYPE_LOCAL_DGRAM:
- break; /* no op */
- case TYPE_UDP:
- case TYPE_RAW:
- autobind(s,AF_INET);
- break;
- #ifdef AX25
- case TYPE_AX25UI:
- autobind(s,AF_AX25);
- break;
- #endif
- #ifdef NETROM
- case TYPE_NETROML3:
- case TYPE_NETROML4:
- autobind(s,AF_NETROM);
- break;
- #endif
- default:
- free_p(bp);
- errno = ENOTCONN;
- return -1;
- }
- }
- cnt = len_p(bp);
- switch(up->type){
- case TYPE_LOCAL_DGRAM:
- if(up->cb.local->peer == NULLUSOCK){
- free_p(bp);
- errno = ENOTCONN;
- return -1;
- }
- enqueue(&up->cb.local->peer->cb.local->q,bp);
- psignal(up->cb.local->peer,0);
- /* If high water mark has been reached, block */
- while(up->cb.local->peer != NULLUSOCK &&
- len_q(up->cb.local->peer->cb.local->q) >=
- up->cb.local->peer->cb.local->hiwat){
- if(up->noblock){
- errno = EWOULDBLOCK;
- return -1;
- } else if((errno = pwait(up->cb.local->peer)) != 0){
- return -1;
- }
- }
- if(up->cb.local->peer == NULLUSOCK){
- errno = ENOTCONN;
- return -1;
- }
- break;
- case TYPE_LOCAL_STREAM:
- if(up->cb.local->peer == NULLUSOCK){
- free_p(bp);
- errno = ENOTCONN;
- return -1;
- }
- append(&up->cb.local->peer->cb.local->q,bp);
- psignal(up->cb.local->peer,0);
- /* If high water mark has been reached, block */
- while(up->cb.local->peer != NULLUSOCK &&
- len_p(up->cb.local->peer->cb.local->q) >=
- up->cb.local->peer->cb.local->hiwat){
- if(up->noblock){
- errno = EWOULDBLOCK;
- return -1;
- } else if((errno = pwait(up->cb.local->peer)) != 0){
- return -1;
- }
- }
- if(up->cb.local->peer == NULLUSOCK){
- errno = ENOTCONN;
- return -1;
- }
- break;
- case TYPE_TCP:
- if((cb.tcb = up->cb.tcb) == NULLTCB){
- free_p(bp);
- errno = ENOTCONN;
- return -1;
- }
- cnt = send_tcp(cb.tcb,bp);
-
- while((cb.tcb = up->cb.tcb) != NULLTCB &&
- cb.tcb->sndcnt > cb.tcb->window){
- /* Send queue is full */
- if(up->noblock){
- errno = EWOULDBLOCK;
- return -1;
- } else if((errno = pwait(up)) != 0){
- return -1;
- }
- }
- if(cb.tcb == NULLTCB){
- errno = ENOTCONN;
- return -1;
- }
- break;
- case TYPE_UDP:
- local.in = (struct sockaddr_in *)up->name;
- lsock.address = local.in->sin_addr.s_addr;
- lsock.port = local.in->sin_port;
- if(to != NULLCHAR)
- remote.in = (struct sockaddr_in *)to;
- else if(up->peername != NULLCHAR)
- remote.in = (struct sockaddr_in *)up->peername;
- else {
- errno = ENOTCONN;
- return -1;
- }
- fsock.address = remote.in->sin_addr.s_addr;
- fsock.port = remote.in->sin_port;
- send_udp(&lsock,&fsock,0,0,bp,0,0,0);
- break;
- case TYPE_RAW:
- local.in = (struct sockaddr_in *)up->name;
- if(to != NULLCHAR)
- remote.in = (struct sockaddr_in *)to;
- else if(up->peername != NULLCHAR)
- remote.in = (struct sockaddr_in *)up->peername;
- else {
- errno = ENOTCONN;
- return -1;
- }
- ip_send(local.in->sin_addr.s_addr,remote.in->sin_addr.s_addr,
- (char)up->cb.rip->protocol,0,0,bp,0,0,0);
- break;
- #ifdef AX25
- case TYPE_AX25I:
- if((cb.ax25 = up->cb.ax25) == NULLAX25){
- free_p(bp);
- errno = ENOTCONN;
- return -1;
- }
- send_ax25(cb.ax25,bp,PID_NO_L3);
-
- while((cb.ax25 = up->cb.ax25) != NULLAX25 &&
- len_q(cb.ax25->txq) * cb.ax25->paclen > cb.ax25->window){
- if(up->noblock){
- errno = EWOULDBLOCK;
- return -1;
- } else if((errno = pwait(up)) != 0){
- return -1;
- }
- }
- if(cb.ax25 == NULLAX25){
- errno = EBADF;
- return -1;
- }
- break;
- case TYPE_AX25UI:
- local.ax = (struct sockaddr_ax *)up->name;
- if(to != NULLCHAR)
- remote.ax = (struct sockaddr_ax *)to;
- else if(up->peername != NULLCHAR)
- remote.ax = (struct sockaddr_ax *)up->peername;
- else {
- errno = ENOTCONN;
- return -1;
- }
- ax_output(if_lookup(remote.ax->iface),
- remote.ax->ax25_addr,
- local.ax->ax25_addr,PID_NO_L3,bp);
- break;
- #endif
- #ifdef NETROM
- case TYPE_NETROML3:
- if(len_p(bp) > NR4MAXINFO) {
- free_p(bp);
- errno = EMSGSIZE;
- return -1;
- }
- local.nr = (struct sockaddr_nr *)up->name;
- if(to != NULLCHAR)
- remote.nr = (struct sockaddr_nr *)to;
- else if(up->peername != NULLCHAR)
- remote.nr = (struct sockaddr_nr *)up->peername;
- else {
- errno = ENOTCONN;
- return -1;
- }
- /* The NETROM username is always ignored in outgoing traffic */
- nr_sendraw(remote.nr->nr_addr.node,
- up->cb.rnr->protocol,up->cb.rnr->protocol,bp);
- break;
- case TYPE_NETROML4:
- if((cb.nr4 = up->cb.nr4) == NULLNR4CB) {
- free_p(bp);
- errno = ENOTCONN;
- return -1;
- }
- if(len_p(bp) > NR4MAXINFO){ /* reject big packets */
- free_p(bp);
- errno = EMSGSIZE;
- return -1;
- }
- send_nr4(cb.nr4,bp);
-
- while((cb.nr4 = up->cb.nr4) != NULLNR4CB &&
- cb.nr4->nbuffered >= cb.nr4->window){
- if(up->noblock){
- errno = EWOULDBLOCK;
- return -1;
- } else if((errno = pwait(up)) != 0){
- errno = EINTR;
- return -1;
- }
- }
- if(cb.nr4 == NULLNR4CB){
- errno = EBADF;
- return -1;
- }
- break;
- #endif
- }
- return cnt;
- }
- /* Return local name passed in an earlier bind() call */
- int
- getsockname(s,name,namelen)
- int s; /* Socket index */
- char *name; /* Place to stash name */
- int *namelen; /* Length of same */
- {
- register struct usock *up;
-
- if((up = itop(s)) == NULLUSOCK){
- errno = EBADF;
- return -1;
- }
- if(name == NULLCHAR || namelen == (int *)NULL){
- errno = EFAULT;
- return -1;
- }
- if(up->name == NULLCHAR){
- /* Not bound yet */
- *namelen = 0;
- return 0;
- }
- if(up->name != NULLCHAR){
- *namelen = min(*namelen,up->namelen);
- memcpy(name,up->name,*namelen);
- }
- return 0;
- }
- /* Get remote name, returning result of earlier connect() call. */
- int
- getpeername(s,peername,peernamelen)
- int s; /* Socket index */
- char *peername; /* Place to stash name */
- int *peernamelen; /* Length of same */
- {
- register struct usock *up;
-
- if((up = itop(s)) == NULLUSOCK){
- errno = EBADF;
- return -1;
- }
- if(up->peername == NULLCHAR){
- errno = ENOTCONN;
- return -1;
- }
- if(peername == NULLCHAR || peernamelen == (int *)NULL){
- errno = EFAULT;
- return -1;
- }
- *peernamelen = min(*peernamelen,up->peernamelen);
- memcpy(peername,up->peername,*peernamelen);
- return 0;
- }
- /* Return length of protocol queue, either send or receive. */
- int
- socklen(s,rtx)
- int s; /* Socket index */
- int rtx; /* 0 = receive queue, 1 = transmit queue */
- {
- register struct usock *up;
- int len = -1;
-
- if((up = itop(s)) == NULLUSOCK){
- errno = EBADF;
- return -1;
- }
- if(up->cb.p == NULLCHAR){
- errno = ENOTCONN;
- return -1;
- }
- if(rtx < 0 || rtx > 1){
- errno = EINVAL;
- return -1;
- }
- switch(up->type){
- case TYPE_LOCAL_DGRAM:
- switch(rtx){
- case 0:
- len = len_q(up->cb.local->q);
- break;
- case 1:
- if(up->cb.local->peer != NULLUSOCK)
- len = len_q(up->cb.local->peer->cb.local->q);
- break;
- }
- break;
- case TYPE_LOCAL_STREAM:
- switch(rtx){
- case 0:
- len = len_p(up->cb.local->q) + len_p(up->ibuf);
- break;
- case 1:
- if(up->cb.local->peer != NULLUSOCK)
- len = len_p(up->cb.local->peer->cb.local->q)
- + len_p(up->obuf);
- break;
- }
- break;
- case TYPE_TCP:
- switch(rtx){
- case 0:
- len = up->cb.tcb->rcvcnt + len_p(up->ibuf);
- break;
- case 1:
- len = up->cb.tcb->sndcnt + len_p(up->obuf);
- break;
- }
- break;
- case TYPE_UDP:
- switch(rtx){
- case 0:
- len = up->cb.udp->rcvcnt;
- break;
- case 1:
- len = 0;
- break;
- }
- break;
- #ifdef AX25
- case TYPE_AX25I:
- switch(rtx){
- case 0:
- len = len_p(up->cb.ax25->rxq) + len_p(up->ibuf);
- break;
- case 1: /* Number of packets, not bytes */
- len = len_q(up->cb.ax25->txq);
- if(up->obuf != NULLBUF)
- len++;
- }
- break;
- case TYPE_AX25UI:
- switch(rtx){
- case 0:
- len = len_q(Bcq);
- break;
- case 1:
- len = 0;
- break;
- }
- break;
- #endif
- #ifdef NETROM
- case TYPE_NETROML3:
- switch(rtx){
- case 0:
- len = len_q(up->cb.rnr->rcvq);
- break;
- case 1:
- len = 0;
- }
- break;
- case TYPE_NETROML4:
- switch(rtx){
- case 0:
- len = len_p(up->cb.nr4->rxq) + len_p(up->obuf);
- break;
- case 1: /* Number of packets, not bytes */
- len = len_q(up->cb.nr4->txq);
- if(up->obuf != NULLBUF)
- len++;
- break;
- }
- break;
- #endif
- case TYPE_RAW:
- switch(rtx){
- case 0:
- len = len_q(up->cb.rip->rcvq);
- break;
- case 1:
- len = 0;
- break;
- }
- break;
- }
- return len;
- }
- /* Force retransmission. Valid only for connection-oriented sockets. */
- int
- sockkick(s)
- int s; /* Socket index */
- {
- register struct usock *up;
-
- if((up = itop(s)) == NULLUSOCK){
- errno = EBADF;
- return -1;
- }
- if(up->type == TYPE_LOCAL_STREAM || up->type == TYPE_LOCAL_DGRAM){
- errno = EINVAL;
- return -1;
- }
- if(up->cb.p == NULLCHAR){
- errno = ENOTCONN;
- return -1;
- }
- switch(up->type){
- case TYPE_TCP:
- kick_tcp(up->cb.tcb);
- break;
- #ifdef AX25
- case TYPE_AX25I:
- kick_ax25(up->cb.ax25);
- break;
- #endif
- #ifdef NETROM
- case TYPE_NETROML4:
- kick_nr4(up->cb.nr4);
- break;
- #endif
- default:
- /* Datagram sockets can't be kicked */
- errno = EOPNOTSUPP;
- return -1;
- }
- return 0;
- }
-
- /* Change owner of socket, return previous owner */
- struct proc *
- sockowner(s,newowner)
- int s; /* Socket index */
- struct proc *newowner; /* Process table address of new owner */
- {
- register struct usock *up;
- struct proc *pp;
-
- if((up = itop(s)) == NULLUSOCK){
- errno = EBADF;
- return NULLPROC;
- }
- pp = up->owner;
- if(newowner != NULLPROC)
- up->owner = newowner;
- return pp;
- }
- /* Close down a socket three ways. Type 0 means "no more receives"; this
- * replaces the incoming data upcall with a routine that discards further
- * data. Type 1 means "no more sends", and obviously corresponds to sending
- * a TCP FIN. Type 2 means "no more receives or sends". This I interpret
- * as "abort the connection".
- */
- int
- shutdown(s,how)
- int s; /* Socket index */
- int how; /* (see above) */
- {
- register struct usock *up;
-
- if((up = itop(s)) == NULLUSOCK){
- errno = EBADF;
- return -1;
- }
- if(up->cb.p == NULLCHAR){
- errno = ENOTCONN;
- return -1;
- }
- switch(up->type){
- case TYPE_LOCAL_DGRAM:
- case TYPE_LOCAL_STREAM:
- if(up->cb.local->q == NULLBUF)
- close_s(s);
- else
- up->cb.local->flags = LOC_SHUTDOWN;
- break;
- case TYPE_TCP:
- switch(how){
- case 0: /* No more receives -- replace upcall */
- up->cb.tcb->r_upcall = trdiscard;
- break;
- case 1: /* Send EOF */
- close_tcp(up->cb.tcb);
- break;
- case 2: /* Blow away TCB */
- reset_tcp(up->cb.tcb);
- up->cb.tcb = NULLTCB;
- break;
- }
- break;
- #ifdef AX25
- case TYPE_AX25UI:
- close_s(s);
- break;
- case TYPE_AX25I:
- switch(how){
- case 0:
- case 1: /* Attempt regular disconnect */
- disc_ax25(up->cb.ax25);
- break;
- case 2: /* Blow it away */
- reset_ax25(up->cb.ax25);
- up->cb.ax25 = NULLAX25;
- break;
- }
- break;
- #endif
- #ifdef NETROM
- case TYPE_NETROML3:
- close_s(s);
- break;
- case TYPE_NETROML4:
- switch(how){
- case 0:
- case 1: /* Attempt regular disconnect */
- disc_nr4(up->cb.nr4);
- break;
- case 2: /* Blow it away */
- reset_nr4(up->cb.nr4);
- up->cb.nr4 = NULLNR4CB;
- break;
- }
- break;
- #endif
- case TYPE_RAW:
- case TYPE_UDP:
- close_s(s);
- break;
- default:
- errno = EOPNOTSUPP;
- return -1;
- }
- psignal(up,0);
- return 0;
- }
- /* Close a socket, freeing it for reuse. Try to do a graceful close on a
- * TCP socket, if possible
- */
- int
- close_s(s)
- int s; /* Socket index */
- {
- register struct usock *up;
-
- if((up = itop(s)) == NULLUSOCK){
- errno = EBADF;
- return -1;
- }
- if(--up->refcnt > 0)
- return 0; /* Others are still using it */
- usflush(s);
- if(up->ibuf != NULLBUF){
- free_p(up->ibuf);
- up->ibuf = NULLBUF;
- }
- switch(up->type){
- case TYPE_LOCAL_STREAM:
- case TYPE_LOCAL_DGRAM:
- if(up->cb.local->peer != NULLUSOCK){
- up->cb.local->peer->cb.local->peer = NULLUSOCK;
- psignal(up->cb.local->peer,0);
- }
- free_q(&up->cb.local->q);
- free(up->cb.local);
- break;
- case TYPE_TCP:
- if(up->cb.tcb != NULLTCB){ /* In case it's been reset */
- up->cb.tcb->r_upcall = trdiscard;
- /* Tell the TCP_CLOSED upcall there's no more socket */
- up->cb.tcb->user = -1;
- close_tcp(up->cb.tcb);
- }
- break;
- case TYPE_UDP:
- if(up->cb.udp != NULLUDP){
- del_udp(up->cb.udp);
- }
- break;
- #ifdef AX25
- case TYPE_AX25I:
- if(up->cb.ax25 != NULLAX25){
- /* Tell the TCP_CLOSED upcall there's no more socket */
- up->cb.ax25->user = -1;
- disc_ax25(up->cb.ax25);
- }
- break;
- case TYPE_AX25UI:
- Axui_sock = -1;
- free_q(&Bcq);
- psignal(&Bcq,0); /* Unblock any reads */
- break;
- #endif
- #ifdef NETROM
- case TYPE_NETROML3:
- del_rnr(up->cb.rnr);
- break;
- case TYPE_NETROML4:
- if(up->cb.nr4 != NULLNR4CB){
- /* Tell the TCP_CLOSED upcall there's no more socket */
- up->cb.nr4->user = -1;
- disc_nr4(up->cb.nr4);
- }
- break;
- #endif
- case TYPE_RAW:
- del_ip(up->cb.rip);
- break;
- default:
- errno = EOPNOTSUPP;
- return -1;
- }
- #ifdef LZW
- if(up->zout != NULLLZW || up->zin != NULLLZW)
- lzwfree(up);
- #endif
- free(up->name);
- free(up->peername);
-
- up->cb.p = NULLCHAR;
- up->name = up->peername = NULLCHAR;
- up->type = NOTUSED;
- psignal(up,0); /* Wake up anybody doing an accept() or recv() */
- return 0;
- }
- /* Increment reference count for specified socket */
- int
- usesock(s)
- int s;
- {
- struct usock *up;
-
- if((up = itop(s)) == NULLUSOCK){
- errno = EBADF;
- return -1;
- }
- up->refcnt++;
- return 0;
- }
- /* Blow away all sockets belonging to a certain process. Used by killproc(). */
- void
- freesock(pp)
- struct proc *pp;
- {
- register struct usock *up;
- register int i;
-
- for(i=SOCKBASE;i < Nusock+SOCKBASE;i++){
- up = itop(i);
- if(up != NULLUSOCK && up->type != NOTUSED && up->owner == pp)
- shutdown(i,2);
- }
- }
- /* Start of internal subroutines */
-
- /* Raw IP receive upcall routine */
- static void
- rip_recv(rp)
- struct raw_ip *rp;
- {
- psignal(itop(rp->user),1);
- pwait(NULL);
- }
-
- /* UDP receive upcall routine */
- static void
- s_urcall(iface,udp,cnt)
- struct iface *iface;
- struct udp_cb *udp;
- int cnt;
- {
- psignal(itop(udp->user),1);
- pwait(NULL);
- }
- /* TCP receive upcall routine */
- static void
- s_trcall(tcb,cnt)
- struct tcb *tcb;
- int cnt;
- {
- /* Wake up anybody waiting for data, and let them run */
- psignal(itop(tcb->user),1);
- pwait(NULL);
- }
- /* TCP transmit upcall routine */
- static void
- s_ttcall(tcb,cnt)
- struct tcb *tcb;
- int cnt;
- {
- /* Wake up anybody waiting to send data, and let them run */
- psignal(itop(tcb->user),1);
- pwait(NULL);
- }
- /* TCP state change upcall routine */
- static void
- s_tscall(tcb,old,new)
- struct tcb *tcb;
- int old,new;
- {
- int s,ns;
- struct usock *up,*nup,*oup;
- union sp sp;
-
- s = tcb->user;
- oup = up = itop(s);
-
- switch(new){
- case TCP_CLOSED:
- /* Clean up. If the user has already closed the socket,
- * then up will be null (s was set to -1 by the close routine).
- * If not, then this is an abnormal close (e.g., a reset)
- * and clearing out the pointer in the socket structure will
- * prevent any further operations on what will be a freed
- * control block. Also wake up anybody waiting on events
- * related to this tcb so they will notice it disappearing.
- */
- if(up != NULLUSOCK){
- up->cb.tcb = NULLTCB;
- up->errcodes[0] = tcb->reason;
- up->errcodes[1] = tcb->type;
- up->errcodes[2] = tcb->code;
- }
- del_tcp(tcb);
- break;
- case TCP_SYN_RECEIVED:
- /* Handle an incoming connection. If this is a server TCB,
- * then we're being handed a "clone" TCB and we need to
- * create a new socket structure for it. In either case,
- * find out who we're talking to and wake up the guy waiting
- * for the connection.
- */
- if(tcb->flags.clone){
- /* Clone the socket */
- ns = socket(AF_INET,SOCK_STREAM,0);
- nup = itop(ns);
- ASSIGN(*nup,*up);
- tcb->user = ns;
- nup->cb.tcb = tcb;
- /* Allocate new memory for the name areas */
- nup->name = mallocw(SOCKSIZE);
- nup->peername = mallocw(SOCKSIZE);
- /* Store the new socket # in the old one */
- up->rdysock = ns;
- up = nup;
- s = ns;
- } else {
- /* Allocate space for the peer's name */
- up->peername = mallocw(SOCKSIZE);
- /* Store the old socket # in the old socket */
- up->rdysock = s;
- }
- /* Load the addresses. Memory for the name has already
- * been allocated, either above or in the original bind.
- */
- sp.p = up->name;
- sp.in->sin_family = AF_INET;
- sp.in->sin_addr.s_addr = up->cb.tcb->conn.local.address;
- sp.in->sin_port = up->cb.tcb->conn.local.port;
- up->namelen = SOCKSIZE;
-
- sp.p = up->peername;
- sp.in->sin_family = AF_INET;
- sp.in->sin_addr.s_addr = up->cb.tcb->conn.remote.address;
- sp.in->sin_port = up->cb.tcb->conn.remote.port;
- up->peernamelen = SOCKSIZE;
-
- /* Wake up the guy accepting it, and let him run */
- psignal(oup,1);
- pwait(NULL);
- break;
- default: /* Ignore all other state transitions */
- break;
- }
- psignal(up,0); /* In case anybody's waiting */
- }
- /* Discard data received on a TCP connection. Used after a receive shutdown or
- * close_s until the TCB disappears.
- */
- static void
- trdiscard(tcb,cnt)
- struct tcb *tcb;
- int cnt;
- {
- struct mbuf *bp;
-
- recv_tcp(tcb,&bp,(int16)cnt);
- free_p(bp);
- }
- #ifdef AX25
- /* AX.25 receive upcall */
- void
- s_arcall(axp,cnt)
- struct ax25_cb *axp;
- int cnt;
- {
- int ns;
- struct usock *up,*nup,*oup;
- union sp sp;
-
- up = itop(axp->user);
- /* When AX.25 data arrives for the first time the AX.25 listener
- is notified, if active. If the AX.25 listener is a server its
- socket is duplicated in the same manner as in s_tscall().
- */
- if (Axi_sock != -1 && axp->user == -1) {
- oup = up = itop(Axi_sock);
- /* From now on, use the same upcalls as the listener */
- axp->t_upcall = up->cb.ax25->t_upcall;
- axp->r_upcall = up->cb.ax25->r_upcall;
- axp->s_upcall = up->cb.ax25->s_upcall;
- if (up->cb.ax25->flags.clone) {
- /* Clone the socket */
- ns = socket(AF_AX25,SOCK_STREAM,0);
- nup = itop(ns);
- ASSIGN(*nup,*up);
- axp->user = ns;
- nup->cb.ax25 = axp;
- /* Allocate new memory for the name areas */
- nup->name = mallocw(sizeof(struct sockaddr_ax));
- nup->peername = mallocw(sizeof(struct sockaddr_ax));
- /* Store the new socket # in the old one */
- up->rdysock = ns;
- up = nup;
- } else {
- axp->user = Axi_sock;
- del_ax25(up->cb.ax25);
- up->cb.ax25 = axp;
- /* Allocate space for the peer's name */
- up->peername = mallocw(sizeof(struct sockaddr_ax));
- /* Store the old socket # in the old socket */
- up->rdysock = Axi_sock;
- }
- /* Load the addresses. Memory for the name has already
- * been allocated, either above or in the original bind.
- */
- sp.p = up->name;
- sp.ax->sax_family = AF_AX25;
- memcpy(sp.ax->ax25_addr,axp->local,AXALEN);
- memcpy(sp.ax->iface,axp->iface->name,ILEN);
- up->namelen = sizeof(struct sockaddr_ax);
-
- sp.p = up->peername;
- sp.ax->sax_family = AF_AX25;
- memcpy(sp.ax->ax25_addr,axp->remote,AXALEN);
- memcpy(sp.ax->iface,axp->iface->name,ILEN);
- up->peernamelen = sizeof(struct sockaddr_ax);
- /* Wake up the guy accepting it, and let him run */
- psignal(oup,1);
- pwait(NULL);
- return;
- }
- /* Wake up anyone waiting, and let them run */
- psignal(up,1);
- pwait(NULL);
- }
- /* AX.25 transmit upcall */
- void
- s_atcall(axp,cnt)
- struct ax25_cb *axp;
- int cnt;
- {
- /* Wake up anyone waiting, and let them run */
- psignal(itop(axp->user),1);
- pwait(NULL);
- }
- /* AX25 state change upcall routine */
- void
- s_ascall(axp,old,new)
- register struct ax25_cb *axp;
- int old,new;
- {
- int s;
- struct usock *up;
-
- s = axp->user;
- up = itop(s);
-
- switch(new){
- case LAPB_DISCONNECTED:
- /* Clean up. If the user has already closed the socket,
- * then up will be null (s was set to -1 by the close routine).
- * If not, then this is an abnormal close (e.g., a reset)
- * and clearing out the pointer in the socket structure will
- * prevent any further operations on what will be a freed
- * control block. Also wake up anybody waiting on events
- * related to this block so they will notice it disappearing.
- */
- if(up != NULLUSOCK){
- up->errcodes[0] = axp->reason;
- up->cb.ax25 = NULLAX25;
- }
- del_ax25(axp);
- break;
- default: /* Other transitions are ignored */
- break;
- }
- psignal(up,0); /* In case anybody's waiting */
- }
- #endif
- #ifdef NETROM
- /* NET/ROM receive upcall routine */
- static void
- s_nrcall(cb,cnt)
- struct nr4cb *cb;
- int cnt;
- {
- /* Wake up anybody waiting for data, and let them run */
- psignal(itop(cb->user),1);
- pwait(NULL);
- }
- /* NET/ROM transmit upcall routine */
- static void
- s_ntcall(cb,cnt)
- struct nr4cb *cb;
- int cnt;
- {
- /* Wake up anybody waiting to send data, and let them run */
- psignal(itop(cb->user),1);
- pwait(NULL);
- }
- /* NET/ROM state change upcall routine */
- static void
- s_nscall(cb,old,new)
- struct nr4cb *cb;
- int old,new;
- {
- int s,ns;
- struct usock *up,*nup,*oup;
- union sp sp;
-
- s = cb->user;
- oup = up = itop(s);
-
- if(new == NR4STDISC && up != NULLUSOCK){
- /* Clean up. If the user has already closed the socket,
- * then up will be null (s was set to -1 by the close routine).
- * If not, then this is an abnormal close (e.g., a reset)
- * and clearing out the pointer in the socket structure will
- * prevent any further operations on what will be a freed
- * control block. Also wake up anybody waiting on events
- * related to this cb so they will notice it disappearing.
- */
- up->cb.nr4 = NULLNR4CB;
- up->errcodes[0] = cb->dreason;
- }
- if(new == NR4STCON && old == NR4STDISC){
- /* Handle an incoming connection. If this is a server cb,
- * then we're being handed a "clone" cb and we need to
- * create a new socket structure for it. In either case,
- * find out who we're talking to and wake up the guy waiting
- * for the connection.
- */
- if(cb->clone){
- /* Clone the socket */
- ns = socket(AF_NETROM,SOCK_SEQPACKET,0);
- nup = itop(ns);
- ASSIGN(*nup,*up);
- cb->user = ns;
- nup->cb.nr4 = cb;
- cb->clone = 0; /* to avoid getting here again */
- /* Allocate new memory for the name areas */
- nup->name = mallocw(sizeof(struct sockaddr_nr));
- nup->peername = mallocw(sizeof(struct sockaddr_nr));
- /* Store the new socket # in the old one */
- up->rdysock = ns;
- up = nup;
- s = ns;
- } else {
- /* Allocate space for the peer's name */
- up->peername = mallocw(sizeof(struct sockaddr_nr));
- /* Store the old socket # in the old socket */
- up->rdysock = s;
- }
- /* Load the addresses. Memory for the name has already
- * been allocated, either above or in the original bind.
- */
- sp.p = up->name;
- sp.nr->nr_family = AF_NETROM;
- ASSIGN(sp.nr->nr_addr,up->cb.nr4->local);
- up->namelen = sizeof(struct sockaddr_nr);
-
- sp.p = up->peername;
- sp.nr->nr_family = AF_NETROM;
- ASSIGN(sp.nr->nr_addr,up->cb.nr4->remote);
- up->peernamelen = sizeof(struct sockaddr_nr);
-
- /* Wake up the guy accepting it, and let him run */
- psignal(oup,1);
- pwait(NULL);
- }
- /* Ignore all other state transitions */
- psignal(up,0); /* In case anybody's waiting */
- }
- #endif
-
- /* Verify address family and length according to the socket type */
- static int
- checkaddr(type,name,namelen)
- int type;
- char *name;
- int namelen;
- {
- union sp sp;
-
- sp.p = name;
- /* Verify length and address family according to protocol */
- switch(type){
- case TYPE_TCP:
- case TYPE_UDP:
- if(sp.in->sin_family != AF_INET
- || namelen != sizeof(struct sockaddr_in))
- return -1;
- break;
- #ifdef AX25
- case TYPE_AX25I:
- case TYPE_AX25UI:
- if(sp.ax->sax_family != AF_AX25
- || namelen != sizeof(struct sockaddr_ax))
- return -1;
- break;
- #endif
- #ifdef NETROM
- case TYPE_NETROML3:
- case TYPE_NETROML4:
- if(sp.nr->nr_family != AF_NETROM
- || namelen != sizeof(struct sockaddr_nr))
- return -1;
- break;
- #endif
- }
- return 0;
- }
- /* Issue an automatic bind of a local address */
- static void
- autobind(s,af)
- int s,af;
- {
- char buf[MAXSOCKSIZE];
- union sp sp;
-
- sp.p = buf;
- switch(af){
- case AF_INET:
- sp.in->sin_family = AF_INET;
- sp.in->sin_addr.s_addr = INADDR_ANY;
- sp.in->sin_port = Lport++;
- bind(s,sp.p,sizeof(struct sockaddr_in));
- break;
- #ifdef AX25
- case AF_AX25:
- sp.ax->sax_family = AF_AX25;
- memset(sp.ax->ax25_addr,'\0',AXALEN);
- memset(sp.ax->iface,'\0',ILEN);
- bind(s,sp.p,sizeof(struct sockaddr_ax));
- break;
- #endif
- #ifdef NETROM
- case AF_NETROM:
- sp.nr->nr_family = AF_NETROM;
- memcpy(sp.nr->nr_addr.user,Mycall,AXALEN);
- memcpy(sp.nr->nr_addr.node,Mycall,AXALEN);
- bind(s,sp.p,sizeof(struct sockaddr_nr));
- break;
- #endif
- }
- }
-
- /* Return a pair of mutually connected sockets in sv[0] and sv[1] */
- int
- socketpair(af,type,protocol,sv)
- int af;
- int type;
- int protocol;
- int sv[];
- {
- struct usock *up0, *up1;
- if(sv == NULLINT){
- errno = EFAULT;
- return -1;
- }
- if(af != AF_LOCAL){
- errno = EAFNOSUPPORT;
- return -1;
- }
- if(type != SOCK_STREAM && type != SOCK_DGRAM){
- errno = ESOCKTNOSUPPORT;
- return -1;
- }
- if((sv[0] = socket(af,type,protocol)) == -1)
- return -1;
- if((sv[1] = socket(af,type,protocol)) == -1){
- close_s(sv[0]);
- return -1;
- }
- up0 = itop(sv[0]);
- up1 = itop(sv[1]);
- up0->cb.local->peer = up1;
- up1->cb.local->peer = up0;
- return sv[1];
- }
-