diff -ur --new-file old/linux/drivers/atm/atmtcp.c new/linux/drivers/atm/atmtcp.c --- old/linux/drivers/atm/atmtcp.c Wed Aug 19 20:07:50 1998 +++ new/linux/drivers/atm/atmtcp.c Wed Aug 19 20:09:17 1998 @@ -3,6 +3,7 @@ /* Written 1997,1998 by Werner Almesberger, EPFL LRC/ICA */ +#include #include #include #include @@ -27,7 +28,7 @@ static void atmtcp_v_dev_close(struct atm_dev *dev) { - /* do nothing */ + MOD_DEC_USE_COUNT; } @@ -251,6 +252,7 @@ kfree(dev_data); return itf == -1 ? -ENOMEM : -EBUSY; } + MOD_INC_USE_COUNT; dev->ci_range.vpi_bits = MAX_VPI_BITS; dev->ci_range.vci_bits = MAX_VCI_BITS; PRIV(dev) = dev_data; @@ -309,3 +311,29 @@ shutdown_atm_dev(dev); return 0; } + + +#ifdef MODULE + +int init_module(void) +{ + atm_tcp_ops.attach = atmtcp_attach; + atm_tcp_ops.create_persistent = atmtcp_create_persistent; + atm_tcp_ops.remove_persistent = atmtcp_remove_persistent; + return 0; +} + +void cleanup_module(void) +{ +} + +#else + +struct atm_tcp_ops atm_tcp_ops = { + atmtcp_attach, /* attach */ + atmtcp_create_persistent, /* create_persistent */ + atmtcp_remove_persistent /* remove_persistent */ +}; + +#endif + diff -ur --new-file old/linux/drivers/atm/suni.c new/linux/drivers/atm/suni.c --- old/linux/drivers/atm/suni.c Wed Aug 19 20:07:50 1998 +++ new/linux/drivers/atm/suni.c Wed Aug 19 20:09:17 1998 @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -176,7 +177,7 @@ case SONET_GETDIAG: return get_diag(dev,arg); case SONET_SETFRAMING: - if (!suser()) return -EPERM; + if (!capable(CAP_NET_ADMIN)) return -EPERM; if (arg != SONET_FRAME_SONET) return -EINVAL; return 0; case SONET_GETFRAMING: @@ -185,7 +186,7 @@ case SONET_GETFRSENSE: return -EINVAL; case SUNI_SETLOOP: - if (!suser()) return -EPERM; + if (!capable(CAP_NET_ADMIN)) return -EPERM; if ((int) arg < 0 || (int) arg > SUNI_LM_LOOP) return -EINVAL; PUT((GET(MCT) & ~(SUNI_MCT_DLE | SUNI_MCT_LLE)) | diff -ur --new-file old/linux/drivers/atm/zatm.c new/linux/drivers/atm/zatm.c --- old/linux/drivers/atm/zatm.c Wed Aug 19 20:07:50 1998 +++ new/linux/drivers/atm/zatm.c Wed Aug 19 20:09:17 1998 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -1609,7 +1610,7 @@ zatm_dev = ZATM_DEV(dev); switch (cmd) { case ZATM_GETPOOLZ: - if (!suser()) return -EPERM; + if (!capable(CAP_NET_ADMIN)) return -EPERM; /* fall through */ case ZATM_GETPOOL: { @@ -1638,7 +1639,7 @@ struct zatm_pool_info info; int pool; - if (!suser()) return -EPERM; + if (!capable(CAP_NET_ADMIN)) return -EPERM; if (get_user(pool, &((struct zatm_pool_req *) arg)->pool_num)) return -EFAULT; diff -ur --new-file old/linux/include/linux/atm.h new/linux/include/linux/atm.h --- old/linux/include/linux/atm.h Wed Aug 19 20:07:50 1998 +++ new/linux/include/linux/atm.h Wed Aug 19 20:09:17 1998 @@ -3,6 +3,11 @@ /* Written 1995-1998 by Werner Almesberger, EPFL LRC/ICA */ +/* + * WARNING: User-space programs should not #include directly. + * Instead, #include + */ + #ifndef _LINUX_ATM_H #define _LINUX_ATM_H diff -ur --new-file old/linux/include/linux/atm_tcp.h new/linux/include/linux/atm_tcp.h --- old/linux/include/linux/atm_tcp.h Wed Aug 19 20:07:50 1998 +++ new/linux/include/linux/atm_tcp.h Wed Aug 19 20:09:17 1998 @@ -33,9 +33,13 @@ #ifdef __KERNEL__ -int atmtcp_attach(struct atm_vcc *vcc,int itf); -int atmtcp_create_persistent(int itf); -int atmtcp_remove_persistent(int itf); +struct atm_tcp_ops { + int (*attach)(struct atm_vcc *vcc,int itf); + int (*create_persistent)(int itf); + int (*remove_persistent)(int itf); +}; + +extern struct atm_tcp_ops atm_tcp_ops; #endif diff -ur --new-file old/linux/include/linux/atmclip.h new/linux/include/linux/atmclip.h --- old/linux/include/linux/atmclip.h Wed Aug 19 20:07:50 1998 +++ new/linux/include/linux/atmclip.h Wed Aug 19 20:09:17 1998 @@ -18,9 +18,8 @@ #define SIOCMKCLIP _IO('a',ATMIOC_CLIP) /* create IP interface */ - #ifdef __KERNEL__ -void clip_xmit_vcc(struct sk_buff *skb,struct atm_vcc *vcc); +extern const unsigned char llc_oui[6]; #endif #endif diff -ur --new-file old/linux/include/linux/capability.h new/linux/include/linux/capability.h --- old/linux/include/linux/capability.h Sun Jun 7 20:22:35 1998 +++ new/linux/include/linux/capability.h Wed Aug 19 20:09:17 1998 @@ -121,6 +121,7 @@ #define CAP_LINUX_IMMUTABLE 9 /* Allows binding to TCP/UDP sockets below 1024 */ +/* Allows binding to ATM VCIs below 32 */ #define CAP_NET_BIND_SERVICE 10 @@ -140,6 +141,7 @@ /* Allow clearing driver statistics */ /* Allow multicasting */ /* Allow read/write of device-specific registers */ +/* Allow activation of ATM control sockets */ #define CAP_NET_ADMIN 12 diff -ur --new-file old/linux/include/linux/pkt_sched.h new/linux/include/linux/pkt_sched.h --- old/linux/include/linux/pkt_sched.h Tue Apr 28 20:10:10 1998 +++ new/linux/include/linux/pkt_sched.h Wed Aug 19 20:09:18 1998 @@ -274,4 +274,17 @@ #define TCA_CBQ_MAX TCA_CBQ_POLICE +/* ATM section */ + +enum { + TCA_ATM_UNSPEC, + TCA_ATM_FD, /* file/socket descriptor */ + TCA_ATM_PTR, /* pointer to descriptor - later */ + TCA_ATM_HDR, /* LL header */ + TCA_ATM_POLICE, /* policing - later */ + TCA_ATM_ADDR /* PVC address (for output only) */ +}; + +#define TCA_ATM_MAX TCA_ATM_ADDR + #endif diff -ur --new-file old/linux/include/linux/skbuff.h new/linux/include/linux/skbuff.h --- old/linux/include/linux/skbuff.h Wed Aug 19 20:07:50 1998 +++ new/linux/include/linux/skbuff.h Wed Aug 19 20:09:18 1998 @@ -110,10 +110,6 @@ struct { struct atm_vcc *vcc; /* ATM VCC */ int iovcnt; /* 0 for "normal" operation */ -#ifdef CONFIG_ATM_NICSTAR - void *recycle_buffer; /* set when buffer should be */ - /* recycled; points to vcc */ -#endif #ifdef CONFIG_AREQUIPA int generation; /* generation number */ #endif diff -ur --new-file old/linux/net/atm/clip.c new/linux/net/atm/clip.c --- old/linux/net/atm/clip.c Wed Aug 19 20:07:51 1998 +++ new/linux/net/atm/clip.c Wed Aug 19 20:09:19 1998 @@ -322,25 +322,6 @@ } -/* - * For playing with RSVP. Should later be merged with clip_start_xmit - */ - - -void clip_xmit_vcc(struct sk_buff *skb,struct atm_vcc *vcc) -{ - void *here; - - skb->atm.vcc = vcc; - here = skb_push(skb,RFC1483LLC_LEN); - memcpy(here,llc_oui,sizeof(llc_oui)); - ((u16 *) here)[3] = skb->protocol; - atomic_add(skb->truesize,&vcc->tx_inuse); - skb->atm.iovcnt = 0; - (void) vcc->dev->ops->send(vcc,skb); -} - - static int clip_start_xmit(struct sk_buff *skb,struct device *dev) { struct atmarp_entry *entry; diff -ur --new-file old/linux/net/atm/common.c new/linux/net/atm/common.c --- old/linux/net/atm/common.c Wed Aug 19 20:07:51 1998 +++ new/linux/net/atm/common.c Wed Aug 19 20:09:19 1998 @@ -14,7 +14,7 @@ #include /* for ioctls */ #include /* SOL_SOCKET */ #include /* error codes */ -#include /* suser */ +#include #include /* verify_area */ #include #include /* struct timeval */ @@ -54,8 +54,12 @@ #endif #endif -#ifdef CONFIG_ATM_TCP +#if defined(CONFIG_ATM_TCP) || defined(CONFIG_ATM_TCP_MODULE) #include +#ifdef CONFIG_ATM_TCP_MODULE +struct atm_tcp_ops atm_tcp_ops; +EXPORT_SYMBOL(atm_tcp_ops); +#endif #endif #include "resources.h" /* atm_find_dev */ @@ -211,7 +215,8 @@ vpi >> dev->ci_range.vpi_bits) || (vci != ATM_VCI_UNSPEC && vci != ATM_VCI_ANY && vci >> dev->ci_range.vci_bits)) return -EINVAL; - if (vci > 0 && vci < ATM_NOT_RSV_VCI && !suser()) return -EPERM; + if (vci > 0 && vci < ATM_NOT_RSV_VCI && !capable(CAP_NET_BIND_SERVICE)) + return -EPERM; error = 0; switch (vcc->qos.aal) { case ATM_AAL0: @@ -572,7 +577,7 @@ ATM_VF_SCTX)) | arg; return 0; case ATMSIGD_CTRL: - if (!suser()) return -EPERM; + if (!capable(CAP_NET_ADMIN)) return -EPERM; error = sigd_attach(vcc); if (!error) sock->state = SS_CONNECTED; return error; @@ -591,21 +596,21 @@ #endif #ifdef CONFIG_ATM_CLIP case SIOCMKCLIP: - if (!suser()) return -EPERM; + if (!capable(CAP_NET_ADMIN)) return -EPERM; return clip_create(arg); case ATMARPD_CTRL: - if (!suser()) return -EPERM; + if (!capable(CAP_NET_ADMIN)) return -EPERM; error = atm_init_atmarp(vcc); if (!error) sock->state = SS_CONNECTED; return error; case ATMARP_MKIP: - if (!suser()) return -EPERM; + if (!capable(CAP_NET_ADMIN)) return -EPERM; return clip_mkip(vcc,arg); case ATMARP_SETENTRY: - if (!suser()) return -EPERM; + if (!capable(CAP_NET_ADMIN)) return -EPERM; return clip_setentry(vcc,arg); case ATMARP_ENCAP: - if (!suser()) return -EPERM; + if (!capable(CAP_NET_ADMIN)) return -EPERM; return clip_encap(vcc,arg); #endif #ifdef CONFIG_AREQUIPA @@ -622,18 +627,18 @@ case AREQUIPA_INCOMING: return arequipa_incoming(sock); case AREQUIPA_CTRL: - if (!suser()) return -EPERM; + if (!capable(CAP_NET_ADMIN)) return -EPERM; error = arequipad_attach(vcc); if (!error) sock->state = SS_CONNECTED; return error; case AREQUIPA_WORK: - if (!suser()) return -EPERM; + if (!capable(CAP_NET_ADMIN)) return -EPERM; arequipa_work(); return 0; #endif #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) case ATMLEC_CTRL: - if (!suser()) return -EPERM; + if (!capable(CAP_NET_ADMIN)) return -EPERM; if (atm_lane_ops.lecd_attach == NULL) atm_lane_init(); if (atm_lane_ops.lecd_attach == NULL) /* try again */ @@ -642,15 +647,15 @@ if (error >= 0) sock->state = SS_CONNECTED; return error; case ATMLEC_MCAST: - if (!suser()) return -EPERM; + if (!capable(CAP_NET_ADMIN)) return -EPERM; return atm_lane_ops.mcast_attach(vcc, (int)arg); case ATMLEC_DATA: - if (!suser()) return -EPERM; + if (!capable(CAP_NET_ADMIN)) return -EPERM; return atm_lane_ops.vcc_attach(vcc, (void*)arg); #endif #if defined(CONFIG_ATM_MPOA) || defined(CONFIG_ATM_MPOA_MODULE) case ATMMPC_CTRL: - if (!suser()) return -EPERM; + if (!capable(CAP_NET_ADMIN)) return -EPERM; if (atm_mpoa_ops.mpoad_attach == NULL) atm_mpoa_init(); if (atm_mpoa_ops.mpoad_attach == NULL) /* try again */ @@ -659,21 +664,21 @@ if (error >= 0) sock->state = SS_CONNECTED; return error; case ATMMPC_DATA: - if (!suser()) return -EPERM; + if (!capable(CAP_NET_ADMIN)) return -EPERM; return atm_mpoa_ops.vcc_attach(vcc, arg); #endif -#ifdef CONFIG_ATM_TCP +#if defined(CONFIG_ATM_TCP) || defined(CONFIG_ATM_TCP_MODULE) case SIOCSIFATMTCP: - if (!suser()) return -EPERM; - error = atmtcp_attach(vcc,(int) arg); + if (!capable(CAP_NET_ADMIN)) return -EPERM; + error = atm_tcp_ops.attach(vcc,(int) arg); if (error >= 0) sock->state = SS_CONNECTED; return error; case ATMTCP_CREATE: - if (!suser()) return -EPERM; - return atmtcp_create_persistent((int) arg); + if (!capable(CAP_NET_ADMIN)) return -EPERM; + return atm_tcp_ops.create_persistent((int) arg); case ATMTCP_REMOVE: - if (!suser()) return -EPERM; - return atmtcp_remove_persistent((int) arg); + if (!capable(CAP_NET_ADMIN)) return -EPERM; + return atm_tcp_ops.remove_persistent((int) arg); #endif default: break; @@ -705,14 +710,14 @@ { unsigned char esi[ESI_LEN]; - if (!suser()) return -EPERM; + if (!capable(CAP_NET_ADMIN)) return -EPERM; if (copy_from_user(esi,buf,ESI_LEN)) return -EFAULT; memcpy(dev->esi,esi,ESI_LEN); return ESI_LEN; } case ATM_GETSTATZ: - if (!suser()) return -EPERM; + if (!capable(CAP_NET_ADMIN)) return -EPERM; /* fall through */ case ATM_GETSTAT: size = sizeof(struct atm_dev_stats); @@ -725,12 +730,12 @@ return -EFAULT; break; case ATM_RSTADDR: - if (!suser()) return -EPERM; + if (!capable(CAP_NET_ADMIN)) return -EPERM; reset_addr(dev); break; case ATM_ADDADDR: case ATM_DELADDR: - if (!suser()) return -EPERM; + if (!capable(CAP_NET_ADMIN)) return -EPERM; { struct sockaddr_atmsvc addr; @@ -752,7 +757,7 @@ case SONET_SETDIAG: case SONET_CLRDIAG: case SONET_SETFRAMING: - if (!suser()) return -EPERM; + if (!capable(CAP_NET_ADMIN)) return -EPERM; /* fall through */ default: if (!dev->ops->ioctl) return -EINVAL; diff -ur --new-file old/linux/net/atm/ipcommon.h new/linux/net/atm/ipcommon.h --- old/linux/net/atm/ipcommon.h Wed Aug 19 20:07:51 1998 +++ new/linux/net/atm/ipcommon.h Wed Aug 19 20:09:19 1998 @@ -13,7 +13,6 @@ #include -extern const unsigned char llc_oui[6]; extern struct device *clip_devs; diff -ur --new-file old/linux/net/atm/lane_mpoa_init.c new/linux/net/atm/lane_mpoa_init.c --- old/linux/net/atm/lane_mpoa_init.c Wed Aug 19 20:07:51 1998 +++ new/linux/net/atm/lane_mpoa_init.c Wed Aug 19 20:09:19 1998 @@ -25,6 +25,7 @@ extern struct atm_mpoa_ops atm_mpoa_ops; /* in common.c */ extern struct atm_lane_ops atm_lane_ops; /* in common.c */ +#if defined(CONFIG_ATM_MPOA) || defined(CONFIG_ATM_MPOA_MODULE) void atm_mpoa_init(void) { #ifndef CONFIG_ATM_MPOA_MODULE /* not module */ @@ -33,7 +34,9 @@ return; } +#endif +#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) void atm_lane_init(void) { #ifndef CONFIG_ATM_LANE_MODULE /* not module */ @@ -42,3 +45,4 @@ return; } +#endif diff -ur --new-file old/linux/net/atm/mpc.c new/linux/net/atm/mpc.c --- old/linux/net/atm/mpc.c Wed Aug 19 20:07:51 1998 +++ new/linux/net/atm/mpc.c Wed Aug 19 20:09:19 1998 @@ -1106,7 +1106,8 @@ memcpy(&tlv[7], mesg->MPS_ctrl, ATM_ESA_LEN); /* MPC ctrl ATM addr */ memcpy(mpc->our_ctrl_addr, mesg->MPS_ctrl, ATM_ESA_LEN); - printk("mpoa: (%s) setting MPC ctrl ATM address to ", mpc->dev->name); + printk("mpoa: (%s) setting MPC ctrl ATM address to ", + (mpc->dev) ? mpc->dev->name : ""); for (i = 7; i < sizeof(tlv); i++) printk("%02x ", tlv[i]); printk("\n"); diff -ur --new-file old/linux/net/atm/mpoa_proc.c new/linux/net/atm/mpoa_proc.c --- old/linux/net/atm/mpoa_proc.c Wed Aug 19 20:07:51 1998 +++ new/linux/net/atm/mpoa_proc.c Wed Aug 19 20:09:19 1998 @@ -17,32 +17,15 @@ * file system statistics */ +#define STAT_FILE_NAME "mpc" /* Our statistic file's name */ + extern struct mpoa_client *mpcs; +extern struct proc_dir_entry atm_proc_root; /* from proc.c. */ static ssize_t proc_mpc_read(struct file *file, char *buff, size_t count, loff_t *pos); /* - * /proc/mpoa DIRECTORY ENTRY. - */ -static struct proc_dir_entry mpc_proc_root = { - 0, /* low_ino (0=dynamic?) */ - 4, /* name length */ - "mpoa", /* name string */ - S_IFDIR | S_IRUGO | S_IXUGO, /* mode/permissions */ - 2, /* 2=dir */ - 0, /* UID */ - 0, /* GID */ - 0, /* size */ - &proc_dir_inode_operations, /* inode operations */ - NULL, /* get_info func-ptr */ - NULL, /* fill_inode func-ptr */ - NULL, /* next ptr */ - NULL, /* parent ptr */ - NULL /* subdir ptr */ -}; - -/* * Define allowed FILE OPERATIONS */ static struct file_operations mpc_file_operations = { @@ -82,12 +65,12 @@ }; /* - * /proc/mpoa/mpc_stats REGULAR_FILE + * Our statistics file */ static struct proc_dir_entry mpc_stats = { 0, /* low_ino */ - 9, /* name length */ - "mpc_stats", /* name */ + sizeof(STAT_FILE_NAME)-1, /* name length */ + STAT_FILE_NAME, /* name */ S_IFREG | S_IRUGO, /* mode */ 1, /* 1=file */ 0, /* UID */ @@ -215,13 +198,8 @@ { int retval = 0; - if ( (retval = proc_register(&proc_root,&mpc_proc_root)) != 0 ) { - printk(KERN_ERR "Unable to initialize /proc/mpoa/\n"); - return retval; - } - - if ( (retval = proc_register(&mpc_proc_root,&mpc_stats)) != 0 ) { - printk(KERN_ERR "Unable to initialize /proc/mpoa/mpc_stats\n"); + if ( (retval = proc_register(&atm_proc_root,&mpc_stats)) != 0 ) { + printk(KERN_ERR "Unable to initialize /proc/atm/%s\n", STAT_FILE_NAME); return retval; } return 0; @@ -232,8 +210,7 @@ */ void mpc_proc_clean(void) { - proc_unregister(&mpc_proc_root,mpc_stats.low_ino); - proc_unregister(&proc_root,mpc_proc_root.low_ino); + proc_unregister(&atm_proc_root,mpc_stats.low_ino); } diff -ur --new-file old/linux/net/atm/signaling.c new/linux/net/atm/signaling.c --- old/linux/net/atm/signaling.c Wed Aug 19 20:07:52 1998 +++ new/linux/net/atm/signaling.c Wed Aug 19 20:09:19 1998 @@ -4,7 +4,7 @@ #include /* error codes */ -#include /* printk, suser */ +#include /* printk */ #include #include #include /* jiffies and HZ */ diff -ur --new-file old/linux/net/core/skbuff.c new/linux/net/core/skbuff.c --- old/linux/net/core/skbuff.c Wed Aug 19 20:07:52 1998 +++ new/linux/net/core/skbuff.c Wed Aug 19 20:09:19 1998 @@ -151,9 +151,6 @@ #ifdef CONFIG_ATM skb->atm.iovcnt = 0; -#ifdef CONFIG_ATM_NICSTAR - skb->atm.recycle_buffer = NULL; -#endif #endif atomic_set(&skb->users, 1); @@ -248,9 +245,6 @@ n->is_clone = 1; atomic_set(&n->users, 1); n->destructor = NULL; -#ifdef CONFIG_ATM_NICSTAR - n->atm.recycle_buffer = NULL; -#endif return n; } @@ -301,9 +295,6 @@ n->stamp=skb->stamp; n->destructor = NULL; n->security=skb->security; -#ifdef CONFIG_ATM_NICSTAR - n->atm.recycle_buffer = NULL; -#endif return n; } diff -ur --new-file old/linux/net/sched/sch_atm.c new/linux/net/sched/sch_atm.c --- old/linux/net/sched/sch_atm.c Wed Aug 19 20:07:51 1998 +++ new/linux/net/sched/sch_atm.c Wed Aug 19 20:09:19 1998 @@ -73,6 +73,8 @@ int ref; /* reference count */ struct tc_stats stats; struct atm_flow_data *next; + int hdr_len; + unsigned char hdr[0]; /* header data */ }; struct atm_qdisc_data { @@ -176,8 +178,10 @@ struct atm_qdisc_data *p = PRIV(sch); struct atm_flow_data *flow = (struct atm_flow_data *) *arg; struct rtattr *opt = tca[TCA_OPTIONS-1]; + struct rtattr *tb[TCA_ATM_MAX]; struct socket *sock; - int fd,error; + int fd,error,hdr_len; + void *hdr; DPRINTK("atm_tc_change(sch %p,[qdisc %p],classid %x,parent %x," "flow %p,opt %p)\n",sch,p,classid,parent,flow,opt); @@ -192,17 +196,22 @@ * class needs to be removed and a new one added. */ if (flow) return -EBUSY; - /* - * @@@ Just treat the whole option block as our argument. (Technically, - * this makes sense, because there's only one variable and it's - * required anyway. Of course, this differs from how things are done - * elsewhere. Need to fix it when adding policing ...) - */ - DPRINTK("atm_tc_change: type %d, payload %d\n",opt->rta_type, - RTA_PAYLOAD(opt)); - if (RTA_PAYLOAD(*tca) != sizeof(int)) return -EINVAL; - fd = *(int *) RTA_DATA(opt); + if (opt == NULL || rtattr_parse(tb,TCA_ATM_MAX,RTA_DATA(opt), + RTA_PAYLOAD(opt))) return -EINVAL; + if (!tb[TCA_ATM_FD-1] || RTA_PAYLOAD(tb[TCA_ATM_FD-1]) < sizeof(fd)) + return -EINVAL; + fd = *(int *) RTA_DATA(tb[TCA_ATM_FD-1]); DPRINTK("atm_tc_change: fd %d\n",fd); + if (tb[TCA_ATM_HDR-1]) { + hdr_len = RTA_PAYLOAD(tb[TCA_ATM_HDR-1]); + hdr = RTA_DATA(tb[TCA_ATM_HDR-1]); + } + else { + hdr_len = RFC1483LLC_LEN; + hdr = NULL; /* default LLC/SNAP for IP */ + } + DPRINTK("atm_tc_change: type %d, payload %d, hdr_len %d\n", + opt->rta_type,RTA_PAYLOAD(opt),hdr_len); if (!(sock = sockfd_lookup(fd,&error))) return error; /* f_count++ */ DPRINTK("atm_tc_change: f_count %d\n",sock->file->f_count); if (sock->ops->family != PF_ATMSVC && sock->ops->family != PF_ATMPVC) { @@ -233,7 +242,7 @@ } } DPRINTK("atm_tc_change: new id %x\n",classid); - flow = kmalloc(sizeof(struct atm_flow_data),GFP_KERNEL); + flow = kmalloc(sizeof(struct atm_flow_data)+hdr_len,GFP_KERNEL); DPRINTK("atm_tc_change: flow %p\n",flow); if (!flow) { error = -ENOBUFS; @@ -251,6 +260,12 @@ flow->ref = 1; flow->next = p->link.next; p->link.next = flow; + flow->hdr_len = hdr_len; + if (hdr) memcpy(flow->hdr,hdr,hdr_len); + else { + memcpy(flow->hdr,llc_oui,sizeof(llc_oui)); + ((u16 *) flow->hdr)[3] = htons(ETH_P_IP); + } *arg = (unsigned long) flow; return 0; err_out: @@ -340,23 +355,27 @@ * If traffic is properly shaped, this won't generate nasty * little bursts. Otherwise, it may ... @@@ */ - while (skb = flow->q->dequeue(flow->q)) { + while ((skb = flow->q->dequeue(flow->q))) { sch->q.qlen--; D2PRINTK("atm_tc_deqeueue: sending on class %p\n",flow); - /* - * Now we're in the unfortunate situation that the - * packet header may have to change. So we remove all - * other headers first. Then clip_xmit_vcc will try to - * add the RFC1483 header. If we're unlucky, we panic, - * because there's not enough space left ... - * - * To avoid this, we should call skb_realloc_headroom - * when we detect that there's not enough space. @@@ - */ + /* remove any LL header somebody else has attached */ + skb_pull(skb,(char *) skb->nh.iph-(char *) skb->data); + if (skb_headroom(skb) < flow->hdr_len) { + struct sk_buff *new; + + new = skb_realloc_headroom(skb,flow->hdr_len); + dev_kfree_skb(skb); + if (!new) continue; + skb = new; + } D2PRINTK("atm_tc_dequeue: ip %p, data %p\n", skb->nh.iph,skb->data); - skb_pull(skb,(char *) skb->nh.iph-(char *) skb->data); - clip_xmit_vcc(skb,flow->vcc); + skb->atm.vcc = flow->vcc; + memcpy(skb_push(skb,flow->hdr_len),flow->hdr, + flow->hdr_len); + atomic_add(skb->truesize,&flow->vcc->tx_inuse); + skb->atm.iovcnt = 0; + (void) flow->vcc->dev->ops->send(flow->vcc,skb); } skb = p->link.q->dequeue(p->link.q); if (skb) sch->q.qlen--; @@ -443,10 +462,15 @@ { struct atm_qdisc_data *p = PRIV(sch); struct atm_flow_data *flow = (struct atm_flow_data *) cl; + unsigned char *b = skb->tail; + struct rtattr *rta; DPRINTK("atm_tc_dump_class(sch %p,[qdisc %p],flow %p,skb %p,tcm %p)\n", sch,p,flow,skb,tcm); if (!find_flow(p,flow)) return -EINVAL; + rta = (struct rtattr *) b; + RTA_PUT(skb,TCA_OPTIONS,0,NULL); + RTA_PUT(skb,TCA_ATM_HDR,flow->hdr_len,flow->hdr); if (flow->vcc) { struct sockaddr_atmpvc pvc; @@ -454,10 +478,13 @@ pvc.sap_addr.itf = flow->vcc->dev ? flow->vcc->dev->number : -1; pvc.sap_addr.vpi = flow->vcc->vpi; pvc.sap_addr.vci = flow->vcc->vci; - RTA_PUT(skb,TCA_OPTIONS,sizeof(pvc),&pvc); + RTA_PUT(skb,TCA_ATM_ADDR,sizeof(pvc),&pvc); } + rta->rta_len = skb->tail-b; return skb->len; + rtattr_failure: + skb_trim(skb,b-skb->data); return -1; } .