#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/param.h>
#include <sys/errno.h>
#include <netat/appletalk.h>
#include <netat/ddp.h>
#include <netat/pap.h>
#include <netat/atp.h>
#define SET_ERRNO(e) errno = e
#define MSGSTR(num,str) str
extern long time();
struct pap_state *paps[NPAPSESSIONS];
int papm[NOFILE];
static int pap_active = 0;
int papfd = 0;
int pap_open2(tuple, num_tries, wait_time)
at_nbptuple_t *tuple;
int num_tries;
long wait_time;
{
int fd, k;
long tm;
int reqid;
unsigned char data[10], rdata[ATP_DATA_SIZE];
at_socket socket = 0;
struct pap_state *papp;
int i;
int status;
int userdata;
u_char *puserdata = (u_char *)&userdata;
at_resp_t resp;
at_retry_t retry;
int error;
SET_ERRNO(0);
if (tuple == NULL) {
SET_ERRNO(EINVAL);
return (-1);
}
if (_nbp_validate_entity_(&tuple->enu_entity,0,1)==0){
SET_ERRNO(EINVAL);
return (-1);
}
if (!valid_at_addr(&tuple->enu_addr))
return(-1);
pap_status_update("=", PAP_SOCKERR, strlen(PAP_SOCKERR));
for (i = 0; i < pap_active; i++)
if (paps[i] == (struct pap_state *)0)
break;
if (i == pap_active)
if (pap_active < NPAPSESSIONS) {
pap_active++;
} else
return -1;
fd = atp_open(&socket);
if (fd < 0)
return(-1);
tm = time(NULL);
srand(tm);
if ((paps[i] =
(struct pap_state *)malloc(sizeof(struct pap_state))) == 0) {
atp_close(fd);
return -1;
}
papm[fd] = i;
papp = paps[i];
papp->pap_req_socket = socket;
papp->pap_inuse = 1;
papp->pap_tickle = 0;
papp->pap_send_count = 0;
papp->pap_rcv_count = 0;
papp->pap_request = 0;
papp->pap_error = 0;
papp->pap_eof = 0;
papp->pap_eof_sent = 0;
papp->pap_read_ignore = 0;
papp->pap_closing = 0;
papp->pap_connID = 0xffff;
papp->pap_timer = 0;
papp->pap_ending = 0;
papp->pap_request_count = 0;
papp->pap_req_timer = 0;
strcpy(&rdata[5], MSGSTR(M_NO_PRINTERS, "No Printers"));
rdata[4] = strlen(&rdata[5]);
reqid = (rand()&0xff) | 0x01;
puserdata[0] = reqid;
puserdata[1] = AT_PAP_TYPE_OPEN_CONN;
puserdata[2] = 0;
puserdata[3] = 0;
retry.interval = 2;
retry.retries = 5;
resp.bitmap = 0x01;
resp.resp[0].iov_base = rdata;
resp.resp[0].iov_len = sizeof(rdata);
i = time(NULL) - tm + wait_time;
data[0] = socket;
data[1] = 8;
data[2] = i>>8;
data[3] = i & 0xff;
for (k=0; k < num_tries; k++) {
status = atp_sendreq(fd, &tuple->enu_addr, data, 4, userdata, 1, 0, 0,
&resp, &retry, 0);
if (status >= 0) {
error = 0;
SET_ERRNO(0);
if (*(short *)&rdata[2] != 0) {
pap_status_update(tuple->enu_entity.type.str,
&rdata[5], rdata[4]&0xff);
error = ECONNREFUSED;
SET_ERRNO(ECONNREFUSED);
if (rdata[1] == 8) {
sleep(1);
i = time(NULL) - tm + wait_time;
data[2] = i>>8;
data[3] = i & 0xff;
continue;
}
goto bad;
}
puserdata = (u_char *)&resp.userdata[0];
if ((puserdata[0]&0xff) != reqid){
error = EINVAL;
SET_ERRNO(EINVAL);
goto bad;
}
if (puserdata[1] !=
AT_PAP_TYPE_OPEN_CONN_REPLY) {
error = EINVAL;
SET_ERRNO(EINVAL);
goto bad;
}
break;
} else {
strcpy(&rdata[5], MSGSTR(M_UNREACH,"Destination unreachable"));
rdata[4] = strlen(&rdata[5]);
error = ECONNREFUSED;
SET_ERRNO(ECONNREFUSED);
}
}
pap_status_update(tuple->enu_entity.type.str, &rdata[5],
rdata[4]&0xff);
if (error)
goto bad;
papp->pap_to.net = tuple->enu_addr.net;
papp->pap_to.node = tuple->enu_addr.node;
papp->pap_to.socket = rdata[0];
papp->pap_connID = reqid;
papp->pap_flow = rdata[1];
if (pap_start_tickle(fd, papp) < 0)
goto bad;
return(fd);
bad:
free(papp);
paps[papm[fd]] = (struct pap_state *)0;
atp_close(fd);
return(-1);
}
int pap_open(tuple)
at_nbptuple_t *tuple;
{
return pap_open2(tuple, 10, 0);
}
void
pap_timeout(n) {
struct pap_state *papp = paps[papm[papfd]];
if (papp == NULL)
return;
if (papp->pap_closing)
papp->pap_inuse = 0;
papp->pap_closing = 1;
pap_close(papfd);
}
int
pap_start_tickle(fd, papp)
int fd;
struct pap_state *papp;
{
int err;
if ((err = pap_send_request(fd, papp, AT_PAP_TYPE_TICKLE, 0, 0)) < 0) {
papp->pap_tickle = 0;
return -1;
} else {
papp->pap_tickle_id = err;
papp->pap_tickle = 1;
}
papfd = fd;
if (!papp->pap_timer) {
signal(SIGALRM, pap_timeout);
alarm(PAP_TIMEOUT);
papp->pap_timer = 1;
}
return 0;
}
int
pap_send_request(fd, papp, function, xo, seqno)
int fd;
struct pap_state *papp;
int function, xo, seqno;
{
u_short tid;
int err;
sigset_t sv, osv;
int userdata;
u_char *puserdata = (u_char *)&userdata;
at_inet_t dest;
at_retry_t retry;
at_resp_t resp;
dest = papp->pap_to;
puserdata[0] = papp->pap_connID;
puserdata[1] = function;
resp.bitmap = seqno;
retry.interval = 10;
retry.retries = -1;
if (seqno) {
papp->pap_send_count++;
if (papp->pap_send_count == 0)
papp->pap_send_count = 1;
*(u_short *)&puserdata[2] = htons(papp->pap_send_count);
} else
*(u_short *)&puserdata[2] = 0;
sigemptyset(&sv);
sigaddset(&sv, SIGIO);
(void) sigprocmask(SIG_SETMASK, &sv, &osv);
err = atp_sendreq(fd, &dest, 0, 0, userdata, xo, 0, &tid, &resp, &retry, 1);
(void) sigprocmask(SIG_SETMASK, &osv, NULL);
return (int)tid;
}