ATM cell alignment.

Introducing the function that does the ATM cell alignment, and
modifying tc_calc_rtable() to use this based upon a linklayer
parameter.

Modified from original to use constants from atm.h and
fix all the usages of rtable in same patch.

Signed-off-by: Jesper Dangaard Brouer <hawk@comx.dk>
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
diff --git a/include/linux/atm.h b/include/linux/atm.h
new file mode 100644
index 0000000..593e6c1
--- /dev/null
+++ b/include/linux/atm.h
@@ -0,0 +1,238 @@
+/* atm.h - general ATM declarations */
+ 
+/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
+ 
+
+/*
+ * WARNING: User-space programs should not #include <linux/atm.h> directly.
+ *          Instead, #include <atm.h>
+ */
+
+#ifndef _LINUX_ATM_H
+#define _LINUX_ATM_H
+
+/*
+ * BEGIN_xx and END_xx markers are used for automatic generation of
+ * documentation. Do not change them.
+ */
+
+#include <linux/atmapi.h>
+#include <linux/atmsap.h>
+#include <linux/atmioc.h>
+
+
+/* general ATM constants */
+#define ATM_CELL_SIZE		    53	/* ATM cell size incl. header */
+#define ATM_CELL_PAYLOAD	    48	/* ATM payload size */
+#define ATM_AAL0_SDU		    52	/* AAL0 SDU size */
+#define ATM_MAX_AAL34_PDU	 65535	/* maximum AAL3/4 PDU payload */
+#define ATM_AAL5_TRAILER	     8	/* AAL5 trailer size */
+#define ATM_MAX_AAL5_PDU	 65535	/* maximum AAL5 PDU payload */
+#define ATM_MAX_CDV		  9999	/* maximum (default) CDV */
+#define ATM_NOT_RSV_VCI		    32	/* first non-reserved VCI value */
+
+#define ATM_MAX_VPI		   255	/* maximum VPI at the UNI */
+#define ATM_MAX_VPI_NNI		  4096	/* maximum VPI at the NNI */
+#define ATM_MAX_VCI		 65535	/* maximum VCI */
+
+
+/* "protcol" values for the socket system call */
+#define ATM_NO_AAL	0		/* AAL not specified */
+#define ATM_AAL0	13		/* "raw" ATM cells */
+#define ATM_AAL1	1		/* AAL1 (CBR) */
+#define ATM_AAL2	2		/* AAL2 (VBR) */
+#define ATM_AAL34	3		/* AAL3/4 (data) */
+#define ATM_AAL5	5		/* AAL5 (data) */
+
+/*
+ * socket option name coding functions
+ *
+ * Note that __SO_ENCODE and __SO_LEVEL are somewhat a hack since the
+ * << 22 only reserves 9 bits for the level.  On some architectures
+ * SOL_SOCKET is 0xFFFF, so that's a bit of a problem
+ */
+
+#define __SO_ENCODE(l,n,t)	((((l) & 0x1FF) << 22) | ((n) << 16) | \
+				sizeof(t))
+#define __SO_LEVEL_MATCH(c,m)	(((c) >> 22) == ((m) & 0x1FF))
+#define __SO_NUMBER(c)		(((c) >> 16) & 0x3f)
+#define __SO_SIZE(c)		((c) & 0x3fff)
+
+/*
+ * ATM layer
+ */
+
+#define SO_SETCLP	__SO_ENCODE(SOL_ATM,0,int)
+			    /* set CLP bit value - TODO */
+#define SO_CIRANGE	__SO_ENCODE(SOL_ATM,1,struct atm_cirange)
+			    /* connection identifier range; socket must be
+			       bound or connected */
+#define SO_ATMQOS	__SO_ENCODE(SOL_ATM,2,struct atm_qos)
+			    /* Quality of Service setting */
+#define SO_ATMSAP	__SO_ENCODE(SOL_ATM,3,struct atm_sap)
+			    /* Service Access Point */
+#define SO_ATMPVC	__SO_ENCODE(SOL_ATM,4,struct sockaddr_atmpvc)
+			    /* "PVC" address (also for SVCs); get only */
+#define SO_MULTIPOINT	__SO_ENCODE(SOL_ATM, 5, int)
+			    /* make this vc a p2mp */
+
+
+/*
+ * Note @@@: since the socket layers don't really distinguish the control and
+ * the data plane but generally seems to be data plane-centric, any layer is
+ * about equally wrong for the SAP. If you have a better idea about this,
+ * please speak up ...
+ */
+
+
+/* ATM cell header (for AAL0) */
+
+/* BEGIN_CH */
+#define ATM_HDR_GFC_MASK	0xf0000000
+#define ATM_HDR_GFC_SHIFT	28
+#define ATM_HDR_VPI_MASK	0x0ff00000
+#define ATM_HDR_VPI_SHIFT	20
+#define ATM_HDR_VCI_MASK	0x000ffff0
+#define ATM_HDR_VCI_SHIFT	4
+#define ATM_HDR_PTI_MASK	0x0000000e
+#define ATM_HDR_PTI_SHIFT	1
+#define ATM_HDR_CLP		0x00000001
+/* END_CH */
+
+
+/* PTI codings */
+
+/* BEGIN_PTI */
+#define ATM_PTI_US0	0  /* user data cell, congestion not exp, SDU-type 0 */
+#define ATM_PTI_US1	1  /* user data cell, congestion not exp, SDU-type 1 */
+#define ATM_PTI_UCES0	2  /* user data cell, cong. experienced, SDU-type 0 */
+#define ATM_PTI_UCES1	3  /* user data cell, cong. experienced, SDU-type 1 */
+#define ATM_PTI_SEGF5	4  /* segment OAM F5 flow related cell */
+#define ATM_PTI_E2EF5	5  /* end-to-end OAM F5 flow related cell */
+#define ATM_PTI_RSV_RM	6  /* reserved for traffic control/resource mgmt */
+#define ATM_PTI_RSV	7  /* reserved */
+/* END_PTI */
+
+
+/*
+ * The following items should stay in linux/atm.h, which should be linked to
+ * netatm/atm.h
+ */
+
+/* Traffic description */
+
+#define ATM_NONE	0		/* no traffic */
+#define ATM_UBR		1
+#define ATM_CBR		2
+#define ATM_VBR		3
+#define ATM_ABR		4
+#define ATM_ANYCLASS	5		/* compatible with everything */
+
+#define ATM_MAX_PCR	-1		/* maximum available PCR */
+
+struct atm_trafprm {
+	unsigned char	traffic_class;	/* traffic class (ATM_UBR, ...) */
+	int		max_pcr;	/* maximum PCR in cells per second */
+	int		pcr;		/* desired PCR in cells per second */
+	int		min_pcr;	/* minimum PCR in cells per second */
+	int		max_cdv;	/* maximum CDV in microseconds */
+	int		max_sdu;	/* maximum SDU in bytes */
+        /* extra params for ABR */
+        unsigned int 	icr;         	/* Initial Cell Rate (24-bit) */
+        unsigned int	tbe;		/* Transient Buffer Exposure (24-bit) */ 
+        unsigned int 	frtt : 24;	/* Fixed Round Trip Time (24-bit) */
+        unsigned int 	rif  : 4;       /* Rate Increment Factor (4-bit) */
+        unsigned int 	rdf  : 4;       /* Rate Decrease Factor (4-bit) */
+        unsigned int nrm_pres  :1;      /* nrm present bit */
+        unsigned int trm_pres  :1;     	/* rm present bit */
+        unsigned int adtf_pres :1;     	/* adtf present bit */
+        unsigned int cdf_pres  :1;    	/* cdf present bit*/
+        unsigned int nrm       :3;     	/* Max # of Cells for each forward RM cell (3-bit) */
+        unsigned int trm       :3;    	/* Time between forward RM cells (3-bit) */    
+	unsigned int adtf      :10;     /* ACR Decrease Time Factor (10-bit) */
+	unsigned int cdf       :3;      /* Cutoff Decrease Factor (3-bit) */
+        unsigned int spare     :9;      /* spare bits */ 
+};
+
+struct atm_qos {
+	struct atm_trafprm txtp;	/* parameters in TX direction */
+	struct atm_trafprm rxtp __ATM_API_ALIGN;
+					/* parameters in RX direction */
+	unsigned char aal __ATM_API_ALIGN;
+};
+
+/* PVC addressing */
+
+#define ATM_ITF_ANY	-1		/* "magic" PVC address values */
+#define ATM_VPI_ANY	-1
+#define ATM_VCI_ANY	-1
+#define ATM_VPI_UNSPEC	-2
+#define ATM_VCI_UNSPEC	-2
+
+
+struct sockaddr_atmpvc {
+	unsigned short 	sap_family;	/* address family, AF_ATMPVC  */
+	struct {			/* PVC address */
+		short	itf;		/* ATM interface */
+		short	vpi;		/* VPI (only 8 bits at UNI) */
+		int	vci;		/* VCI (only 16 bits at UNI) */
+	} sap_addr __ATM_API_ALIGN;	/* PVC address */
+};
+
+/* SVC addressing */
+
+#define	ATM_ESA_LEN	20		/* ATM End System Address length */
+#define ATM_E164_LEN	12		/* maximum E.164 number length */
+
+#define ATM_AFI_DCC	0x39		/* DCC ATM Format */
+#define ATM_AFI_ICD	0x47		/* ICD ATM Format */
+#define ATM_AFI_E164	0x45		/* E.164 ATM Format */
+#define ATM_AFI_LOCAL	0x49		/* Local ATM Format */ 
+
+#define ATM_AFI_DCC_GROUP	0xBD	/* DCC ATM Group Format */
+#define ATM_AFI_ICD_GROUP	0xC5	/* ICD ATM Group Format */
+#define ATM_AFI_E164_GROUP	0xC3	/* E.164 ATM Group Format */
+#define ATM_AFI_LOCAL_GROUP	0xC7	/* Local ATM Group Format */
+
+#define ATM_LIJ_NONE	0		/* no leaf-initiated join */
+#define ATM_LIJ		1		/* request joining */
+#define ATM_LIJ_RPJ	2		/* set to root-prompted join */
+#define ATM_LIJ_NJ	3		/* set to network join */
+
+
+struct sockaddr_atmsvc {
+    unsigned short 	sas_family;	/* address family, AF_ATMSVC */
+    struct {				/* SVC address */
+        unsigned char	prv[ATM_ESA_LEN];/* private ATM address */
+        char		pub[ATM_E164_LEN+1]; /* public address (E.164) */
+    					/* unused addresses must be bzero'ed */
+	char		lij_type;	/* role in LIJ call; one of ATM_LIJ* */
+	uint32_t	lij_id;		/* LIJ call identifier */
+    } sas_addr __ATM_API_ALIGN;		/* SVC address */
+};
+
+
+static __inline__ int atmsvc_addr_in_use(struct sockaddr_atmsvc addr)
+{
+	return *addr.sas_addr.prv || *addr.sas_addr.pub;
+}
+
+
+static __inline__ int atmpvc_addr_in_use(struct sockaddr_atmpvc addr)
+{
+	return addr.sap_addr.itf || addr.sap_addr.vpi || addr.sap_addr.vci;
+}
+
+
+/*
+ * Some stuff for linux/sockios.h
+ */
+
+struct atmif_sioc {
+    int number;
+    int length;
+    void *arg;
+};
+
+typedef unsigned short atm_backend_t;
+#endif
diff --git a/include/linux/atmapi.h b/include/linux/atmapi.h
new file mode 100644
index 0000000..8fe54d9
--- /dev/null
+++ b/include/linux/atmapi.h
@@ -0,0 +1,29 @@
+/* atmapi.h - ATM API user space/kernel compatibility */
+ 
+/* Written 1999,2000 by Werner Almesberger, EPFL ICA */
+ 
+
+#ifndef _LINUX_ATMAPI_H
+#define _LINUX_ATMAPI_H
+
+#if defined(__sparc__) || defined(__ia64__)
+/* such alignment is not required on 32 bit sparcs, but we can't
+   figure that we are on a sparc64 while compiling user-space programs. */
+#define __ATM_API_ALIGN	__attribute__((aligned(8)))
+#else
+#define __ATM_API_ALIGN
+#endif
+
+
+/*
+ * Opaque type for kernel pointers. Note that _ is never accessed. We need
+ * the struct in order hide the array, so that we can make simple assignments
+ * instead of being forced to use memcpy. It also improves error reporting for
+ * code that still assumes that we're passing unsigned longs.
+ *
+ * Convention: NULL pointers are passed as a field of all zeroes.
+ */
+ 
+typedef struct { unsigned char _[8]; } __ATM_API_ALIGN atm_kptr_t;
+
+#endif
diff --git a/include/linux/atmioc.h b/include/linux/atmioc.h
new file mode 100644
index 0000000..37f67aa
--- /dev/null
+++ b/include/linux/atmioc.h
@@ -0,0 +1,41 @@
+/* atmioc.h - ranges for ATM-related ioctl numbers */
+ 
+/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */
+
+
+/*
+ * See http://icawww1.epfl.ch/linux-atm/magic.html for the complete list of
+ * "magic" ioctl numbers.
+ */
+
+
+#ifndef _LINUX_ATMIOC_H
+#define _LINUX_ATMIOC_H
+
+#include <asm/ioctl.h>
+		/* everybody including atmioc.h will also need _IO{,R,W,WR} */
+
+#define ATMIOC_PHYCOM	  0x00 /* PHY device common ioctls, globally unique */
+#define ATMIOC_PHYCOM_END 0x0f
+#define ATMIOC_PHYTYP	  0x10 /* PHY dev type ioctls, unique per PHY type */
+#define ATMIOC_PHYTYP_END 0x2f
+#define ATMIOC_PHYPRV	  0x30 /* PHY dev private ioctls, unique per driver */
+#define ATMIOC_PHYPRV_END 0x4f
+#define ATMIOC_SARCOM	  0x50 /* SAR device common ioctls, globally unique */
+#define ATMIOC_SARCOM_END 0x50
+#define ATMIOC_SARPRV	  0x60 /* SAR dev private ioctls, unique per driver */
+#define ATMIOC_SARPRV_END 0x7f
+#define ATMIOC_ITF	  0x80 /* Interface ioctls, globally unique */
+#define ATMIOC_ITF_END	  0x8f
+#define ATMIOC_BACKEND	  0x90 /* ATM generic backend ioctls, u. per backend */
+#define ATMIOC_BACKEND_END 0xaf
+/* 0xb0-0xbf: Reserved for future use */
+#define ATMIOC_AREQUIPA	  0xc0 /* Application requested IP over ATM, glob. u. */
+#define ATMIOC_LANE	  0xd0 /* LAN Emulation, globally unique */
+#define ATMIOC_MPOA       0xd8 /* MPOA, globally unique */
+#define	ATMIOC_CLIP	  0xe0 /* Classical IP over ATM control, globally u. */
+#define	ATMIOC_CLIP_END	  0xef
+#define	ATMIOC_SPECIAL	  0xf0 /* Special-purpose controls, globally unique */
+#define	ATMIOC_SPECIAL_END 0xff
+
+#endif
diff --git a/include/linux/atmsap.h b/include/linux/atmsap.h
new file mode 100644
index 0000000..799b104
--- /dev/null
+++ b/include/linux/atmsap.h
@@ -0,0 +1,162 @@
+/* atmsap.h - ATM Service Access Point addressing definitions */
+
+/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */
+
+
+#ifndef _LINUX_ATMSAP_H
+#define _LINUX_ATMSAP_H
+
+#include <linux/atmapi.h>
+
+/*
+ * BEGIN_xx and END_xx markers are used for automatic generation of
+ * documentation. Do not change them.
+ */
+
+
+/*
+ * Layer 2 protocol identifiers
+ */
+
+/* BEGIN_L2 */
+#define ATM_L2_NONE	0	/* L2 not specified */
+#define ATM_L2_ISO1745  0x01	/* Basic mode ISO 1745 */
+#define ATM_L2_Q291	0x02	/* ITU-T Q.291 (Rec. I.441) */
+#define ATM_L2_X25_LL	0x06	/* ITU-T X.25, link layer */
+#define ATM_L2_X25_ML	0x07	/* ITU-T X.25, multilink */
+#define ATM_L2_LAPB	0x08	/* Extended LAPB, half-duplex (Rec. T.71) */
+#define ATM_L2_HDLC_ARM	0x09	/* HDLC ARM (ISO/IEC 4335) */
+#define ATM_L2_HDLC_NRM	0x0a	/* HDLC NRM (ISO/IEC 4335) */
+#define ATM_L2_HDLC_ABM	0x0b	/* HDLC ABM (ISO/IEC 4335) */
+#define ATM_L2_ISO8802	0x0c	/* LAN LLC (ISO/IEC 8802/2) */
+#define ATM_L2_X75	0x0d	/* ITU-T X.75, SLP */
+#define ATM_L2_Q922	0x0e	/* ITU-T Q.922 */
+#define ATM_L2_USER	0x10	/* user-specified */
+#define ATM_L2_ISO7776	0x11	/* ISO 7776 DTE-DTE */
+/* END_L2 */
+
+
+/*
+ * Layer 3 protocol identifiers
+ */
+
+/* BEGIN_L3 */
+#define ATM_L3_NONE	0	/* L3 not specified */
+#define ATM_L3_X25	0x06	/* ITU-T X.25, packet layer */
+#define ATM_L3_ISO8208	0x07	/* ISO/IEC 8208 */
+#define ATM_L3_X223	0x08	/* ITU-T X.223 | ISO/IEC 8878 */
+#define ATM_L3_ISO8473	0x09	/* ITU-T X.233 | ISO/IEC 8473 */
+#define ATM_L3_T70	0x0a	/* ITU-T T.70 minimum network layer */
+#define ATM_L3_TR9577	0x0b	/* ISO/IEC TR 9577 */
+#define ATM_L3_H310	0x0c	/* ITU-T Recommendation H.310 */
+#define ATM_L3_H321	0x0d	/* ITU-T Recommendation H.321 */
+#define ATM_L3_USER	0x10	/* user-specified */
+/* END_L3 */
+
+
+/*
+ * High layer identifiers
+ */
+
+/* BEGIN_HL */
+#define ATM_HL_NONE	0	/* HL not specified */
+#define ATM_HL_ISO	0x01	/* ISO */
+#define ATM_HL_USER	0x02	/* user-specific */
+#define ATM_HL_HLP	0x03	/* high layer profile - UNI 3.0 only */
+#define ATM_HL_VENDOR	0x04	/* vendor-specific application identifier */
+/* END_HL */
+
+
+/*
+ * ITU-T coded mode of operation
+ */
+
+/* BEGIN_IMD */
+#define ATM_IMD_NONE	 0	/* mode not specified */
+#define ATM_IMD_NORMAL	 1	/* normal mode of operation */
+#define ATM_IMD_EXTENDED 2	/* extended mode of operation */
+/* END_IMD */
+
+/*
+ * H.310 code points
+ */
+
+#define ATM_TT_NONE	0	/* terminal type not specified */
+#define ATM_TT_RX	1	/* receive only */
+#define ATM_TT_TX	2	/* send only */
+#define ATM_TT_RXTX	3	/* receive and send */
+
+#define ATM_MC_NONE	0	/* no multiplexing */
+#define ATM_MC_TS	1	/* transport stream (TS) */
+#define ATM_MC_TS_FEC	2	/* transport stream with forward error corr. */
+#define ATM_MC_PS	3	/* program stream (PS) */
+#define ATM_MC_PS_FEC	4	/* program stream with forward error corr. */
+#define ATM_MC_H221	5	/* ITU-T Rec. H.221 */
+
+/*
+ * SAP structures
+ */
+
+#define ATM_MAX_HLI	8	/* maximum high-layer information length */
+
+
+struct atm_blli {
+    unsigned char l2_proto;	/* layer 2 protocol */
+    union {
+	struct {
+	    unsigned char mode;	/* mode of operation (ATM_IMD_xxx), 0 if */
+				/* absent */
+	    unsigned char window; /* window size (k), 1-127 (0 to omit) */
+	} itu;			/* ITU-T encoding */
+	unsigned char user;	/* user-specified l2 information */
+    } l2;
+    unsigned char l3_proto;	/* layer 3 protocol */
+    union {
+	struct {
+	    unsigned char mode;	/* mode of operation (ATM_IMD_xxx), 0 if */
+				/* absent */
+	    unsigned char def_size; /* default packet size (log2), 4-12 (0 to */
+				    /* omit) */
+	    unsigned char window;/* packet window size, 1-127 (0 to omit) */
+	} itu;			/* ITU-T encoding */
+	unsigned char user;	/* user specified l3 information */
+	struct {		      /* if l3_proto = ATM_L3_H310 */
+	    unsigned char term_type;  /* terminal type */
+	    unsigned char fw_mpx_cap; /* forward multiplexing capability */
+				      /* only if term_type != ATM_TT_NONE */
+	    unsigned char bw_mpx_cap; /* backward multiplexing capability */
+				      /* only if term_type != ATM_TT_NONE */
+	} h310;
+	struct {		  /* if l3_proto = ATM_L3_TR9577 */
+	    unsigned char ipi;	  /* initial protocol id */
+	    unsigned char snap[5];/* IEEE 802.1 SNAP identifier */
+				  /* (only if ipi == NLPID_IEEE802_1_SNAP) */
+	} tr9577;
+    } l3;
+} __ATM_API_ALIGN;
+
+
+struct atm_bhli {
+    unsigned char hl_type;	/* high layer information type */
+    unsigned char hl_length;	/* length (only if hl_type == ATM_HL_USER || */
+				/* hl_type == ATM_HL_ISO) */
+    unsigned char hl_info[ATM_MAX_HLI];/* high layer information */
+};
+
+
+#define ATM_MAX_BLLI	3		/* maximum number of BLLI elements */
+
+
+struct atm_sap {
+	struct atm_bhli bhli;		/* local SAP, high-layer information */
+	struct atm_blli blli[ATM_MAX_BLLI] __ATM_API_ALIGN;
+					/* local SAP, low-layer info */
+};
+
+
+static __inline__ int blli_in_use(struct atm_blli blli)
+{
+	return blli.l2_proto || blli.l3_proto;
+}
+
+#endif
diff --git a/tc/m_police.c b/tc/m_police.c
index e55a8c9..ace43b5 100644
--- a/tc/m_police.c
+++ b/tc/m_police.c
@@ -36,7 +36,8 @@
 {
 	fprintf(stderr, "Usage: ... police rate BPS burst BYTES[/BYTES] [ mtu BYTES[/BYTES] ]\n");
 	fprintf(stderr, "                [ peakrate BPS ] [ avrate BPS ] [ overhead BYTES ]\n");
-	fprintf(stderr, "                [ ACTIONTERM ]\n");
+	fprintf(stderr, "                [ linklayer TYPE ] [ ACTIONTERM ]\n");
+
 	fprintf(stderr, "Old Syntax ACTIONTERM := action <EXCEEDACT>[/NOTEXCEEDACT] \n");
 	fprintf(stderr, "New Syntax ACTIONTERM := conform-exceed <EXCEEDACT>[/NOTEXCEEDACT] \n");
 	fprintf(stderr, "Where: *EXCEEDACT := pipe | ok | reclassify | drop | continue \n");
@@ -134,6 +135,7 @@
 	int presult = 0;
 	unsigned buffer=0, mtu=0, mpu=0;
 	unsigned short overhead=0;
+	unsigned int linklayer = LINKLAYER_ETHERNET; /* Assume ethernet */
 	int Rcell_log=-1, Pcell_log = -1;
 	struct rtattr *tail;
 
@@ -240,6 +242,11 @@
 			if (get_u16(&overhead, *argv, 10)) {
 				explain1("overhead"); return -1;
 			}
+		} else if (matches(*argv, "linklayer") == 0) {
+			NEXT_ARG();
+			if (get_linklayer(&linklayer, *argv)) {
+				explain1("linklayer"); return -1;
+			}
 		} else if (strcmp(*argv, "help") == 0) {
 			usage();
 		} else {
@@ -270,7 +277,7 @@
 	if (p.rate.rate) {
 		p.rate.mpu = mpu;
 		p.rate.overhead = overhead;
-		if (tc_calc_rtable(&p.rate, rtab, Rcell_log, mtu) < 0) {
+		if (tc_calc_rtable(&p.rate, rtab, Rcell_log, mtu, linklayer) < 0) {
 			fprintf(stderr, "TBF: failed to calculate rate table.\n");
 			return -1;
 		}
@@ -280,7 +287,7 @@
 	if (p.peakrate.rate) {
 		p.peakrate.mpu = mpu;
 		p.peakrate.overhead = overhead;
-		if (tc_calc_rtable(&p.peakrate, ptab, Pcell_log, mtu) < 0) {
+		if (tc_calc_rtable(&p.peakrate, ptab, Pcell_log, mtu, linklayer) < 0) {
 			fprintf(stderr, "POLICE: failed to calculate peak rate table.\n");
 			return -1;
 		}
diff --git a/tc/q_cbq.c b/tc/q_cbq.c
index e53d167..c99dc3b 100644
--- a/tc/q_cbq.c
+++ b/tc/q_cbq.c
@@ -32,7 +32,7 @@
 	fprintf(stderr, "               [ prio NUMBER ] [ cell BYTES ] [ ewma LOG ]\n");
 	fprintf(stderr, "               [ estimator INTERVAL TIME_CONSTANT ]\n");
 	fprintf(stderr, "               [ split CLASSID ] [ defmap MASK/CHANGE ]\n");
-	fprintf(stderr, "               [ overhead BYTES ]\n");
+	fprintf(stderr, "               [ overhead BYTES ] [ linklayer TYPE ]\n");
 }
 
 static void explain(void)
@@ -55,6 +55,7 @@
 	__u32 rtab[256];
 	unsigned mpu=0, avpkt=0, allot=0;
 	unsigned short overhead=0;
+	unsigned int linklayer = LINKLAYER_ETHERNET; /* Assume ethernet */
 	int cell_log=-1;
 	int ewma_log=-1;
 	struct rtattr *tail;
@@ -120,6 +121,11 @@
 			if (get_u16(&overhead, *argv, 10)) {
 				explain1("overhead"); return -1;
 			}
+		} else if (matches(*argv, "linklayer") == 0) {
+			NEXT_ARG();
+			if (get_linklayer(&linklayer, *argv)) {
+				explain1("linklayer"); return -1;
+			}
 		} else if (matches(*argv, "help") == 0) {
 			explain();
 			return -1;
@@ -146,7 +152,7 @@
 
 	r.mpu = mpu;
 	r.overhead = overhead;
-	if (tc_calc_rtable(&r, rtab, cell_log, allot) < 0) {
+	if (tc_calc_rtable(&r, rtab, cell_log, allot, linklayer) < 0) {
 		fprintf(stderr, "CBQ: failed to calculate rate table.\n");
 		return -1;
 	}
@@ -188,6 +194,7 @@
 	unsigned bndw = 0;
 	unsigned minburst=0, maxburst=0;
 	unsigned short overhead=0;
+	unsigned int linklayer = LINKLAYER_ETHERNET; /* Assume ethernet */
 	struct rtattr *tail;
 
 	memset(&r, 0, sizeof(r));
@@ -331,6 +338,11 @@
 			if (get_u16(&overhead, *argv, 10)) {
 				explain1("overhead"); return -1;
 			}
+		} else if (matches(*argv, "linklayer") == 0) {
+			NEXT_ARG();
+			if (get_linklayer(&linklayer, *argv)) {
+				explain1("linklayer"); return -1;
+			}
 		} else if (matches(*argv, "help") == 0) {
 			explain_class();
 			return -1;
@@ -351,7 +363,7 @@
 			wrr.allot = (lss.avpkt*3)/2;
 		r.mpu = mpu;
 		r.overhead = overhead;
-		if (tc_calc_rtable(&r, rtab, cell_log, pktsize) < 0) {
+		if (tc_calc_rtable(&r, rtab, cell_log, pktsize, linklayer) < 0) {
 			fprintf(stderr, "CBQ: failed to calculate rate table.\n");
 			return -1;
 		}
diff --git a/tc/q_htb.c b/tc/q_htb.c
index e24ad6d..c69e350 100644
--- a/tc/q_htb.c
+++ b/tc/q_htb.c
@@ -41,7 +41,7 @@
 		" burst    max bytes burst which can be accumulated during idle period {computed}\n"
 		" mpu      minimum packet size used in rate computations\n"
 		" overhead per-packet size overhead used in rate computations\n"
-
+		" linklay  adapting to a linklayer e.g. atm\n"
 		" ceil     definite upper class rate (no borrows) {rate}\n"
 		" cburst   burst but for ceil {computed}\n"
 		" mtu      max packet size we create rate map for {1600}\n"
@@ -110,6 +110,7 @@
 	unsigned mtu;
 	unsigned short mpu = 0;
 	unsigned short overhead = 0;
+	unsigned int linklayer  = LINKLAYER_ETHERNET; /* Assume ethernet */
 	struct rtattr *tail;
 
 	memset(&opt, 0, sizeof(opt)); mtu = 1600; /* eth packet len */
@@ -136,6 +137,11 @@
 			if (get_u16(&overhead, *argv, 10)) {
 				explain1("overhead"); return -1;
 			}
+		} else if (matches(*argv, "linklayer") == 0) {
+			NEXT_ARG();
+			if (get_linklayer(&linklayer, *argv)) {
+				explain1("linklayer"); return -1;
+			}
 		} else if (matches(*argv, "quantum") == 0) {
 			NEXT_ARG();
 			if (get_u32(&opt.quantum, *argv, 10)) {
@@ -213,13 +219,13 @@
 	opt.ceil.mpu = mpu;
 	opt.rate.mpu = mpu;
 
-	if (tc_calc_rtable(&opt.rate, rtab, cell_log, mtu) < 0) {
+	if (tc_calc_rtable(&opt.rate, rtab, cell_log, mtu, linklayer) < 0) {
 		fprintf(stderr, "htb: failed to calculate rate table.\n");
 		return -1;
 	}
 	opt.buffer = tc_calc_xmittime(opt.rate.rate, buffer);
 
-	if (tc_calc_rtable(&opt.ceil, ctab, ccell_log, mtu) < 0) {
+	if (tc_calc_rtable(&opt.ceil, ctab, ccell_log, mtu, linklayer) < 0) {
 		fprintf(stderr, "htb: failed to calculate ceil rate table.\n");
 		return -1;
 	}
diff --git a/tc/q_tbf.c b/tc/q_tbf.c
index 3bdce5a..dbf9586 100644
--- a/tc/q_tbf.c
+++ b/tc/q_tbf.c
@@ -27,7 +27,7 @@
 {
 	fprintf(stderr, "Usage: ... tbf limit BYTES burst BYTES[/BYTES] rate KBPS [ mtu BYTES[/BYTES] ]\n");
 	fprintf(stderr, "               [ peakrate KBPS ] [ latency TIME ] ");
-	fprintf(stderr, "[ overhead BYTES ]\n");
+	fprintf(stderr, "[ overhead BYTES ] [ linklayer TYPE ]\n");
 }
 
 static void explain1(char *arg)
@@ -47,6 +47,7 @@
 	unsigned buffer=0, mtu=0, mpu=0, latency=0;
 	int Rcell_log=-1, Pcell_log = -1;
 	unsigned short overhead=0;
+	unsigned int linklayer = LINKLAYER_ETHERNET; /* Assume ethernet */
 	struct rtattr *tail;
 
 	memset(&opt, 0, sizeof(opt));
@@ -141,6 +142,11 @@
 			if (get_u16(&overhead, *argv, 10)) {
 				explain1("overhead"); return -1;
 			}
+		} else if (matches(*argv, "linklayer") == 0) {
+			NEXT_ARG();
+			if (get_linklayer(&linklayer, *argv)) {
+				explain1("linklayer"); return -1;
+			}
 		} else if (strcmp(*argv, "help") == 0) {
 			explain();
 			return -1;
@@ -183,7 +189,7 @@
 
 	opt.rate.mpu      = mpu;
 	opt.rate.overhead = overhead;
-	if (tc_calc_rtable(&opt.rate, rtab, Rcell_log, mtu) < 0) {
+	if (tc_calc_rtable(&opt.rate, rtab, Rcell_log, mtu, linklayer) < 0) {
 		fprintf(stderr, "TBF: failed to calculate rate table.\n");
 		return -1;
 	}
@@ -192,7 +198,7 @@
 	if (opt.peakrate.rate) {
 		opt.peakrate.mpu      = mpu;
 		opt.peakrate.overhead = overhead;
-		if (tc_calc_rtable(&opt.peakrate, ptab, Pcell_log, mtu) < 0) {
+		if (tc_calc_rtable(&opt.peakrate, ptab, Pcell_log, mtu, linklayer) < 0) {
 			fprintf(stderr, "TBF: failed to calculate peak rate table.\n");
 			return -1;
 		}
diff --git a/tc/tc_core.c b/tc/tc_core.c
index 9ae4d8e..855c115 100644
--- a/tc/tc_core.c
+++ b/tc/tc_core.c
@@ -22,6 +22,7 @@
 #include <string.h>
 
 #include "tc_core.h"
+#include <linux/atm.h>
 
 static double tick_in_usec = 1;
 static double clock_factor = 1;
@@ -66,10 +67,33 @@
 }
 
 /*
+ * The align to ATM cells is used for determining the (ATM) SAR
+ * alignment overhead at the ATM layer. (SAR = Segmentation And
+ * Reassembly).  This is for example needed when scheduling packet on
+ * an ADSL connection.  Note that the extra ATM-AAL overhead is _not_
+ * included in this calculation. This overhead is added in the kernel
+ * before doing the rate table lookup, as this gives better precision
+ * (as the table will always be aligned for 48 bytes).
+ *  --Hawk, d.7/11-2004. <hawk@diku.dk>
+ */
+unsigned tc_align_to_atm(unsigned size)
+{
+	int linksize, cells;
+	cells = size / ATM_CELL_PAYLOAD;
+	if ((size % ATM_CELL_PAYLOAD) > 0)
+		cells++;
+
+	linksize = cells * ATM_CELL_SIZE; /* Use full cell size to add ATM tax */
+	return linksize;
+}
+
+/*
    rtab[pkt_len>>cell_log] = pkt_xmit_time
  */
 
-int tc_calc_rtable(struct tc_ratespec *r, __u32 *rtab, int cell_log, unsigned mtu)
+int tc_calc_rtable(struct tc_ratespec *r, __u32 *rtab,
+		   int cell_log, unsigned mtu,
+		   enum link_layer linklayer)
 {
 	int i;
 	unsigned bps = r->rate;
@@ -80,15 +104,29 @@
 
 	if (cell_log < 0) {
 		cell_log = 0;
-		while ((mtu>>cell_log) > 255)
+		while ((mtu >> cell_log) > 255)
 			cell_log++;
 	}
+
 	for (i=0; i<256; i++) {
-		unsigned sz = ((i+1)<<cell_log);
+		unsigned sz = (i+1)<<cell_log;
 		if (sz < mpu)
 			sz = mpu;
+
+		switch (linklayer) {
+		case LINKLAYER_ATM:
+			sz = tc_align_to_atm(sz);
+			break;
+		case LINKLAYER_ETHERNET:
+			// No size adjustments on Ethernet
+			break;
+		default:
+			break;
+		}
+
 		rtab[i] = tc_calc_xmittime(bps, sz);
 	}
+
 	r->cell_align=-1; // Due to the sz calc
 	r->cell_log=cell_log;
 	return cell_log;
diff --git a/tc/tc_core.h b/tc/tc_core.h
index 080a0cd..9f835e8 100644
--- a/tc/tc_core.h
+++ b/tc/tc_core.h
@@ -6,6 +6,12 @@
 
 #define TIME_UNITS_PER_SEC	1000000
 
+enum link_layer {
+	LINKLAYER_ETHERNET=1,
+	LINKLAYER_ATM     =2,
+};
+
+
 int  tc_core_time2big(unsigned time);
 unsigned tc_core_time2tick(unsigned time);
 unsigned tc_core_tick2time(unsigned tick);
@@ -13,7 +19,8 @@
 unsigned tc_core_ktime2time(unsigned ktime);
 unsigned tc_calc_xmittime(unsigned rate, unsigned size);
 unsigned tc_calc_xmitsize(unsigned rate, unsigned ticks);
-int tc_calc_rtable(struct tc_ratespec *r, __u32 *rtab, int cell_log, unsigned mtu);
+int tc_calc_rtable(struct tc_ratespec *r, __u32 *rtab,
+		   int cell_log, unsigned mtu, enum link_layer link_layer);
 
 int tc_setup_estimator(unsigned A, unsigned time_const, struct tc_estimator *est);
 
diff --git a/tc/tc_util.c b/tc/tc_util.c
index cdbae42..cd9dd59 100644
--- a/tc/tc_util.c
+++ b/tc/tc_util.c
@@ -435,6 +435,23 @@
 	return 0;
 }
 
+int get_linklayer(unsigned int *val, const char *arg)
+{
+	int res;
+
+	if (matches(arg, "ethernet") == 0)
+		res = LINKLAYER_ETHERNET;
+	else if (matches(arg, "atm") == 0)
+		res = LINKLAYER_ATM;
+	else if (matches(arg, "adsl") == 0)
+		res = LINKLAYER_ATM;
+	else
+		return -1; /* Indicate error */
+
+	*val = res;
+	return 0;
+}
+
 void print_tm(FILE * f, const struct tcf_t *tm)
 {
 	int hz = get_user_hz();
diff --git a/tc/tc_util.h b/tc/tc_util.h
index 120d6ce..301b5c7 100644
--- a/tc/tc_util.h
+++ b/tc/tc_util.h
@@ -49,6 +49,8 @@
 extern int get_size(unsigned *size, const char *str);
 extern int get_size_and_cell(unsigned *size, int *cell_log, char *str);
 extern int get_time(unsigned *time, const char *str);
+extern int get_linklayer(unsigned *val, const char *arg);
+
 extern void print_rate(char *buf, int len, __u32 rate);
 extern void print_size(char *buf, int len, __u32 size);
 extern void print_percent(char *buf, int len, __u32 percent);