#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/ioctl.h>
#include <sys/errno.h>
#include <sys/time.h>
#include <sys/proc.h>
#include <kern/kern_types.h>
#include <kern/zalloc.h>
#include <kern/queue.h>
#include <net/if.h>
#include <netat/sysglue.h>
#include <netat/appletalk.h>
#include <netat/ddp.h>
#include <netat/at_pcb.h>
#include <netat/debug.h>
#include <netat/at_var.h>
#include <netat/adsp.h>
#include <netat/adsp_internal.h>
extern struct atpcb ddp_head;
extern struct atpcb *atp_inputQ[];
extern CCB *adsp_inputQ[];
extern at_ifaddr_t *ifID_home;
extern struct {
void (*func)();
} ddp_handler[];
int DDP_chksum_on = FALSE;
int DDP_slfsnd_on = FALSE;
zone_t atpcb_zone;
void at_memzone_init()
{
vm_size_t str_size;
str_size = (vm_size_t)sizeof(struct atpcb);
atpcb_zone = (zone_t)zinit(str_size, 1000*str_size, 8192, "atpcb zone");
}
int at_pcballoc(so, head)
struct socket *so;
struct atpcb *head;
{
register struct atpcb *pcb;
pcb = (struct atpcb *)zalloc(atpcb_zone);
if (pcb == NULL)
return (ENOBUFS);
bzero((caddr_t)pcb, sizeof(*pcb));
if (DDP_chksum_on)
pcb->ddp_flags |= DDPFLG_CHKSUM;
else
pcb->ddp_flags &= ~DDPFLG_CHKSUM;
if (DDP_slfsnd_on)
pcb->ddp_flags |= DDPFLG_SLFSND;
else
pcb->ddp_flags &= ~DDPFLG_SLFSND;
pcb->atpcb_head = head;
pcb->atpcb_socket = so;
if (head)
insque((queue_t)pcb, (queue_t)head);
so->so_pcb = (caddr_t)pcb;
return (0);
}
int at_pcbdetach(pcb)
struct atpcb *pcb;
{
struct socket *so = pcb->atpcb_socket;
if (pcb->lport) {
ddp_notify_nbp(pcb->lport, pcb->pid, pcb->ddptype);
pcb->lport = 0;
}
so->so_pcb = 0;
if ((pcb->atpcb_next) && (pcb->atpcb_prev))
remque((queue_t)pcb);
zfree(atpcb_zone, (vm_offset_t)pcb);
sofree(so);
return(0);
}
int ddp_socket_inuse(ddpsock, proto)
u_char ddpsock, proto;
{
struct atpcb *pcb;
if ((!proto || (proto == DDP_ATP)) && atp_inputQ[ddpsock])
return TRUE;
if ((!proto || (proto == DDP_ADSP)) && adsp_inputQ[ddpsock])
return TRUE;
if (ddp_handler[ddpsock].func)
return TRUE;
for (pcb = ddp_head.atpcb_next; pcb != &ddp_head;
pcb = pcb->atpcb_next) {
if (pcb->lport == ddpsock &&
(!pcb->ddptype || !proto || (pcb->ddptype == proto)))
return TRUE;
}
return FALSE;
}
int at_pcbbind(pcb, nam)
register struct atpcb *pcb;
struct sockaddr *nam;
{
register struct socket *so = pcb->atpcb_socket;
register struct sockaddr_at *local = (struct sockaddr_at *) nam;
u_char ddpsock = local->sat_port;
if ((!ifID_home) || (local->sat_family != AF_APPLETALK))
return(EADDRNOTAVAIL);
if (pcb->lport != ATADDR_ANYPORT ||
pcb->laddr.s_node != ATADDR_ANYNODE ||
pcb->laddr.s_net != ATADDR_ANYNET)
return(EINVAL);
if (ddpsock == 0) {
for (ddpsock = DDP_SOCKET_LAST;
ddpsock >= (DDP_SOCKET_1st_DYNAMIC + 1);
ddpsock--) {
if (! ddp_socket_inuse(ddpsock, pcb->ddptype))
break;
}
if (ddpsock < (DDP_SOCKET_1st_DYNAMIC + 1))
return(EADDRNOTAVAIL);
} else {
if (ddpsock > DDP_SOCKET_LAST)
return(EINVAL);
if (ddp_socket_inuse(ddpsock, pcb->ddptype))
return(EADDRNOTAVAIL);
}
pcb->lport = ddpsock;
if (local->sat_addr.s_net || local->sat_addr.s_node) {
if (MULTIHOME_MODE) {
at_ifaddr_t *ifID;
TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) {
if (ifID->ifThisNode.s_net == local->sat_addr.s_net &&
ifID->ifThisNode.s_node == local->sat_addr.s_node) {
pcb->laddr = local->sat_addr;
return(0);
}
}
return(EINVAL);
} else {
if (ifID_home->ifThisNode.s_net == local->sat_addr.s_net &&
ifID_home->ifThisNode.s_node == local->sat_addr.s_node) {
pcb->laddr = local->sat_addr;
return(0);
}
return(EINVAL);
}
}
return(0);
}