#define RESOLVE_DBG
#include <sys/errno.h>
#include <sys/types.h>
#include <sys/param.h>
#include <machine/spl.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/filedesc.h>
#include <sys/fcntl.h>
#include <sys/mbuf.h>
#include <sys/ioctl.h>
#include <sys/malloc.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/protosw.h>
#include <net/if.h>
#include <net/dlil.h>
#include <netat/sysglue.h>
#include <netat/appletalk.h>
#include <netat/at_var.h>
#include <netat/ddp.h>
#include <netat/ep.h>
#include <netat/nbp.h>
#include <netat/rtmp.h>
#include <netat/zip.h>
#include <netat/at_pcb.h>
#include <netat/routing_tables.h>
#include <netat/at_snmp.h>
#include <netat/aurp.h>
#include <netat/debug.h>
#include <netat/at_ddp_brt.h>
#include <netat/at_aarp.h>
#include <netat/adsp.h>
#include <netat/adsp_internal.h>
struct at_ifQueueHd at_ifQueueHd;
extern at_state_t at_state;
extern TAILQ_HEAD(name_registry, _nve_) name_registry;
snmpStats_t snmpStats;
extern at_ddp_stats_t at_ddp_stats;
extern struct atpcb ddp_head;
extern at_ifaddr_t *ifID_home, *ifID_table[];
extern aarp_amt_array *aarp_table[];
extern at_ifaddr_t at_interfaces[];
void (*ddp_AURPsendx)();
at_ifaddr_t *aurp_ifID = 0;
extern pktsIn,pktsOut;
int pktsDropped,pktsHome;
atlock_t ddpall_lock;
atlock_t ddpinp_lock;
extern int *atp_pidM;
extern int *adsp_pidM;
extern struct atpcb *atp_inputQ[];
extern CCB *adsp_inputQ[];
at_ifaddr_t *forUs(at_ddp_t *);
void ddp_input(), ddp_notify_nbp();
extern void routing_needed();
extern void ddp_brt_sweep();
struct {
void (*func)();
} ddp_handler[256];
void init_ddp_handler()
{
bzero(ddp_handler, sizeof(ddp_handler));
}
void add_ddp_handler(ddp_socket, input_func)
u_char ddp_socket;
void (*input_func)();
{
ddp_handler[ddp_socket].func = input_func;
}
void
ddp_slowtimo()
{
ddp_brt_sweep();
}
int ddp_ctloutput(so, sopt)
struct socket *so;
struct sockopt *sopt;
{
struct atpcb *at_pcb = sotoatpcb(so);
int optval, error = 0;
if (sopt->sopt_level != ATPROTO_NONE)
return (EINVAL);
switch (sopt->sopt_dir) {
case SOPT_GET:
switch (sopt->sopt_name) {
case DDP_HDRINCL:
optval = at_pcb->ddp_flags & DDPFLG_HDRINCL;
error = sooptcopyout(sopt, &optval, sizeof optval);
break;
case DDP_CHKSUM_ON:
optval = at_pcb->ddp_flags & DDPFLG_CHKSUM;
error = sooptcopyout(sopt, &optval, sizeof optval);
break;
case DDP_STRIPHDR:
optval = at_pcb->ddp_flags & DDPFLG_STRIPHDR;
error = sooptcopyout(sopt, &optval, sizeof optval);
break;
case DDP_SLFSND_ON:
optval = at_pcb->ddp_flags & DDPFLG_SLFSND;
error = sooptcopyout(sopt, &optval, sizeof optval);
break;
case DDP_GETSOCKNAME:
{
ddp_addr_t addr;
addr.inet.net = at_pcb->laddr.s_net;
addr.inet.node = at_pcb->laddr.s_node;
addr.inet.socket = at_pcb->lport;
addr.ddptype = at_pcb->ddptype;
error = sooptcopyout(sopt, &addr, sizeof addr);
}
break;
default:
error = ENOPROTOOPT;
break;
}
break;
case SOPT_SET:
switch (sopt->sopt_name) {
case DDP_HDRINCL:
error = sooptcopyin(sopt, &optval, sizeof optval,
sizeof optval);
if (error)
break;
if (optval)
at_pcb->ddp_flags |= DDPFLG_HDRINCL;
else
at_pcb->ddp_flags &= ~DDPFLG_HDRINCL;
break;
case DDP_CHKSUM_ON:
error = sooptcopyin(sopt, &optval, sizeof optval,
sizeof optval);
if (error)
break;
if (optval)
at_pcb->ddp_flags |= DDPFLG_CHKSUM;
else
at_pcb->ddp_flags &= ~DDPFLG_CHKSUM;
break;
case DDP_STRIPHDR:
error = sooptcopyin(sopt, &optval, sizeof optval,
sizeof optval);
if (error)
break;
if (optval)
at_pcb->ddp_flags |= DDPFLG_STRIPHDR;
else
at_pcb->ddp_flags &= ~DDPFLG_STRIPHDR;
break;
case DDP_SLFSND_ON:
error = sooptcopyin(sopt, &optval, sizeof optval,
sizeof optval);
if (error)
break;
if (optval)
at_pcb->ddp_flags |= DDPFLG_SLFSND;
else
at_pcb->ddp_flags &= ~DDPFLG_SLFSND;
break;
default:
error = ENOPROTOOPT;
break;
}
break;
}
return(error);
}
u_short ddp_checksum(mp, offset)
register gbuf_t *mp;
register int offset;
{
register u_char *data;
register int length;
register u_short checksum;
checksum = 0;
do {
if (offset >= gbuf_len(mp))
offset -= gbuf_len(mp);
else {
data = ((unsigned char *) gbuf_rptr(mp)) + offset;
length = gbuf_len(mp) - offset;
offset = 0;
while (length--) {
checksum += *data++;
checksum = (checksum & 0x8000) ?
((checksum << 1) | 1) : (checksum << 1);
}
}
} while ( (mp = gbuf_cont(mp)) );
if (checksum == 0)
checksum = 0xffff;
return(checksum);
}
int ddp_add_if(ifID)
register at_ifaddr_t *ifID;
{
int port = -1;
dPrintf(D_M_DDP, D_L_STARTUP,
("ddp_add_if: called, ifID:0x%x\n", (u_int) ifID));
if (ifID->ifFlags & AT_IFF_DEFAULT) {
if (ifID_home)
return(EEXIST);
else {
port = IFID_HOME;
ifID_home = ifID;
}
} else {
for (port=IFID_HOME+1; port<IF_TOTAL_MAX; port++)
if (!ifID_table[port]) {
break;
}
if (port == IF_TOTAL_MAX)
return(ENOMEM);
}
if ((aarp_table[port] =
(aarp_amt_array *)_MALLOC(sizeof(aarp_amt_array),
M_RTABLE, M_WAITOK)) == NULL)
return(ENOMEM);
dPrintf(D_M_DDP, D_L_STARTUP, ("ddp:adding ifID_table[%d]\n", port));
ifID_table[port] = ifID;
ifID->ifPort = port;
TAILQ_INSERT_TAIL(&at_ifQueueHd, ifID, aa_link);
return (0);
}
void ddp_rem_if(ifID)
register at_ifaddr_t *ifID;
{
struct ifaddr *ifa = &ifID->aa_ifa;
if (ifa->ifa_addr) {
int s = splnet();
TAILQ_REMOVE(&ifID->aa_ifp->if_addrhead, ifa, ifa_link);
ifa->ifa_addr = NULL;
splx(s);
}
if (ifID->at_dl_tag) {
ether_detach_at(ifID->aa_ifp);
ifID->at_dl_tag = 0;
}
if (ifID->ifPort) {
if (aarp_table[ifID->ifPort]) {
FREE(aarp_table[ifID->ifPort], M_RTABLE);
aarp_table[ifID->ifPort] = NULL;
}
at_state.flags |= AT_ST_IF_CHANGED;
ifID->aa_ifp = NULL;
trackrouter_rem_if(ifID);
TAILQ_REMOVE(&at_ifQueueHd, ifID, aa_link);
ifID_table[ifID->ifPort] = NULL;
ifID->ifName[0] = '\0';
ifID->ifPort = 0;
}
}
int ot_ddp_check_socket(socket, pid)
unsigned char socket;
int pid;
{
int cnt = 0;
gref_t *gref;
dPrintf(D_M_DDP, D_L_INFO, ("ot_ddp_check_socket: %d\n", socket));
for (gref = ddp_head.atpcb_next; gref != &ddp_head; gref = gref->atpcb_next)
if (gref->lport == socket && gref->pid == pid)
cnt++;
if ((atp_inputQ[socket] != NULL) && (atp_inputQ[socket] != (gref_t *)1)
&& (atp_pidM[socket] == pid))
cnt++;
if ((adsp_inputQ[socket] != NULL) && (adsp_pidM[socket] == pid))
cnt++;
return(cnt);
}
void ddp_notify_nbp(socket, pid, ddptype)
unsigned char socket;
int pid;
unsigned char ddptype;
{
extern int nve_lock;
nve_entry_t *nve_entry, *nve_next;
if (at_state.flags & AT_ST_STARTED) {
ATDISABLE(nve_lock, NVE_LOCK);
for ((nve_entry = TAILQ_FIRST(&name_registry)); nve_entry; nve_entry = nve_next) {
nve_next = TAILQ_NEXT(nve_entry, nve_link);
if ((at_socket)socket == nve_entry->address.socket &&
pid == nve_entry->pid &&
ot_ddp_check_socket(nve_entry->address.socket,
nve_entry->pid) < 2) {
nbp_delete_entry(nve_entry);
}
}
ATENABLE(nve_lock, NVE_LOCK);
}
}
static void fillin_pkt_chain(m)
gbuf_t *m;
{
gbuf_t *tmp_m = m;
register at_ddp_t
*ddp = (at_ddp_t *)gbuf_rptr(m),
*tmp_ddp;
u_short tmp;
if (UAS_VALUE(ddp->checksum)) {
tmp = ddp_checksum(m, 4);
UAS_ASSIGN(ddp->checksum, tmp);
}
for (tmp_m=gbuf_next(tmp_m); tmp_m; tmp_m=gbuf_next(tmp_m)) {
tmp_ddp = (at_ddp_t *)gbuf_rptr(tmp_m);
tmp_ddp->length = gbuf_msgsize(tmp_m);
tmp_ddp->hopcount =
tmp_ddp->unused = 0;
NET_NET(tmp_ddp->src_net, ddp->src_net);
tmp_ddp->src_node = ddp->src_node;
tmp_ddp->src_socket = ddp->src_socket;
if (UAS_VALUE(tmp_ddp->checksum)) {
tmp = ddp_checksum(tmp_m, 4);
UAS_ASSIGN(tmp_ddp->checksum, tmp);
}
}
}
#define DIRECT_ADDR 1
#define BRT_ENTRY 2
#define BRIDGE_ADDR 3
int ddp_output(mp, src_socket, src_addr_included)
register gbuf_t **mp;
at_socket src_socket;
int src_addr_included;
{
register at_ifaddr_t *ifID = ifID_home, *ifIDTmp = NULL;
register at_ddp_t *ddp;
register ddp_brt_t *brt;
register at_net_al dst_net;
register int len;
struct atalk_addr at_dest;
at_ifaddr_t *ARouterIf = NULL;
int loop = 0;
int error = 0;
int addr_type;
u_char addr_flag;
char *addr = NULL;
register gbuf_t *m;
KERNEL_DEBUG(DBG_AT_DDP_OUTPUT | DBG_FUNC_START, 0,
0,0,0,0);
snmpStats.dd_outReq++;
m = *mp;
ddp = (at_ddp_t *)gbuf_rptr(m);
if (!ifID) {
dPrintf(D_M_DDP, D_L_ERROR, ("Device/Interface not configured"));
error = ENXIO;
gbuf_freel(*mp);
goto exit_ddp_output;
}
if ((ddp->dst_socket > (unsigned) (DDP_SOCKET_LAST + 1)) ||
(ddp->dst_socket < DDP_SOCKET_1st_RESERVED)) {
dPrintf(D_M_DDP, D_L_ERROR,
("Illegal destination socket on outgoing packet (0x%x)",
ddp->dst_socket));
at_ddp_stats.xmit_bad_addr++;
error = ENOTSOCK;
gbuf_freel(*mp);
goto exit_ddp_output;
}
if ((len = gbuf_msgsize(*mp)) > DDP_DATAGRAM_SIZE) {
dPrintf(D_M_DDP, D_L_ERROR,
("Outgoing packet too long (len=%d bytes)", len));
at_ddp_stats.xmit_bad_length++;
error = EMSGSIZE;
gbuf_freel(*mp);
goto exit_ddp_output;
}
at_ddp_stats.xmit_bytes += len;
at_ddp_stats.xmit_packets++;
ddp->length = len;
ddp->hopcount =
ddp->unused = 0;
dst_net = NET_VALUE(ddp->dst_net);
if ((ddp->dst_node == 0xfe) &&
((dst_net == ATADDR_ANYNET) ||
(dst_net >= ifID_home->ifThisCableStart &&
dst_net <= ifID_home->ifThisCableEnd))) {
NET_ASSIGN(ddp->dst_net, ifID_home->ifARouter.s_net);
dst_net = ifID_home->ifARouter.s_net;
ddp->dst_node = ifID_home->ifARouter.s_node;
}
if (MULTIHOME_MODE && (ifIDTmp = forUs(ddp))) {
ifID = ifIDTmp;
loop = TRUE;
dPrintf(D_M_DDP_LOW, D_L_USR1,
("ddp_out: for us if:%s\n", ifIDTmp->ifName));
}
if (!loop)
loop = ((ddp->dst_node == ifID->ifThisNode.s_node) &&
(dst_net == ifID->ifThisNode.s_net)
);
if (loop) {
gbuf_t *mdata, *mdata_next;
if (!MULTIHOME_MODE || !src_addr_included) {
NET_ASSIGN(ddp->src_net, ifID->ifThisNode.s_net);
ddp->src_node = ifID->ifThisNode.s_node;
}
ddp->src_socket = src_socket;
dPrintf(D_M_DDP_LOW, D_L_OUTPUT,
("ddp_output: loop to %d:%d port=%d\n",
NET_VALUE(ddp->dst_net),
ddp->dst_node,
ifID->ifPort));
fillin_pkt_chain(*mp);
dPrintf(D_M_DDP, D_L_VERBOSE,
("Looping back packet from skt 0x%x to skt 0x%x\n",
ddp->src_socket, ddp->dst_socket));
for (mdata = *mp; mdata; mdata = mdata_next) {
mdata_next = gbuf_next(mdata);
gbuf_next(mdata) = 0;
ddp_input(mdata, ifID);
}
goto exit_ddp_output;
}
if ((ddp->dst_socket == ZIP_SOCKET) &&
(zip_type_packet(*mp) == ZIP_GETMYZONE)) {
ddp->src_socket = src_socket;
error = zip_handle_getmyzone(ifID, *mp);
gbuf_freel(*mp);
goto exit_ddp_output;
}
TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) {
if ((ifID->ifThisNode.s_net == dst_net) || (dst_net == 0))
break;
if ((ifID->ifThisCableStart <= dst_net) &&
(ifID->ifThisCableEnd >= dst_net)
)
break;
if (ARouterIf == NULL && ATALK_VALUE(ifID->ifARouter))
ARouterIf = ifID;
}
dPrintf(D_M_DDP_LOW, D_L_USR1,
("ddp_output: after search ifid:0x%x %s ifID_home:0x%x\n",
(u_int)ifID, ifID ? ifID->ifName : "",
(u_int)ifID_home));
if (ifID) {
addr_type = DIRECT_ADDR;
} else {
if (!MULTIPORT_MODE) {
BRT_LOOK (brt, dst_net);
if (brt) {
dPrintf(D_M_DDP, D_L_VERBOSE,
("Found BRT entry to send to net 0x%x", dst_net));
at_ddp_stats.xmit_BRT_used++;
addr_type = BRT_ENTRY;
ifID = brt->ifID;
} else {
if ((ifID = ARouterIf) != NULL)
addr_type = BRIDGE_ADDR;
else {
dPrintf(D_M_DDP, D_L_WARNING,
("Found no interface to send pkt"));
at_ddp_stats.xmit_bad_addr++;
error = ENETUNREACH;
gbuf_freel(*mp);
goto exit_ddp_output;
}
}
}
else {
at_ddp_stats.xmit_BRT_used++;
ifID = ifID_home;
if (!src_addr_included) {
ddp->src_node = ifID->ifThisNode.s_node;
NET_ASSIGN(ddp->src_net, ifID->ifThisNode.s_net);
}
ddp->src_socket = src_socket;
routing_needed(*mp, ifID, TRUE);
goto exit_ddp_output;
}
}
if (ifID->ifState == LAP_OFFLINE) {
gbuf_freel(*mp);
goto exit_ddp_output;
}
switch (addr_type) {
case DIRECT_ADDR :
NET_ASSIGN(at_dest.atalk_net, dst_net);
at_dest.atalk_node = ddp->dst_node;
addr_flag = AT_ADDR;
addr = (char *)&at_dest;
break;
case BRT_ENTRY :
addr_flag = ET_ADDR;
addr = (char *)&brt->et_addr;
break;
case BRIDGE_ADDR :
NET_ASSIGN(at_dest.atalk_net, ifID->ifARouter.s_net);
at_dest.atalk_node = ifID->ifARouter.s_node;
addr_flag = AT_ADDR;
addr = (char *)&at_dest;
break;
}
if (MULTIHOME_MODE) {
if (!src_addr_included) {
ddp->src_node = ifID->ifThisNode.s_node;
NET_ASSIGN(ddp->src_net, ifID->ifThisNode.s_net);
}
}
else {
ddp->src_node = ifID_home->ifThisNode.s_node;
NET_ASSIGN(ddp->src_net, ifID_home->ifThisNode.s_net);
}
ddp->src_socket = src_socket;
dPrintf(D_M_DDP_LOW, D_L_OUTPUT,
("ddp_output: going out to %d:%d skt%d on %s\n",
dst_net, ddp->dst_node, ddp->dst_socket, ifID->ifName));
fillin_pkt_chain(*mp);
{
struct etalk_addr dest_addr;
struct atalk_addr dest_at_addr;
int loop = TRUE;
m = *mp;
if (addr == NULL) {
addr_flag = *(u_char *)gbuf_rptr(m);
gbuf_rinc(m,1);
}
switch (addr_flag) {
case AT_ADDR_NO_LOOP :
loop = FALSE;
case AT_ADDR :
if (addr == NULL) {
dest_at_addr = *(struct atalk_addr *)gbuf_rptr(m);
gbuf_rinc(m,sizeof(struct atalk_addr));
} else
dest_at_addr = *(struct atalk_addr *)addr;
break;
case ET_ADDR :
if (addr == NULL) {
dest_addr = *(struct etalk_addr *)gbuf_rptr(m);
gbuf_rinc(m,sizeof(struct etalk_addr));
} else
dest_addr = *(struct etalk_addr *)addr;
break;
default :
dPrintf(D_M_DDP_LOW,D_L_ERROR,
("ddp_output: Unknown addr_flag = 0x%x\n", addr_flag));
gbuf_freel(m);
goto exit_ddp_output;
}
m = gbuf_strip(m);
if (ifID->ifState == LAP_ONLINE_FOR_ZIP) {
if (zip_type_packet(m) == 0) {
gbuf_freel(m);
goto exit_ddp_output;
}
}
ifID->stats.xmit_packets++;
ifID->stats.xmit_bytes += gbuf_msgsize(m);
snmpStats.dd_outLong++;
switch (addr_flag) {
case AT_ADDR_NO_LOOP :
case AT_ADDR :
aarp_send_data(m,ifID,&dest_at_addr, loop);
break;
case ET_ADDR :
pat_output(ifID, m, &dest_addr, 0);
break;
}
}
exit_ddp_output:
KERNEL_DEBUG(DBG_AT_DDP_OUTPUT | DBG_FUNC_END, 0,
error, 0, 0, 0);
return(error);
}
void ddp_input(mp, ifID)
register gbuf_t *mp;
register at_ifaddr_t *ifID;
{
register at_ddp_t *ddp;
register int msgsize;
register at_socket socket;
register int len;
register at_net_al dst_net;
KERNEL_DEBUG(DBG_AT_DDP_INPUT | DBG_FUNC_START, 0,
ifID, mp, gbuf_len(mp),0);
if (ifID_home == (at_ifaddr_t *)NULL) {
dPrintf(D_M_DDP, D_L_ERROR,
("dropped incoming packet ifID_home not set yet\n"));
gbuf_freem(mp);
goto out;
}
if ((mp = (gbuf_t *)ddp_compress_msg(mp)) == NULL) {
dPrintf(D_M_DDP, D_L_ERROR,
("dropped short incoming ET packet (len %d)", 0));
snmpStats.dd_inTotal++;
at_ddp_stats.rcv_bad_length++;
goto out;
}
msgsize = gbuf_msgsize(mp);
at_ddp_stats.rcv_bytes += msgsize;
at_ddp_stats.rcv_packets++;
if (!ifID)
ifID = ifID_home;
if (msgsize < DDP_X_HDR_SIZE) {
dPrintf(D_M_DDP, D_L_ERROR,
("dropped short incoming ET packet (len %d)", msgsize));
at_ddp_stats.rcv_bad_length++;
gbuf_freem(mp);
goto out;
}
ddp = (at_ddp_t *)gbuf_rptr(mp);
len = ddp->length;
if (msgsize != len) {
if ((unsigned) msgsize > len) {
if (len < DDP_X_HDR_SIZE) {
dPrintf(D_M_DDP, D_L_ERROR,
("Length problems, ddp length %d, buffer length %d",
len, msgsize));
snmpStats.dd_tooLong++;
at_ddp_stats.rcv_bad_length++;
gbuf_freem(mp);
goto out;
}
mp = ddp_adjmsg(mp, -(msgsize - len)) ? mp : 0;
if (mp == 0)
goto out;
} else {
dPrintf(D_M_DDP, D_L_ERROR,
("Length problems, ddp length %d, buffer length %d",
len, msgsize));
snmpStats.dd_tooShort++;
at_ddp_stats.rcv_bad_length++;
gbuf_freem(mp);
goto out;
}
}
socket = ddp->dst_socket;
if (!MULTIPORT_MODE && (socket > DDP_SOCKET_LAST ||
socket < DDP_SOCKET_1st_RESERVED)) {
dPrintf(D_M_DDP, D_L_WARNING,
("Bad dst socket on incoming packet (0x%x)",
ddp->dst_socket));
at_ddp_stats.rcv_bad_socket++;
gbuf_freem(mp);
goto out;
}
if (UAS_VALUE(ddp->checksum) &&
(UAS_VALUE(ddp->checksum) != ddp_checksum(mp, 4))) {
dPrintf(D_M_DDP, D_L_WARNING,
("Checksum error on incoming pkt, calc 0x%x, exp 0x%x",
ddp_checksum(mp, 4), UAS_VALUE(ddp->checksum)));
snmpStats.dd_checkSum++;
at_ddp_stats.rcv_bad_checksum++;
gbuf_freem(mp);
goto out;
}
if (ddp_handler[socket].func) {
dPrintf(D_M_DDP,D_L_INPUT,
("ddp_input: skt %d hdnlr:0x%x\n",
(u_int) socket, ddp_handler[socket].func));
pktsHome++;
snmpStats.dd_inLocal++;
(*ddp_handler[socket].func)(mp, ifID);
goto out;
}
dst_net = NET_VALUE(ddp->dst_net);
if (
forUs(ddp) ||
((ddp->dst_node == 255) &&
(((dst_net >= ifID_home->ifThisCableStart) &&
(dst_net <= ifID_home->ifThisCableEnd)) ||
dst_net == 0)) ||
(ifID->ifRoutingState < PORT_ONLINE)
) {
gref_t *gref;
pktsHome++;
snmpStats.dd_inLocal++;
if (ddp->type == DDP_ATP) {
if (atp_inputQ[socket] && (atp_inputQ[socket] != (gref_t *)1)) {
atp_input(mp);
goto out;
}
} else if (ddp->type == DDP_ADSP) {
if (adsp_inputQ[socket]) {
adsp_input(mp);
goto out;
}
}
for (gref = ddp_head.atpcb_next; gref != &ddp_head;
gref = gref->atpcb_next)
if (gref->lport == socket &&
(gref->ddptype == 0 || gref->ddptype == ddp->type)) {
dPrintf(D_M_DDP, D_L_INPUT,
("ddp_input: streamq, skt %d\n", socket));
if (gref->atpcb_socket) {
struct sockaddr_at ddp_in;
ddp_in.sat_len = sizeof(ddp_in);
ddp_in.sat_family = AF_APPLETALK;
ddp_in.sat_addr.s_net = NET_VALUE(ddp->src_net);
ddp_in.sat_addr.s_node = ddp->src_node;
ddp_in.sat_port = ddp->src_socket;
if (gref->ddp_flags & DDPFLG_STRIPHDR) {
mp = m_pullup((struct mbuf *)mp,
DDP_X_HDR_SIZE);
if (mp) {
gbuf_rinc(mp, DDP_X_HDR_SIZE);
} else {
at_ddp_stats.rcv_bad_length++;
goto out;
}
}
if (sbappendaddr(&((gref->atpcb_socket)->so_rcv),
(struct sockaddr *)&ddp_in,
mp, 0) == 0)
gbuf_freem(mp);
else
sorwakeup(gref->atpcb_socket);
} else {
atalk_putnext(gref, mp);
}
goto out;
}
at_ddp_stats.rcv_bad_socket++;
gbuf_freem(mp);
snmpStats.dd_noHandler++;
dPrintf(D_M_DDP, D_L_WARNING,
("ddp_input: dropped pkt for socket %d\n", socket));
} else {
dPrintf(D_M_DDP, D_L_ROUTING,
("ddp_input: routing_needed from port=%d sock=%d\n",
ifID->ifPort, ddp->dst_socket));
snmpStats.dd_fwdReq++;
if (((pktsIn-pktsHome+200) >= RouterMix) && ((++pktsDropped % 5) == 0)) {
at_ddp_stats.rcv_dropped_nobuf++;
gbuf_freem(mp);
}
else {
routing_needed(mp, ifID, FALSE);
}
}
out:
KERNEL_DEBUG(DBG_AT_DDP_INPUT | DBG_FUNC_END, 0,0,0,0,0);
}
int ddp_router_output(mp, ifID, addr_type, router_net, router_node, enet_addr)
gbuf_t *mp;
at_ifaddr_t *ifID;
int addr_type;
at_net_al router_net;
at_node router_node;
etalk_addr_t *enet_addr;
{
register at_ddp_t *ddp;
struct atalk_addr at_dest;
int addr_flag;
char *addr = NULL;
register gbuf_t *m;
if (!ifID) {
dPrintf(D_M_DDP, D_L_WARNING, ("BAD BAD ifID\n"));
gbuf_freel(mp);
return(EPROTOTYPE);
}
ddp = (at_ddp_t *)gbuf_rptr(mp);
if (ifID->ifFlags & AT_IFF_AURP) {
if (ddp_AURPsendx) {
fillin_pkt_chain(mp);
if (router_node == 255)
router_node = 0;
ddp_AURPsendx(AURPCODE_DATAPKT, mp, router_node);
return 0;
} else {
gbuf_freel(mp);
return EPROTOTYPE;
}
}
if (gbuf_msgsize(mp) > DDP_DATAGRAM_SIZE) {
dPrintf(D_M_DDP, D_L_WARNING,
("ddp_router_output: Packet too large size=%d\n",
gbuf_msgsize(mp)));
gbuf_freel(mp);
return (EMSGSIZE);
}
switch (addr_type) {
case AT_ADDR :
if ((ddp->dst_node == ifID->ifThisNode.s_node) &&
(NET_VALUE(ddp->dst_net) == ifID->ifThisNode.s_net)) {
dPrintf(D_M_DDP_LOW, D_L_ROUTING,
("ddp_r_output: sending back home from port=%d socket=%d\n",
ifID->ifPort, ddp->dst_socket));
UAS_ASSIGN(ddp->checksum, 0);
ddp_input(mp, ifID);
return(0);
}
NET_ASSIGN(at_dest.atalk_net, router_net);
at_dest.atalk_node = router_node;
addr_flag = AT_ADDR_NO_LOOP;
addr = (char *)&at_dest;
dPrintf(D_M_DDP_LOW, D_L_ROUTING_AT,
("ddp_r_output: AT_ADDR out port=%d net %d:%d via rte %d:%d",
ifID->ifPort, NET_VALUE(ddp->dst_net), ddp->dst_node, router_net,
router_node));
break;
case ET_ADDR :
addr_flag = ET_ADDR;
addr = (char *)enet_addr;
dPrintf(D_M_DDP_LOW, D_L_ROUTING,
("ddp_r_output: ET_ADDR out port=%d net %d:%d\n",
ifID->ifPort, NET_VALUE(ddp->dst_net), ddp->dst_node));
break;
}
if (ifID->ifState == LAP_OFFLINE) {
gbuf_freel(mp);
return 0;
}
fillin_pkt_chain(mp);
{
struct etalk_addr dest_addr;
struct atalk_addr dest_at_addr;
int loop = TRUE;
m = mp;
if (addr == NULL) {
addr_flag = *(u_char *)gbuf_rptr(m);
gbuf_rinc(m,1);
}
switch (addr_flag) {
case AT_ADDR_NO_LOOP :
loop = FALSE;
case AT_ADDR :
if (addr == NULL) {
dest_at_addr = *(struct atalk_addr *)gbuf_rptr(m);
gbuf_rinc(m,sizeof(struct atalk_addr));
} else
dest_at_addr = *(struct atalk_addr *)addr;
break;
case ET_ADDR :
if (addr == NULL) {
dest_addr = *(struct etalk_addr *)gbuf_rptr(m);
gbuf_rinc(m,sizeof(struct etalk_addr));
} else
dest_addr = *(struct etalk_addr *)addr;
break;
default :
dPrintf(D_M_DDP_LOW,D_L_ERROR,
("ddp_router_output: Unknown addr_flag = 0x%x\n", addr_flag));
gbuf_freel(m);
return 0;
}
m = gbuf_strip(m);
if (ifID->ifState == LAP_ONLINE_FOR_ZIP) {
if (zip_type_packet(m) == 0) {
gbuf_freel(m);
return 0;
}
}
ifID->stats.xmit_packets++;
ifID->stats.xmit_bytes += gbuf_msgsize(m);
snmpStats.dd_outLong++;
switch (addr_flag) {
case AT_ADDR_NO_LOOP :
case AT_ADDR :
aarp_send_data(m,ifID,&dest_at_addr, loop);
break;
case ET_ADDR :
pat_output(ifID, m, &dest_addr, 0);
break;
}
}
return(0);
}
void rt_delete(NetStop, NetStart)
unsigned short NetStop;
unsigned short NetStart;
{
RT_entry *found;
int s;
ATDISABLE(s, ddpinp_lock);
if ((found = rt_bdelete(NetStop, NetStart)) != 0) {
bzero(found, sizeof(RT_entry));
found->right = RT_table_freelist;
RT_table_freelist = found;
}
ATENABLE(s, ddpinp_lock);
}
int ddp_AURPfuncx(code, param, node)
int code;
void *param;
unsigned char node;
{
extern void rtmp_timeout();
extern void rtmp_send_port();
at_ifaddr_t *ifID;
int k;
switch (code) {
case AURPCODE_DATAPKT:
if (aurp_ifID) {
dPrintf(D_M_DDP, D_L_TRACE, ("ddp_AURPfuncx: data, 0x%x, %d\n",
(u_int) aurp_ifID, node));
ddp_input((gbuf_t *)param, aurp_ifID);
} else
gbuf_freem((gbuf_t *)param);
break;
case AURPCODE_REG:
if (!ROUTING_MODE)
return -1;
ddp_AURPsendx = (void(*)())param;
if (param) {
if (aurp_ifID)
return 0;
for (k=(IFID_HOME+1); k < IF_TOTAL_MAX; k++) {
if (ifID_table[k] == 0) {
aurp_ifID = &at_interfaces[k];
aurp_ifID->ifFlags = RTR_XNET_PORT;
ddp_add_if(aurp_ifID);
aurp_ifID->ifState = LAP_ONLINE;
aurp_ifID->ifRoutingState = PORT_ONLINE;
dPrintf(D_M_DDP, D_L_TRACE,
("ddp_AURPfuncx: on, 0x%x\n",
(u_int) aurp_ifID));
ddp_AURPsendx(AURPCODE_DEBUGINFO,
&dbgBits, aurp_ifID->ifPort);
return 0;
}
}
return -1;
} else {
if (aurp_ifID) {
rtmp_purge(aurp_ifID);
ddp_rem_if(aurp_ifID);
aurp_ifID->ifState = LAP_OFFLINE;
aurp_ifID->ifRoutingState = PORT_OFFLINE;
dPrintf(D_M_DDP, D_L_TRACE,
("ddp_AURPfuncx: off, 0x%x\n", (u_int) aurp_ifID));
aurp_ifID = 0;
}
}
break;
case AURPCODE_AURPPROTO:
if (aurp_ifID) {
aurp_ifID->ifFlags |= AT_IFF_AURP;
}
break;
}
return 0;
}
at_ifaddr_t *forUs(ddp)
register at_ddp_t *ddp;
{
at_ifaddr_t *ifID;
TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) {
if ((ddp->dst_node == ifID->ifThisNode.s_node) &&
(NET_VALUE(ddp->dst_net) == ifID->ifThisNode.s_net)
) {
dPrintf(D_M_DDP_LOW, D_L_ROUTING,
("pkt was for port %d\n", ifID->ifPort));
return(ifID);
}
}
return((at_ifaddr_t *)NULL);
}