/* atmequal.c - Compares ATM addresses for equality */

/* Written 1995,1996 by Werner Almesberger, EPFL-LRC */


#include <string.h>
#include <assert.h>
#include <sys/socket.h>
#include <linux/atm.h>

#include "atm.h"


int atm_equal(const struct sockaddr_atmsvc *a,const struct sockaddr_atmsvc *b,
  int len,int flags)
{
    const unsigned char *a_prv,*b_prv;
    int len_a,len_b;

    assert(a->sas_family == AF_ATMSVC && b->sas_family == AF_ATMSVC);
    if (!(flags & AXE_WILDCARD)) len = ATM_ESA_LEN*8;
    assert(len >= 0 && len <= ATM_ESA_LEN*8);
    if (*a->sas_addr.prv && *b->sas_addr.prv) {
	a_prv = a->sas_addr.prv;
	b_prv = b->sas_addr.prv;
	if ((flags & AXE_WILDCARD) && len >= 8 && *a_prv == ATM_AFI_E164 &&
	  *b_prv == ATM_AFI_E164)
	    if (len < 68) return 0; /* no comparison possible */
	    else {
		int a_pos,b_pos;
		unsigned char a_val,b_val;

		for (a_pos = 2; !a_prv[a_pos/2]; a_pos += 2);
		if (!(a_prv[a_pos/2] & 0xf0)) a_pos++;
		for (b_pos = 2; !b_prv[b_pos/2]; b_pos += 2);
		if (!(b_prv[b_pos/2] & 0xf0)) b_pos++;
		while (1) {
		    a_val = (a_prv[a_pos/2] >> (((~a_pos) & 1)*4)) & 0xf;
		    b_val = (b_prv[b_pos/2] >> (((~b_pos) & 1)*4)) & 0xf;
		    if (a_val == 15 || b_val == 15) break;
		    if (a_val != b_val) return 0;
		}
		a_prv += 9;
		b_prv += 9;
		if ((len -= 72) < 0) len = 0;
	    }
	if (memcmp(a_prv,b_prv,len/8)) return 0;
	if ((len & 7) && (a_prv[len/8+1]^b_prv[len/8+1]) &
	  (0xff00 >> (len & 7))) return 0;
	return 1;
    }
    if ((*a->sas_addr.prv || *b->sas_addr.prv) && !(flags & AXE_PRVOPT))
	return 0;
    if (!*a->sas_addr.pub || !*b->sas_addr.pub) return 0;
    len_a = strlen(a->sas_addr.pub);
    len_b = strlen(b->sas_addr.pub);
    if (len_a != len_b && !(flags & AXE_WILDCARD)) return 0;
    return !strncmp(a->sas_addr.pub,b->sas_addr.pub,len_a < len_b ? len_a :
      len_b);
}
