Пример #1
0
void add_route(SIG_ENTITY *sig,struct sockaddr_atmsvc *addr,int len)
{
    ROUTE *route;

    for (route = routes; route; route = route->next)
        if (route->len == len && (!len || atm_equal((struct sockaddr *) addr,
          (struct sockaddr *) &route->addr,len,
          AXE_PRVOPT | (len == INT_MAX ? 0 : AXE_WILDCARD))))
            diag(COMPONENT,DIAG_FATAL,"duplicate route");
    route = alloc_t(ROUTE);
    if (addr) route->addr = *addr;
    route->len = len;
    route->sig = sig;
    route->next = routes;
    routes = route;
}
Пример #2
0
SIG_ENTITY *route_remote(struct sockaddr_atmsvc *addr)
{
    ROUTE *best,*route;
    int best_len;

    if (!routes) return entities;
    best = NULL;
    best_len = -1;
    for (route = routes; route; route = route->next)
        if (route->len > best_len && (!route->len ||
          atm_equal((struct sockaddr *) addr,(struct sockaddr *) &route->addr,
          route->len,
          AXE_PRVOPT | (route->len == INT_MAX ? 0 : AXE_WILDCARD)))) {
            if (route->len == INT_MAX) return route->sig;
            best_len = route->len;
            best = route;
        }
    return best ? best->sig : NULL;
}
Пример #3
0
int sap_compat(const struct sockaddr_atmsvc *old_addr,
  const struct sockaddr_atmsvc *new_addr,struct sockaddr_atmsvc *res_addr,
  const struct atm_sap *old_sap,const struct atm_sap *new_sap,
  struct atm_sap *res_sap,const struct atm_qos *old_qos,
  const struct atm_qos *new_qos,struct atm_qos *res_qos)
{
    if (atmsvc_addr_in_use(*old_addr) &&
      !atm_equal((struct sockaddr *) old_addr,(struct sockaddr *) new_addr,0,0))
	return 0;
    if (res_qos) *res_qos = *new_qos;
    if (old_qos->txtp.max_sdu && new_qos->rxtp.max_sdu &&
      old_qos->txtp.max_sdu > new_qos->rxtp.max_sdu) return 0;
    if (new_qos->txtp.max_sdu && old_qos->rxtp.max_sdu &&
      new_qos->txtp.max_sdu > old_qos->rxtp.max_sdu) return 0;
    if (!class_compat(&old_qos->txtp,&new_qos->rxtp) ||
      !class_compat(&new_qos->txtp,&old_qos->rxtp)) return 0;
    if (!sap_equal(old_sap,new_sap,
      SXE_COMPATIBLE | SXE_NEGOTIATION | (res_sap ? SXE_RESULT : 0),res_sap))
	return 0;
    return 1;
}
Пример #4
0
SIG_ENTITY *route_local(struct sockaddr_atmsvc *addr)
{
    SIG_ENTITY *sig;
    VPCI *vpci;
    LOCAL_ADDR *walk;

    /*
     * @@@ This is quite close to the truth but still not entirely correct:
     * the actual result should be the VPCI to use. While this is irrelevant
     * when the connection identifier is assigned by the peer, the VPI
     * selection should be based on the VPCI we find here if it's atmsigd who
     * assigns the connection identifier. The bottom line is that VPI > 0 plus
     * connection identifier assignment by atmsigd doesn't work yet.
     */
    for (sig = entities; sig; sig = sig->next)
	for (vpci = sig->vpcis; vpci; vpci = vpci->next)
	    for (walk = vpci->local_addr; walk->state != ls_unused; walk++)
		if (walk->state == ls_same && atm_equal((struct sockaddr *)
		  &walk->addr,(struct sockaddr *) addr,(ATM_ESA_LEN-1)*8,
		  AXE_WILDCARD))
		    return sig;
    return NULL;
}
Пример #5
0
int get_addr(int itf,LOCAL_ADDR *local_addr)
{
    struct atmif_sioc req;
    struct sockaddr_atmsvc buffer[MAX_LOCAL_ADDRS];
    LOCAL_ADDR *from,*to;
    int addrs,i;

    for (from = to = local_addr; from->state != ls_unused; from++)
	if (from->state != ls_removed) {
	    from->state = ls_removed;
	    *to++ = *from;
	}
    to->state = ls_unused;
    req.number = itf;
    req.arg = buffer;
    req.length = sizeof(buffer);
    if (ioctl(entities->signaling,ATM_GETADDR,&req) < 0)
	diag(COMPONENT,DIAG_FATAL,"ioctl ATM_GETADDR yields \"%s\"",
	  strerror(errno));
    addrs = req.length/sizeof(struct sockaddr_atmsvc);
    for (i = 0; i < addrs; i++) {
	for (from = local_addr; from->state != ls_unused; from++)
	    if (atm_equal((struct sockaddr *) (buffer+i),
	      (struct sockaddr *) &from->addr,0,0)) break;
	if (from->state != ls_unused) from->state = ls_same;
	else if (to == local_addr+MAX_LOCAL_ADDRS-1)
		diag(COMPONENT,DIAG_WARN,"local address table overflow");
	    else {
		to->state = ls_added;
		to->addr = buffer[i];
		to++;
		to->state = ls_unused;
	    }
    }
    return addrs;
}
Пример #6
0
static int learn(VCC *vcc,uint32_t ip,struct sockaddr_atmsvc *addr)
{
    ENTRY *entry;
    ITF *itf;
    VCC *walk,*next;
    unsigned char *ipp;
    int result = 0;

    if (!ip) return 0;
    ipp = (unsigned char *) &ip;
    itf = lookup_itf_by_ip(ip);
    if (!itf) {
	diag(COMPONENT,DIAG_ERROR,"got unroutable IP address %d.%d.%d.%d",
	  ipp[0],ipp[1],ipp[2],ipp[3]);
	return 0;
    }
    entry = lookup_ip(itf,ip);
    assert(!vcc || vcc->entry);
    /*
     * If the entry on which we received the update isn't dangling but it
     * doesn't correspond to the one with the address, ...
     */
    if (entry && vcc && vcc->entry->itf && entry != vcc->entry) {
	diag(COMPONENT,DIAG_DEBUG,"collision on %d.%d.%d.%d",ipp[0],ipp[1],
	  ipp[2],ipp[3]);
	return 0;
    }
    /*
     * If the entry on which we received the update is dangling and we found
     * an entry that already describes that IP address, ...
     */
    if (entry && vcc && !vcc->entry->itf) {
	if (!entry->svc) {
	    diag(COMPONENT,DIAG_ERROR,"attempt to overwrite PVC for IP "
	      "%d.%d.%d.%d",ipp[0],ipp[1],ipp[2],ipp[3]);
	    return 0;
	}
	STOP_TIMER(vcc->entry);
	Q_REMOVE(unknown_incoming,vcc->entry);
	free(vcc->entry);
	vcc->entry = entry;
	Q_INSERT_HEAD(entry->vccs,vcc);
	set_sndbuf(vcc);
	entry->flags &= ~ATF_NOVC;
	assert(!vcc->connecting);
	if (set_ip(vcc->fd,ip) < 0) {
	    diag(COMPONENT,DIAG_ERROR,"set_ip: %s",strerror(errno));
	    disconnect_vcc(vcc);
	    vcc = NULL;
	    result = -1;
	}
    }
    /*
     * If we still don't have an entry, we try to use the entry that already
     * belongs to the VCC (InARP), or we create a new one (ARP).
     */
    if (!entry) {
	if (vcc) {
	    entry = vcc->entry;
	    if (!entry->itf) {
		Q_REMOVE(unknown_incoming,entry);
		entry->sndbuf = itf->sndbuf;
		set_sndbuf(vcc);
	    }
	    else if (entry->ip && entry->ip != ip && (entry->flags & ATF_PERM)
		  && !(entry->flags & ATF_ARPSRV)) {
		    diag(COMPONENT,DIAG_ERROR,"ignoring attempt to change IP "
		      "address of permanent entry (to %d.%d.%d.%d)",ipp[0],
		      ipp[1],ipp[2],ipp[3]);
		    return result;
		}
	}
	else {
	    entry = alloc_entry(1);
	    entry->flags = ATF_PUBL;
	}
    }
    if (!atmsvc_addr_in_use(*addr)) addr = NULL;
    if (entry->addr && addr && (entry->flags & ATF_PERM) &&
      !atm_equal((struct sockaddr *) entry->addr,(struct sockaddr *) addr,0,0))
      {
	diag(COMPONENT,DIAG_ERROR,"ignoring attempt to change ATM address of "
	  "permanent entry");
	return result;
    }
    if (entry->state == as_valid && entry->ip == ip && (!addr || (entry->addr
      && atm_equal((struct sockaddr *) entry->addr,(struct sockaddr *) addr,0,
      0)))) return result; /* no news */
    STOP_TIMER(entry);
    if (entry->ip != ip) send_notifications(entry,0);
    entry->ip = ip;
    if (!entry->itf) {
	entry->itf = itf;
	/* @@@
	 * Need to fix this is in case we allow entries without a valid IP
	 * address but with a pre-set QOS, e.g. a VC on a given PVC with an
	 * unknown remote end.
	 */
	entry->qos = entry->itf->qos;
	adjust_qos(entry->itf,&entry->qos,0);
	Q_INSERT_HEAD(itf->table,entry);
    }
    if (entry->itf != itf)
	diag(COMPONENT,DIAG_ERROR,"interesting, interface has changed ... "
	  "(%d -> %d)",entry->itf->number,itf->number);
    if (addr) {
	if (!entry->addr) entry->addr = alloc(sizeof(*addr));
	*entry->addr = *addr;
	if (merge) {
	    ENTRY *incoming;

	    while ((incoming = lookup_incoming(addr))) {
		STOP_TIMER(incoming);
		Q_REMOVE(unknown_incoming,incoming);
		incoming->vccs->entry = entry;
		Q_INSERT_HEAD(entry->vccs,incoming->vccs);
		set_sndbuf(incoming->vccs);
		free(incoming);
	    }
	}
    }
    for (walk = entry->vccs; walk; walk = next) {
	next = walk->next;
	if (!walk->connecting)
	    if (set_ip(walk->fd,ip) < 0) {
		diag(COMPONENT,DIAG_ERROR,"set_ip: %s",strerror(errno));
		disconnect_vcc(walk);
		if (walk == vcc) result = -1;
	    }
    }
    if (entry->state != as_valid) {
	if (!entry->vccs && itf->arp_srv && !(entry->flags & ATF_NOVC))
	    connect_me(entry);
	send_notifications(entry,1);
    }
    if ((entry->flags & ATF_ARPSRV) || !(entry->flags & ATF_PERM)) {
	if (entry->itf->arp_srv) START_TIMER(entry,CREVAL);
	else START_TIMER(entry,SREVAL);
    }
    entry->state = as_valid;
    return result;
}