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; }
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; }
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; }
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; }
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; }
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; }