#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <netat/appletalk.h>
#include <netat/atp.h>
#include <netat/ddp.h>
#include "at_proto.h"
#define SET_ERRNO(e) errno = e
#define atpBDSsize (sizeof(struct atpBDS)*ATP_TRESP_MAX)
int at_send_nowait_request(fd,treq_buff)
int fd;
at_atpreq *treq_buff;
{
int status;
char buff[640+atpBDSsize];
int i, len;
struct atp_set_default *pp;
struct atpBDS *atpBDS;
at_atp_t *atp;
at_ddp_t *ddp;
len = treq_buff->at_atpreq_treq_length +
sizeof(struct atp_set_default) + TOTAL_ATP_HDR_SIZE + atpBDSsize;
(void) memset (buff, 0, len);
atpBDS = (struct atpBDS *)buff;
for (i = 0; i < ATP_TRESP_MAX; i++) {
UAL_ASSIGN(atpBDS[i].bdsBuffAddr, 1);
UAS_ASSIGN(atpBDS[i].bdsBuffSz, ATP_DATA_SIZE);
}
if ((*treq_buff).at_atpreq_type != ATP_CMD_TREQ) {
SET_ERRNO(EINVAL);
return(-1);
}
if (!(1 < (*treq_buff).at_atpreq_to.socket &&
(*treq_buff).at_atpreq_to.socket <= 254)) {
SET_ERRNO(EINVAL);
return(-1);
}
if (!((*treq_buff).at_atpreq_treq_length <= ATP_DATA_SIZE)) {
SET_ERRNO(EMSGSIZE);
return(-1);
}
pp = (struct atp_set_default *)&buff[atpBDSsize];
pp->def_retries = (int)treq_buff->at_atpreq_maximum_retries;
pp->def_rate = (int)treq_buff->at_atpreq_retry_timeout*100;
pp->def_bdsp = (struct atpBDS *)1;
pp->def_BDSlen = sizeof (struct atpBDS) * ATP_TRESP_MAX;
ddp = (at_ddp_t *)(&buff[sizeof(struct atp_set_default)+atpBDSsize]);
NET_ASSIGN(ddp->dst_net, treq_buff->at_atpreq_to.net);
ddp->dst_node = treq_buff->at_atpreq_to.node;
ddp->dst_socket = treq_buff->at_atpreq_to.socket;
atp = ATP_ATP_HDR(&buff[sizeof(struct atp_set_default)+atpBDSsize]);
atp->xo = treq_buff->at_atpreq_xo;
atp->xo_relt = treq_buff->at_atpreq_xo_relt;
atp->bitmap = treq_buff->at_atpreq_treq_bitmap;
UAL_UAL(atp->user_bytes, treq_buff->at_atpreq_treq_user_bytes);
(void) memcpy((char *)atp->data,
(char *)treq_buff->at_atpreq_treq_data,
treq_buff->at_atpreq_treq_length);
while ((status = ATPsndreq(fd, buff, len, 1)) < 0) {
if (errno == EINTR || errno == EAGAIN)
continue;
perror("ATPsndreq");
return -1;
}
treq_buff->at_atpreq_tid = status;
return 0;
}
int at_send_request(fd,treq_buff)
int fd;
at_atpreq *treq_buff;
{
int status;
char buff[640+atpBDSsize];
int i, len;
struct atp_set_default *pp;
struct atpBDS *atpBDS;
register struct atpBDS *newbdsp;
register int newcount;
at_atp_t *atp;
at_ddp_t *ddp;
len = treq_buff->at_atpreq_treq_length +
sizeof(struct atp_set_default) + TOTAL_ATP_HDR_SIZE + atpBDSsize;
(void) memset (buff, 0, len);
atpBDS = (struct atpBDS *)buff;
for (i = 0; i < ATP_TRESP_MAX; i++) {
UAL_ASSIGN(atpBDS[i].bdsBuffAddr,
(long) treq_buff->at_atpreq_tresp_data[i]);
UAS_ASSIGN(atpBDS[i].bdsBuffSz, treq_buff->at_atpreq_tresp_lengths[i]);
}
if ((*treq_buff).at_atpreq_type != ATP_CMD_TREQ) {
SET_ERRNO(EINVAL);
return(-1);
}
if (!(1 < (*treq_buff).at_atpreq_to.socket &&
(*treq_buff).at_atpreq_to.socket <= 254)) {
SET_ERRNO(EINVAL);
return(-1);
}
if (!((*treq_buff).at_atpreq_treq_length <= ATP_DATA_SIZE)) {
SET_ERRNO(EMSGSIZE);
return(-1);
}
pp = (struct atp_set_default *)&buff[atpBDSsize];
pp->def_retries = (int)treq_buff->at_atpreq_maximum_retries;
pp->def_rate = (int)treq_buff->at_atpreq_retry_timeout*100;
pp->def_bdsp = (struct atpBDS *)1;
pp->def_BDSlen = sizeof (struct atpBDS) * ATP_TRESP_MAX;
ddp = (at_ddp_t *)(&buff[sizeof(struct atp_set_default)+atpBDSsize]);
NET_ASSIGN(ddp->dst_net, treq_buff->at_atpreq_to.net);
ddp->dst_node = treq_buff->at_atpreq_to.node;
ddp->dst_socket = treq_buff->at_atpreq_to.socket;
atp = ATP_ATP_HDR(&buff[sizeof(struct atp_set_default)+atpBDSsize]);
atp->xo = treq_buff->at_atpreq_xo;
atp->xo_relt = treq_buff->at_atpreq_xo_relt;
atp->bitmap = treq_buff->at_atpreq_treq_bitmap;
UAL_UAL(atp->user_bytes, treq_buff->at_atpreq_treq_user_bytes);
(void) memcpy((char *)atp->data,
(char *)treq_buff->at_atpreq_treq_data,
treq_buff->at_atpreq_treq_length);
while ((status = ATPsndreq(fd, buff, len, 0)) < 0) {
if (errno == EINTR || errno == EAGAIN)
continue;
perror("ATPsndreq");
return -1;
}
treq_buff->at_atpreq_tid = status;
newbdsp = (struct atpBDS *)buff;
newcount = UAS_VALUE(newbdsp->bdsBuffSz);
status = 0;
if (newcount > 0) {
treq_buff->at_atpreq_tresp_bitmap = (1 << newcount) - 1;
treq_buff->at_atpreq_tresp_eom_seqno = newcount-1;
for (i = 0; i < newcount; i++) {
UAL_UAL(treq_buff->at_atpreq_tresp_user_bytes[i], newbdsp->bdsUserData);
treq_buff->at_atpreq_tresp_lengths[i] =
UAS_VALUE(newbdsp->bdsDataSz);
status += UAS_VALUE(newbdsp->bdsDataSz);
newbdsp++;
}
return(status);
} else
return -1;
}
int
atp_sendreq (fd,dest,reqbuf,reqlen,userdata,xo,xo_relt,tid,resp,retry,nowait)
int fd;
at_inet_t *dest;
char *reqbuf;
int reqlen, userdata, xo, xo_relt;
u_short *tid;
at_resp_t *resp;
at_retry_t *retry;
int nowait;
{
int i;
u_char bitmap;
at_atpreq treq;
if (xo && (xo_relt&0x07 > ATP_XO_8MIN)) {
SET_ERRNO(EINVAL);
return (-1);
}
if (retry && (retry->interval <= 0)) {
SET_ERRNO(EINVAL);
return (-1);
}
if (!valid_at_addr(dest))
return (-1);
treq.at_atpreq_type = ATP_CMD_TREQ;
UAL_ASSIGN(treq.at_atpreq_treq_user_bytes, userdata);
treq.at_atpreq_to = *dest;
treq.at_atpreq_treq_data = reqbuf;
treq.at_atpreq_treq_length = reqlen;
treq.at_atpreq_treq_bitmap = resp ? resp->bitmap : 0xff;
treq.at_atpreq_xo = xo;
treq.at_atpreq_xo_relt = xo ? xo_relt : 0;
treq.at_atpreq_retry_timeout = retry ? retry->interval : ATP_DEF_INTERVAL;
treq.at_atpreq_maximum_retries = retry ? retry->retries : ATP_DEF_RETRIES;
if (resp && !nowait) {
bitmap = resp->bitmap;
for (i = 0; i < ATP_TRESP_MAX; i++) {
if (!(bitmap & (1 << i)))
continue;
if (resp->resp[i].iov_len < 0 || resp->resp[i].iov_len > ATP_DATA_SIZE) {
SET_ERRNO(EINVAL);
return (-1);
}
treq.at_atpreq_tresp_data[i] = (u_char *)resp->resp[i].iov_base;
treq.at_atpreq_tresp_lengths[i] = resp->resp[i].iov_len;
}
} else
bitmap = 0;
if (nowait) {
if (at_send_nowait_request(fd, &treq) == -1)
return(-1);
}
else {
if (at_send_request(fd, &treq) == -1)
return(-1);
}
if (tid)
*tid = treq.at_atpreq_tid;
if (nowait)
return (0);
if (resp) {
resp->bitmap = treq.at_atpreq_tresp_bitmap;
for (i = 0; i < ATP_TRESP_MAX; i++) {
if (!(bitmap & (1 << i)))
continue;
resp->userdata[i] = *(long*)treq.at_atpreq_tresp_user_bytes[i];
resp->resp[i].iov_len = treq.at_atpreq_tresp_lengths[i];
}
}
return (0);
}