From 4e54c4816bfe51c145382d272b19c2ae41e9e36f Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Tue, 15 Jun 2004 06:37:41 -0700 Subject: [NET]: Add tc extensions infrastructure. Signed-off-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- include/linux/netdevice.h | 2 + include/linux/pkt_cls.h | 171 +++++++++++++++++++++++++++++++++++++++++++--- include/linux/pkt_sched.h | 1 + include/linux/rtnetlink.h | 17 +++++ include/linux/skbuff.h | 10 ++- 5 files changed, 192 insertions(+), 9 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index a55f97a34035..6402659e2e6a 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -366,6 +366,8 @@ struct net_device struct Qdisc *qdisc_ingress; unsigned long tx_queue_len; /* Max frames per queue allowed */ + /* ingress path synchronizer */ + spinlock_t ingress_lock; /* hard_start_xmit synchronizer */ spinlock_t xmit_lock; /* cpu id of processor entered to hard_start_xmit or -1, diff --git a/include/linux/pkt_cls.h b/include/linux/pkt_cls.h index f54111f9d14c..74daa67e81c9 100644 --- a/include/linux/pkt_cls.h +++ b/include/linux/pkt_cls.h @@ -1,14 +1,130 @@ #ifndef __LINUX_PKT_CLS_H #define __LINUX_PKT_CLS_H +/* I think i could have done better macros ; for now this is stolen from + * some arch/mips code - jhs +*/ +#define _TC_MAKE32(x) ((x)) + +#define _TC_MAKEMASK1(n) (_TC_MAKE32(1) << _TC_MAKE32(n)) +#define _TC_MAKEMASK(v,n) (_TC_MAKE32((_TC_MAKE32(1)<<(v))-1) << _TC_MAKE32(n)) +#define _TC_MAKEVALUE(v,n) (_TC_MAKE32(v) << _TC_MAKE32(n)) +#define _TC_GETVALUE(v,n,m) ((_TC_MAKE32(v) & _TC_MAKE32(m)) >> _TC_MAKE32(n)) + +/* verdict bit breakdown + * +bit 0: when set -> this packet has been munged already + +bit 1: when set -> It is ok to munge this packet + +bit 2,3,4,5: Reclassify counter - sort of reverse TTL - if exceeded +assume loop + +bit 6,7: Where this packet was last seen +0: Above the transmit example at the socket level +1: on the Ingress +2: on the Egress + +bit 8: when set --> Request not to classify on ingress. + +bits 9,10,11: redirect counter - redirect TTL. Loop avoidance + + * + * */ + +#define TC_MUNGED _TC_MAKEMASK1(0) +#define SET_TC_MUNGED(v) ( TC_MUNGED | (v & ~TC_MUNGED)) +#define CLR_TC_MUNGED(v) ( v & ~TC_MUNGED) + +#define TC_OK2MUNGE _TC_MAKEMASK1(1) +#define SET_TC_OK2MUNGE(v) ( TC_OK2MUNGE | (v & ~TC_OK2MUNGE)) +#define CLR_TC_OK2MUNGE(v) ( v & ~TC_OK2MUNGE) + +#define S_TC_VERD _TC_MAKE32(2) +#define M_TC_VERD _TC_MAKEMASK(4,S_TC_VERD) +#define G_TC_VERD(x) _TC_GETVALUE(x,S_TC_VERD,M_TC_VERD) +#define V_TC_VERD(x) _TC_MAKEVALUE(x,S_TC_VERD) +#define SET_TC_VERD(v,n) ((V_TC_VERD(n)) | (v & ~M_TC_VERD)) + +#define S_TC_FROM _TC_MAKE32(6) +#define M_TC_FROM _TC_MAKEMASK(2,S_TC_FROM) +#define G_TC_FROM(x) _TC_GETVALUE(x,S_TC_FROM,M_TC_FROM) +#define V_TC_FROM(x) _TC_MAKEVALUE(x,S_TC_FROM) +#define SET_TC_FROM(v,n) ((V_TC_FROM(n)) | (v & ~M_TC_FROM)) +#define AT_STACK 0x0 +#define AT_INGRESS 0x1 +#define AT_EGRESS 0x2 + +#define TC_NCLS _TC_MAKEMASK1(8) +#define SET_TC_NCLS(v) ( TC_NCLS | (v & ~TC_NCLS)) +#define CLR_TC_NCLS(v) ( v & ~TC_NCLS) + +#define S_TC_RTTL _TC_MAKE32(9) +#define M_TC_RTTL _TC_MAKEMASK(3,S_TC_RTTL) +#define G_TC_RTTL(x) _TC_GETVALUE(x,S_TC_RTTL,M_TC_RTTL) +#define V_TC_RTTL(x) _TC_MAKEVALUE(x,S_TC_RTTL) +#define SET_TC_RTTL(v,n) ((V_TC_RTTL(n)) | (v & ~M_TC_RTTL)) + +#define S_TC_AT _TC_MAKE32(12) +#define M_TC_AT _TC_MAKEMASK(2,S_TC_AT) +#define G_TC_AT(x) _TC_GETVALUE(x,S_TC_AT,M_TC_AT) +#define V_TC_AT(x) _TC_MAKEVALUE(x,S_TC_AT) +#define SET_TC_AT(v,n) ((V_TC_AT(n)) | (v & ~M_TC_AT)) + +/* Action types */ +enum +{ + TCA_ACT_UNSPEC=0, + TCA_ACT_KIND=1, + TCA_ACT_OPTIONS=2, + TCA_ACT_INDEX=3, + TCA_ACT_POLICE=4, + /* other actions go here */ + __TCA_ACT_MAX=255 +}; + +#define TCA_ACT_MAX __TCA_ACT_MAX +#define TCA_OLD_COMPAT (TCA_ACT_MAX+1) +#define TCA_ACT_MAX_PRIO 32 +#define TCA_ACT_BIND 1 +#define TCA_ACT_NOBIND 0 +#define TCA_ACT_UNBIND 1 +#define TCA_ACT_NOUNBIND 0 +#define TCA_ACT_REPLACE 1 +#define TCA_ACT_NOREPLACE 0 +#define MAX_REC_LOOP 4 +#define MAX_RED_LOOP 4 + +#define TC_ACT_UNSPEC (-1) +#define TC_ACT_OK 0 +#define TC_ACT_RECLASSIFY 1 +#define TC_ACT_SHOT 2 +#define TC_ACT_PIPE 3 +#define TC_ACT_STOLEN 4 +#define TC_ACT_QUEUED 5 +#define TC_ACT_REPEAT 6 +#define TC_ACT_JUMP 0x10000000 + struct tc_police { __u32 index; +#ifdef CONFIG_NET_CLS_ACT + int refcnt; + int bindcnt; +#endif +/* Turned off because it requires new tc + * to work (for now maintain ABI) + * +#ifdef CONFIG_NET_CLS_ACT + __u32 capab; +#endif +*/ int action; -#define TC_POLICE_UNSPEC (-1) -#define TC_POLICE_OK 0 -#define TC_POLICE_RECLASSIFY 1 -#define TC_POLICE_SHOT 2 +#define TC_POLICE_UNSPEC TC_ACT_UNSPEC +#define TC_POLICE_OK TC_ACT_OK +#define TC_POLICE_RECLASSIFY TC_ACT_RECLASSIFY +#define TC_POLICE_SHOT TC_ACT_SHOT +#define TC_POLICE_PIPE TC_ACT_PIPE __u32 limit; __u32 burst; @@ -17,6 +133,26 @@ struct tc_police struct tc_ratespec peakrate; }; +struct tcf_t +{ + __u32 install; + __u32 lastuse; + __u32 expires; +}; + +struct tc_cnt +{ + int refcnt; + int bindcnt; +}; + +#define tc_gen \ + __u32 index; \ + __u32 capab; \ + int action; \ + int refcnt; \ + int bindcnt + enum { TCA_POLICE_UNSPEC, @@ -25,8 +161,8 @@ enum TCA_POLICE_PEAKRATE, TCA_POLICE_AVRATE, TCA_POLICE_RESULT, -#define TCA_POLICE_RESULT TCA_POLICE_RESULT __TCA_POLICE_MAX +#define TCA_POLICE_RESULT TCA_POLICE_RESULT }; #define TCA_POLICE_MAX (__TCA_POLICE_MAX - 1) @@ -50,6 +186,12 @@ enum TCA_U32_DIVISOR, TCA_U32_SEL, TCA_U32_POLICE, +#ifdef CONFIG_NET_CLS_ACT + TCA_U32_ACT, +#endif +#ifdef CONFIG_NET_CLS_IND + TCA_U32_INDEV, +#endif __TCA_U32_MAX }; @@ -61,6 +203,9 @@ struct tc_u32_key __u32 val; int off; int offmask; +#ifdef CONFIG_CLS_U32_PERF + unsigned long kcnt; +#endif }; struct tc_u32_sel @@ -68,6 +213,7 @@ struct tc_u32_sel unsigned char flags; unsigned char offshift; unsigned char nkeys; + unsigned char fshift; /* fold shift */ __u16 offmask; __u16 off; @@ -75,7 +221,10 @@ struct tc_u32_sel short hoff; __u32 hmask; - +#ifdef CONFIG_CLS_U32_PERF + unsigned long rcnt; + unsigned long rhit; +#endif struct tc_u32_key keys[0]; }; @@ -102,7 +251,7 @@ enum __TCA_RSVP_MAX }; -#define TCA_RSVP_MAX (__TCA_RSVP_MAX - 1) +#define TCA_RSVP_MAX (__TCA_RSVP_MAX - 1 ) struct tc_rsvp_gpi { @@ -143,6 +292,12 @@ enum TCA_FW_UNSPEC, TCA_FW_CLASSID, TCA_FW_POLICE, +#ifdef CONFIG_NET_CLS_IND + TCA_FW_INDEV, +#endif +#ifdef CONFIG_NET_CLS_ACT + TCA_FW_ACT, +#endif __TCA_FW_MAX }; @@ -162,6 +317,6 @@ enum __TCA_TCINDEX_MAX }; -#define TCA_TCINDEX_MAX (__TCA_TCINDEX_MAX - 1) +#define TCA_TCINDEX_MAX (__TCA_TCINDEX_MAX - 1) #endif diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h index a3d6b59af515..437cf3206e0e 100644 --- a/include/linux/pkt_sched.h +++ b/include/linux/pkt_sched.h @@ -37,6 +37,7 @@ struct tc_stats __u32 bps; /* Current flow byte rate */ __u32 pps; /* Current flow packet rate */ __u32 qlen; + __u32 reqs; /* number of requeues happened */ __u32 backlog; #ifdef __KERNEL__ spinlock_t *lock; diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index 4b3a0b5d44b6..366eae3b4fc3 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -44,6 +44,10 @@ #define RTM_DELTFILTER (RTM_BASE+29) #define RTM_GETTFILTER (RTM_BASE+30) +#define RTM_NEWACTION (RTM_BASE+32) +#define RTM_DELACTION (RTM_BASE+33) +#define RTM_GETACTION (RTM_BASE+34) + #define RTM_NEWPREFIX (RTM_BASE+36) #define RTM_GETPREFIX (RTM_BASE+38) @@ -639,6 +643,7 @@ enum TCA_STATS, TCA_XSTATS, TCA_RATE, + TCA_FCNT, __TCA_MAX }; @@ -673,6 +678,18 @@ enum #define RTMGRP_IPV6_PREFIX 0x20000 +/* TC action piece */ +struct tcamsg +{ + unsigned char tca_family; + unsigned char tca__pad1; + unsigned short tca__pad2; +}; +#define TA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct tcamsg)))) +#define TA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct tcamsg)) +#define TCA_ACT_TAB 1 /* attr type must be >=1 */ +#define TCAA_MAX 1 + /* End of information exported to user level */ #ifdef __KERNEL__ diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 7bf6501a9024..dcadb7781b9d 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -155,6 +155,7 @@ struct skb_shared_info { * @sk: Socket we are owned by * @stamp: Time we arrived * @dev: Device we arrived on/are leaving by + * @input_dev: Device we arrived on * @real_dev: The real device we are using * @h: Transport layer header * @nh: Network layer header @@ -197,6 +198,7 @@ struct sk_buff { struct sock *sk; struct timeval stamp; struct net_device *dev; + struct net_device *input_dev; struct net_device *real_dev; union { @@ -262,9 +264,15 @@ struct sk_buff { } private; #endif #ifdef CONFIG_NET_SCHED - __u32 tc_index; /* traffic control index */ + __u32 tc_index; /* traffic control index */ +#ifdef CONFIG_NET_CLS_ACT + __u32 tc_verd; /* traffic control verdict */ + __u32 tc_classid; /* traffic control classid */ + #endif + #endif + /* These elements must be at the end, see alloc_skb() for details. */ unsigned int truesize; atomic_t users; -- cgit v1.2.3 From d51d5d95df511761ed5493df34aa8c2a7e33e900 Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Sun, 20 Jun 2004 00:18:46 -0700 Subject: [NET]: Fix module refcounting of TC actions. --- include/linux/pkt_cls.h | 27 ++++++++++++------ include/linux/pkt_sched.h | 6 ++++ include/net/pkt_act.h | 14 +++++----- include/net/pkt_sched.h | 15 ++++++---- net/sched/Kconfig | 12 +++++--- net/sched/act_api.c | 70 ++++++++++++++++++++++++++++++++++++----------- net/sched/cls_u32.c | 25 ++++++++--------- net/sched/police.c | 27 ++++++++++-------- net/sched/sch_prio.c | 3 +- 9 files changed, 133 insertions(+), 66 deletions(-) (limited to 'include/linux') diff --git a/include/linux/pkt_cls.h b/include/linux/pkt_cls.h index 74daa67e81c9..06e4e728d4fc 100644 --- a/include/linux/pkt_cls.h +++ b/include/linux/pkt_cls.h @@ -71,16 +71,14 @@ bits 9,10,11: redirect counter - redirect TTL. Loop avoidance #define V_TC_AT(x) _TC_MAKEVALUE(x,S_TC_AT) #define SET_TC_AT(v,n) ((V_TC_AT(n)) | (v & ~M_TC_AT)) -/* Action types */ +/* Action attributes */ enum { - TCA_ACT_UNSPEC=0, - TCA_ACT_KIND=1, - TCA_ACT_OPTIONS=2, - TCA_ACT_INDEX=3, - TCA_ACT_POLICE=4, - /* other actions go here */ - __TCA_ACT_MAX=255 + TCA_ACT_UNSPEC, + TCA_ACT_KIND, + TCA_ACT_OPTIONS, + TCA_ACT_INDEX, + __TCA_ACT_MAX }; #define TCA_ACT_MAX __TCA_ACT_MAX @@ -105,6 +103,17 @@ enum #define TC_ACT_REPEAT 6 #define TC_ACT_JUMP 0x10000000 +/* Action type identifiers*/ +enum +{ + TCA_ID_UNSPEC=0, + TCA_ID_POLICE=1, + /* other actions go here */ + __TCA_ID_MAX=255 +}; + +#define TCA_ID_MAX __TCA_ID_MAX + struct tc_police { __u32 index; @@ -213,7 +222,9 @@ struct tc_u32_sel unsigned char flags; unsigned char offshift; unsigned char nkeys; +#ifdef fix_u32_bug unsigned char fshift; /* fold shift */ +#endif __u16 offmask; __u16 off; diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h index 437cf3206e0e..86f98b500fa6 100644 --- a/include/linux/pkt_sched.h +++ b/include/linux/pkt_sched.h @@ -37,7 +37,13 @@ struct tc_stats __u32 bps; /* Current flow byte rate */ __u32 pps; /* Current flow packet rate */ __u32 qlen; +#ifdef CONFIG_NET_CLS_ACT +/* eventually remove the define here; adding this(useful) +field at least fixes the 8 byte layout problems we +have with MIPS and PPC because we have a u64 +*/ __u32 reqs; /* number of requeues happened */ +#endif __u32 backlog; #ifdef __KERNEL__ spinlock_t *lock; diff --git a/include/net/pkt_act.h b/include/net/pkt_act.h index 390b82aea577..9f37ac40f1a0 100644 --- a/include/net/pkt_act.h +++ b/include/net/pkt_act.h @@ -69,20 +69,21 @@ tcf_hash_destroy(struct tcf_st *p) BUG_TRAP(0); } -static inline void +static inline int tcf_hash_release(struct tcf_st *p, int bind ) { + int ret = 0; if (p) { if (bind) { p->bindcnt--; } p->refcnt--; - if (p->refcnt > 0) - MOD_DEC_USE_COUNT; if(p->bindcnt <=0 && p->refcnt <= 0) { tcf_hash_destroy(p); + ret = 1; } } + return ret; } static __inline__ int @@ -117,7 +118,6 @@ tcf_dump_walker(struct sk_buff *skb, struct netlink_callback *cb, r->rta_len = skb->tail - (u8*)r; n_i++; if (n_i >= TCA_ACT_MAX_PRIO) { - printk("Jamal Dump Exceeded batch limit\n"); goto done; } } @@ -148,8 +148,9 @@ tcf_del_walker(struct sk_buff *skb, struct tc_action *a) while (p != NULL) { s_p = p->next; - printk("tcf_del_walker deleting ..\n"); - tcf_hash_release(p, 0); + if (ACT_P_DELETED == tcf_hash_release(p, 0)) { + module_put(a->ops->owner); + } n_i++; p = s_p; } @@ -250,7 +251,6 @@ tcf_hash_create(struct tc_st *parm, struct rtattr *est, struct tc_action *a, int p->bindcnt = 1; } - MOD_INC_USE_COUNT; spin_lock_init(&p->lock); p->stats.lock = &p->lock; p->index = parm->index ? : tcf_hash_new_index(); diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h index eb6c344ddd95..f0d5fc3b66cc 100644 --- a/include/net/pkt_sched.h +++ b/include/net/pkt_sched.h @@ -414,6 +414,8 @@ struct tcf_police #ifdef CONFIG_NET_CLS_ACT +#define ACT_P_CREATED 1 +#define ACT_P_DELETED 1 #define tca_gen(name) \ struct tcf_##name *next; \ u32 index; \ @@ -442,10 +444,11 @@ struct tc_action_ops char kind[IFNAMSIZ]; __u32 type; /* TBD to match kind */ __u32 capab; /* capabilities includes 4 bit version */ + struct module *owner; int (*act)(struct sk_buff **, struct tc_action *); int (*get_stats)(struct sk_buff *, struct tc_action *); int (*dump)(struct sk_buff *, struct tc_action *,int , int); - void (*cleanup)(struct tc_action *, int bind); + int (*cleanup)(struct tc_action *, int bind); int (*lookup)(struct tc_action *, u32 ); int (*init)(struct rtattr *,struct rtattr *,struct tc_action *, int , int ); int (*walk)(struct sk_buff *, struct netlink_callback *, int , struct tc_action *); @@ -472,24 +475,26 @@ extern void tcf_police_destroy(struct tcf_police *p); extern struct tcf_police * tcf_police_locate(struct rtattr *rta, struct rtattr *est); extern int tcf_police_dump(struct sk_buff *skb, struct tcf_police *p); -static inline void tcf_police_release(struct tcf_police *p, int bind) +static inline int tcf_police_release(struct tcf_police *p, int bind) { + int ret = 0; #ifdef CONFIG_NET_CLS_ACT if (p) { if (bind) { p->bindcnt--; } p->refcnt--; - if (p->refcnt > 0) - MOD_DEC_USE_COUNT; - if (p->refcnt <= 0 && !p->bindcnt) + if (p->refcnt <= 0 && !p->bindcnt) { tcf_police_destroy(p); + ret = 1; + } } #else if (p && --p->refcnt == 0) tcf_police_destroy(p); #endif + return ret; } extern struct Qdisc noop_qdisc; diff --git a/net/sched/Kconfig b/net/sched/Kconfig index 481b8ad2b84c..924e9f2dcee7 100644 --- a/net/sched/Kconfig +++ b/net/sched/Kconfig @@ -280,6 +280,7 @@ config CLS_U32_PERF help gathers stats that could be used to tune u32 classifier perfomance. Requires a new iproute2 + You MUST NOT turn this on if you dont have an update iproute2. config NET_CLS_IND bool "classify input device (slows things u32/fw) " @@ -289,6 +290,7 @@ config NET_CLS_IND metadata action appears because it slows things a little Available only for u32 and fw classifiers. Requires a new iproute2 + You MUST NOT turn this on if you dont have an update iproute2. config NET_CLS_RSVP tristate "Special RSVP classifier" @@ -321,22 +323,24 @@ config NET_CLS_RSVP6 config NET_CLS_ACT bool ' Packet ACTION ' - depends on NET_CLS && NET_QOS + depends on EXPERIMENTAL && NET_CLS && NET_QOS ---help--- This option requires you have a new iproute2. It enables tc extensions which can be used with tc classifiers. Only the u32 and fw classifiers are supported at the moment. + You MUST NOT turn this on if you dont have an update iproute2. config NET_ACT_POLICE tristate ' Policing Actions' - depends on NET_CLS_ACT + depends on NET_CLS_ACT ---help--- If you are using a newer iproute2 select this one, otherwise use one - NET_CLS_POLICE below + below to select a policer. + You MUST NOT turn this on if you dont have an update iproute2. config NET_CLS_POLICE bool "Traffic policing (needed for in/egress)" - depends on NET_CLS && NET_QOS && !NET_ACT_POLICE + depends on NET_CLS && NET_QOS && NET_ACT_POLICE!=y && NET_ACT_POLICE!=m help Say Y to support traffic policing (bandwidth limits). Needed for ingress and egress rate limiting. diff --git a/net/sched/act_api.c b/net/sched/act_api.c index a0ba2f6363e9..91076dc78b5d 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c @@ -48,11 +48,12 @@ int tcf_register_action(struct tc_action_ops *act) write_lock(&act_mod_lock); for (ap = &act_base; (a=*ap)!=NULL; ap = &a->next) { - if (strcmp(act->kind, a->kind) == 0) { + if (act->type == a->type || (strcmp(act->kind, a->kind) == 0)) { write_unlock(&act_mod_lock); return -EEXIST; } } + act->next = NULL; *ap = act; @@ -89,8 +90,13 @@ struct tc_action_ops *tc_lookup_action_n(char *kind) if (kind) { read_lock(&act_mod_lock); for (a = act_base; a; a = a->next) { - if (strcmp(kind,a->kind) == 0) + if (strcmp(kind,a->kind) == 0) { + if (!try_module_get(a->owner)) { + read_unlock(&act_mod_lock); + return NULL; + } break; + } } read_unlock(&act_mod_lock); } @@ -108,8 +114,13 @@ struct tc_action_ops *tc_lookup_action(struct rtattr *kind) read_lock(&act_mod_lock); for (a = act_base; a; a = a->next) { - if (strcmp((char*)RTA_DATA(kind),a->kind) == 0) + if (strcmp((char*)RTA_DATA(kind),a->kind) == 0){ + if (!try_module_get(a->owner)) { + read_unlock(&act_mod_lock); + return NULL; + } break; + } } read_unlock(&act_mod_lock); } @@ -125,8 +136,13 @@ struct tc_action_ops *tc_lookup_action_id(u32 type) if (type) { read_lock(&act_mod_lock); for (a = act_base; a; a = a->next) { - if (a->type == type) + if (a->type == type) { + if (!try_module_get(a->owner)) { + read_unlock(&act_mod_lock); + return NULL; + } break; + } } read_unlock(&act_mod_lock); } @@ -177,7 +193,10 @@ void tcf_action_destroy(struct tc_action *act, int bind) if (a && a->ops && a->ops->cleanup) { DPRINTK("tcf_action_destroy destroying %p next %p\n", a,a->next?a->next:NULL); act = act->next; - a->ops->cleanup(a, bind); + if (ACT_P_DELETED == a->ops->cleanup(a, bind)) { + module_put(a->ops->owner); + } + a->ops = NULL; kfree(a); } else { /*FIXME: Remove later - catch insertion bugs*/ @@ -270,7 +289,6 @@ int tcf_action_init_1(struct rtattr *rta, struct rtattr *est, struct tc_action * int err = -EINVAL; - if (NULL == name) { if (rtattr_parse(tb, TCA_ACT_MAX, RTA_DATA(rta), RTA_PAYLOAD(rta))<0) goto err_out; @@ -306,27 +324,37 @@ int tcf_action_init_1(struct rtattr *rta, struct rtattr *est, struct tc_action * } if (NULL == a) { - goto err_out; + goto err_mod; } /* backward compatibility for policer */ if (NULL == name) { err = a_o->init(tb[TCA_ACT_OPTIONS-1], est, a, ovr, bind); if (0 > err ) { - return -EINVAL; + err = -EINVAL; + goto err_mod; } } else { err = a_o->init(rta, est, a, ovr, bind); if (0 > err ) { - return -EINVAL; + err = -EINVAL; + goto err_mod; } } - DPRINTK("tcf_action_init_1: sucess %s\n",act_name); - + /* module count goes up only when brand new policy is created + if it exists and is only bound to in a_o->init() then + ACT_P_CREATED is not returned (a zero is). + */ + if (ACT_P_CREATED != err) { + module_put(a_o->owner); + } a->ops = a_o; + DPRINTK("tcf_action_init_1: successfull %s \n",act_name); return 0; +err_mod: + module_put(a_o->owner); err_out: return err; } @@ -350,7 +378,7 @@ int tcf_action_init(struct rtattr *rta, struct rtattr *est, struct tc_action *a, err = -ENOMEM; goto bad_ret; } - memset(act, 0,sizeof(*act)); + memset(act, 0,sizeof(*act)); } act->next = NULL; if (0 > tcf_action_init_1(tb[i],est,act,name,ovr,bind)) { @@ -489,15 +517,21 @@ int tcf_action_get_1(struct rtattr *rta, struct tc_action *a, struct nlmsghdr *n } if (NULL == a) { - goto err_out; + goto err_mod; } a->ops = a_o; - if (NULL == a_o->lookup || 0 == a_o->lookup(a, index)) - return -EINVAL; + if (NULL == a_o->lookup || 0 == a_o->lookup(a, index)) { + a->ops = NULL; + err = -EINVAL; + goto err_mod; + } + module_put(a_o->owner); return 0; +err_mod: + module_put(a_o->owner); err_out: return err; } @@ -621,6 +655,7 @@ int tca_action_flush(struct rtattr *rta, struct nlmsghdr *n, u32 pid) nlh->nlmsg_len = skb->tail - b; nlh->nlmsg_flags |= NLM_F_ROOT; + module_put(a->ops->owner); kfree(a); err = rtnetlink_send(skb, pid, RTMGRP_TC, n->nlmsg_flags&NLM_F_ECHO); if (err > 0) @@ -630,6 +665,7 @@ int tca_action_flush(struct rtattr *rta, struct nlmsghdr *n, u32 pid) rtattr_failure: + module_put(a->ops->owner); nlmsg_failure: err_out: kfree_skb(skb); @@ -852,7 +888,7 @@ static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n, void *arg) char * find_dump_kind(struct nlmsghdr *n) { - struct rtattr *tb1, *tb2[TCA_ACT_MAX_PRIO+1]; + struct rtattr *tb1, *tb2[TCA_ACT_MAX+1]; struct rtattr *tb[TCA_ACT_MAX_PRIO + 1]; struct rtattr *rta[TCAA_MAX + 1]; struct rtattr *kind = NULL; @@ -941,10 +977,12 @@ tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb) nlh->nlmsg_len = skb->tail - b; if (NETLINK_CB(cb->skb).pid && ret) nlh->nlmsg_flags |= NLM_F_MULTI; + module_put(a_o->owner); return skb->len; rtattr_failure: nlmsg_failure: + module_put(a_o->owner); skb_trim(skb, b - skb->data); return skb->len; } diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index 7ea20b622fc8..24620274d6b8 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c @@ -101,12 +101,14 @@ static struct tc_u_common *u32_list; static __inline__ unsigned u32_hash_fold(u32 key, struct tc_u32_sel *sel) { +#ifdef fix_u32_bug unsigned h = (key & sel->hmask)>>sel->fshift; +#else + unsigned h = (key & sel->hmask); - /* h ^= h>>16; h ^= h>>8; - */ +#endif return h; } @@ -684,6 +686,14 @@ static int u32_change(struct tcf_proto *tp, unsigned long base, u32 handle, return -EINVAL; s = RTA_DATA(tb[TCA_U32_SEL-1]); + +#ifdef CONFIG_CLS_U32_PERF + if (RTA_PAYLOAD(tb[TCA_U32_SEL-1]) < + (s->nkeys*sizeof(struct tc_u32_key)) + sizeof(struct tc_u32_sel)) { + printk("Please upgrade your iproute2 tools or compile proper options in!\n"); + return -EINVAL; +} +#endif n = kmalloc(sizeof(*n) + s->nkeys*sizeof(struct tc_u32_key), GFP_KERNEL); if (n == NULL) return -ENOBUFS; @@ -775,18 +785,7 @@ static int u32_dump(struct tcf_proto *tp, unsigned long fh, if (n->ht_down) RTA_PUT(skb, TCA_U32_LINK, 4, &n->ht_down->handle); #ifdef CONFIG_CLS_U32_PERF2 - printk("fh %x cnt %lu hit %lu\n",n->handle,n->sel.rcnt,n->sel.rhit); n->sel.rcnt = n->sel.rhit = 0; - /* dump key cnt */ - { - int i = 0; - struct tc_u32_key *key = n->sel.keys; - for (i = n->sel.nkeys; i>0; i--, key++) { - printk("\t key%d success %lu\n",i,key->kcnt); - key->cnt = 0; - } - } - #endif #ifdef CONFIG_NET_CLS_ACT /* again for backward compatible mode - we want diff --git a/net/sched/police.c b/net/sched/police.c index 14ccbae43858..2556651b7366 100644 --- a/net/sched/police.c +++ b/net/sched/police.c @@ -166,6 +166,7 @@ void tcf_police_destroy(struct tcf_police *p) int tcf_act_police_locate(struct rtattr *rta, struct rtattr *est,struct tc_action *a, int ovr, int bind) { unsigned h; + int ret = 0; struct rtattr *tb[TCA_POLICE_MAX]; struct tc_police *parm; struct tcf_police *p; @@ -195,7 +196,7 @@ int tcf_act_police_locate(struct rtattr *rta, struct rtattr *est,struct tc_actio goto override; } spin_unlock(&p->lock); - return 1; + return ret; } p = kmalloc(sizeof(*p), GFP_KERNEL); @@ -203,7 +204,7 @@ int tcf_act_police_locate(struct rtattr *rta, struct rtattr *est,struct tc_actio return -1; memset(p, 0, sizeof(*p)); - MOD_INC_USE_COUNT; + ret = 1; p->refcnt = 1; spin_lock_init(&p->lock); p->stats.lock = &p->lock; @@ -211,11 +212,13 @@ int tcf_act_police_locate(struct rtattr *rta, struct rtattr *est,struct tc_actio p->bindcnt = 1; override: if (parm->rate.rate) { - if ((p->R_tab = qdisc_get_rtab(&parm->rate, tb[TCA_POLICE_RATE-1])) == NULL) + if ((p->R_tab = qdisc_get_rtab(&parm->rate, tb[TCA_POLICE_RATE-1])) == NULL) { goto failure; + } if (parm->peakrate.rate && - (p->P_tab = qdisc_get_rtab(&parm->peakrate, tb[TCA_POLICE_PEAKRATE-1])) == NULL) + (p->P_tab = qdisc_get_rtab(&parm->peakrate, tb[TCA_POLICE_PEAKRATE-1])) == NULL) { goto failure; + } } if (tb[TCA_POLICE_RESULT-1]) p->result = *(int*)RTA_DATA(tb[TCA_POLICE_RESULT-1]); @@ -236,7 +239,7 @@ override: if (ovr) { spin_unlock(&p->lock); - return 1; + return ret; } PSCHED_GET_TIME(p->t_c); p->index = parm->index ? : tcf_police_new_index(); @@ -250,9 +253,8 @@ override: tcf_police_ht[h] = p; write_unlock_bh(&police_lock); - MOD_INC_USE_COUNT; a->priv = (void *)p; - return 1; + return ret; failure: if (p->R_tab) @@ -263,12 +265,14 @@ failure: return -1; } -void tcf_act_police_cleanup(struct tc_action *a, int bind) +int tcf_act_police_cleanup(struct tc_action *a, int bind) { struct tcf_police *p; p = PRIV(a); if (NULL != p) - tcf_police_release(p, bind); + return tcf_police_release(p, bind); + + return 0; } int tcf_act_police_stats(struct sk_buff *skb, struct tc_action *a) @@ -392,8 +396,9 @@ MODULE_LICENSE("GPL"); struct tc_action_ops act_police_ops = { NULL, "police", - TCA_ACT_POLICE, + TCA_ID_POLICE, TCA_CAP_NONE, + THIS_MODULE, tcf_act_police, tcf_act_police_stats, tcf_act_police_dump, @@ -437,7 +442,6 @@ struct tcf_police * tcf_police_locate(struct rtattr *rta, struct rtattr *est) if (parm->index && (p = tcf_police_lookup(parm->index)) != NULL) { p->refcnt++; - MOD_INC_USE_COUNT; return p; } @@ -483,7 +487,6 @@ struct tcf_police * tcf_police_locate(struct rtattr *rta, struct rtattr *est) p->next = tcf_police_ht[h]; tcf_police_ht[h] = p; write_unlock_bh(&police_lock); - MOD_INC_USE_COUNT; return p; failure: diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c index 52a4c2e28272..fa6741d96a27 100644 --- a/net/sched/sch_prio.c +++ b/net/sched/sch_prio.c @@ -129,11 +129,12 @@ dropped: static int prio_requeue(struct sk_buff *skb, struct Qdisc* sch) { - //struct prio_sched_data *q = (struct prio_sched_data *)sch->data; struct Qdisc *qdisc; int ret = NET_XMIT_DROP; +#ifdef CONFIG_NET_CLS_ACT sch->stats.reqs++; +#endif qdisc = prio_classify(skb, sch, &ret); if (qdisc == NULL) goto dropped; -- cgit v1.2.3 From 30962905aa5bfcd061496ff9f6dc22006dfd4c09 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 21 Jun 2004 00:28:23 -0700 Subject: [NETFILTER]: Fix non-existant config option for IP_NF_ASSERT, fix some broken assertions Signed-off-by: Patrick McHardy Signed-off-by: Harald Welte Signed-off-by: David S. Miller --- include/linux/netfilter_ipv4/ip_conntrack.h | 2 +- net/ipv4/netfilter/ip_conntrack_core.c | 4 +--- net/ipv4/netfilter/ip_nat_core.c | 5 +++-- 3 files changed, 5 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netfilter_ipv4/ip_conntrack.h b/include/linux/netfilter_ipv4/ip_conntrack.h index 26d7f3a11fd7..1974f162f5a0 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack.h +++ b/include/linux/netfilter_ipv4/ip_conntrack.h @@ -103,7 +103,7 @@ union ip_conntrack_nat_help { #include #include -#ifdef CONFIG_NF_DEBUG +#ifdef CONFIG_NETFILTER_DEBUG #define IP_NF_ASSERT(x) \ do { \ if (!(x)) \ diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c index 1f47e9bbc4eb..35b7e8f3330d 100644 --- a/net/ipv4/netfilter/ip_conntrack_core.c +++ b/net/ipv4/netfilter/ip_conntrack_core.c @@ -174,13 +174,12 @@ static void destroy_expect(struct ip_conntrack_expect *exp) { DEBUGP("destroy_expect(%p) use=%d\n", exp, atomic_read(&exp->use)); - IP_NF_ASSERT(atomic_read(&exp->use)); + IP_NF_ASSERT(atomic_read(&exp->use) == 0); IP_NF_ASSERT(!timer_pending(&exp->timeout)); kfree(exp); } - inline void ip_conntrack_expect_put(struct ip_conntrack_expect *exp) { IP_NF_ASSERT(exp); @@ -716,7 +715,6 @@ init_conntrack(const struct ip_conntrack_tuple *tuple, DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n", conntrack, expected); /* Welcome, Mr. Bond. We've been expecting you... */ - IP_NF_ASSERT(master_ct(conntrack)); __set_bit(IPS_EXPECTED_BIT, &conntrack->status); conntrack->master = expected; expected->sibling = conntrack; diff --git a/net/ipv4/netfilter/ip_nat_core.c b/net/ipv4/netfilter/ip_nat_core.c index 3e5ca975459d..40116b9850d1 100644 --- a/net/ipv4/netfilter/ip_nat_core.c +++ b/net/ipv4/netfilter/ip_nat_core.c @@ -528,6 +528,7 @@ ip_nat_setup_info(struct ip_conntrack *conntrack, MUST_BE_WRITE_LOCKED(&ip_nat_lock); IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING || hooknum == NF_IP_POST_ROUTING + || hooknum == NF_IP_LOCAL_IN || hooknum == NF_IP_LOCAL_OUT); IP_NF_ASSERT(info->num_manips < IP_NAT_MAX_MANIPS); IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum)))); @@ -899,10 +900,10 @@ icmp_reply_translation(struct sk_buff **pskb, /* Must be RELATED */ IP_NF_ASSERT((*pskb)->nfct - - (struct ip_conntrack *)(*pskb)->nfct->master + - ((struct ip_conntrack *)(*pskb)->nfct->master)->infos == IP_CT_RELATED || (*pskb)->nfct - - (struct ip_conntrack *)(*pskb)->nfct->master + - ((struct ip_conntrack *)(*pskb)->nfct->master)->infos == IP_CT_RELATED+IP_CT_IS_REPLY); /* Redirects on non-null nats must be dropped, else they'll -- cgit v1.2.3 From 02c83c2e15de9b2a06275388f0b288a2af92ad3e Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 21 Jun 2004 00:34:20 -0700 Subject: [NETFILTER]: Add new function 'nf_reset' to reset netfilter related skb-fields Signed-off-by: Patrick McHardy Signed-off-by: Harald Welte Signed-off-by: David S. Miller --- include/linux/skbuff.h | 15 ++++++++++++--- net/ipv4/ip_gre.c | 16 ++-------------- net/ipv4/ip_input.c | 6 +----- net/ipv4/ipip.c | 16 ++-------------- net/ipv4/ipmr.c | 15 +++------------ net/ipv4/netfilter/ipt_REJECT.c | 6 +----- net/ipv6/ip6_tunnel.c | 8 +------- net/ipv6/sit.c | 16 ++-------------- 8 files changed, 24 insertions(+), 74 deletions(-) (limited to 'include/linux') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 1b33d607f276..f47163e84760 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1109,6 +1109,14 @@ static inline void nf_conntrack_get(struct nf_ct_info *nfct) if (nfct) atomic_inc(&nfct->master->use); } +static inline void nf_reset(struct sk_buff *skb) +{ + nf_conntrack_put(skb->nfct); + skb->nfct = NULL; +#ifdef CONFIG_NETFILTER_DEBUG + skb->nf_debug = 0; +#endif +} #ifdef CONFIG_BRIDGE_NETFILTER static inline void nf_bridge_put(struct nf_bridge_info *nf_bridge) @@ -1121,9 +1129,10 @@ static inline void nf_bridge_get(struct nf_bridge_info *nf_bridge) if (nf_bridge) atomic_inc(&nf_bridge->use); } -#endif - -#endif +#endif /* CONFIG_BRIDGE_NETFILTER */ +#else /* CONFIG_NETFILTER */ +static inline void nf_reset(struct sk_buff *skb) {} +#endif /* CONFIG_NETFILTER */ #endif /* __KERNEL__ */ #endif /* _LINUX_SKBUFF_H */ diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 4a227f51b2c1..0c2f8ca5ae83 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -643,13 +643,7 @@ int ipgre_rcv(struct sk_buff *skb) skb->dev = tunnel->dev; dst_release(skb->dst); skb->dst = NULL; -#ifdef CONFIG_NETFILTER - nf_conntrack_put(skb->nfct); - skb->nfct = NULL; -#ifdef CONFIG_NETFILTER_DEBUG - skb->nf_debug = 0; -#endif -#endif + nf_reset(skb); ipgre_ecn_decapsulate(iph, skb); netif_rx(skb); read_unlock(&ipgre_lock); @@ -877,13 +871,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) } } -#ifdef CONFIG_NETFILTER - nf_conntrack_put(skb->nfct); - skb->nfct = NULL; -#ifdef CONFIG_NETFILTER_DEBUG - skb->nf_debug = 0; -#endif -#endif + nf_reset(skb); IPTUNNEL_XMIT(); tunnel->recursion--; diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index 2f71ed5cfcc9..5b473004fab9 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -202,17 +202,13 @@ static inline int ip_local_deliver_finish(struct sk_buff *skb) #ifdef CONFIG_NETFILTER_DEBUG nf_debug_ip_local_deliver(skb); - skb->nf_debug = 0; #endif /*CONFIG_NETFILTER_DEBUG*/ __skb_pull(skb, ihl); -#ifdef CONFIG_NETFILTER /* Free reference early: we don't need it any more, and it may hold ip_conntrack module loaded indefinitely. */ - nf_conntrack_put(skb->nfct); - skb->nfct = NULL; -#endif /*CONFIG_NETFILTER*/ + nf_reset(skb); /* Point into the IP datagram, just past the header. */ skb->h.raw = skb->data; diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 757b1d3f6aa2..98ba22404ac3 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -497,13 +497,7 @@ static int ipip_rcv(struct sk_buff *skb) skb->dev = tunnel->dev; dst_release(skb->dst); skb->dst = NULL; -#ifdef CONFIG_NETFILTER - nf_conntrack_put(skb->nfct); - skb->nfct = NULL; -#ifdef CONFIG_NETFILTER_DEBUG - skb->nf_debug = 0; -#endif -#endif + nf_reset(skb); ipip_ecn_decapsulate(iph, skb); netif_rx(skb); read_unlock(&ipip_lock); @@ -648,13 +642,7 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) if ((iph->ttl = tiph->ttl) == 0) iph->ttl = old_iph->ttl; -#ifdef CONFIG_NETFILTER - nf_conntrack_put(skb->nfct); - skb->nfct = NULL; -#ifdef CONFIG_NETFILTER_DEBUG - skb->nf_debug = 0; -#endif -#endif + nf_reset(skb); IPTUNNEL_XMIT(); tunnel->recursion--; diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index a25e56077072..3aecdcf5e085 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -1105,10 +1105,7 @@ static void ip_encap(struct sk_buff *skb, u32 saddr, u32 daddr) skb->h.ipiph = skb->nh.iph; skb->nh.iph = iph; memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); -#ifdef CONFIG_NETFILTER - nf_conntrack_put(skb->nfct); - skb->nfct = NULL; -#endif + nf_reset(skb); } static inline int ipmr_forward_finish(struct sk_buff *skb) @@ -1461,10 +1458,7 @@ int pim_rcv_v1(struct sk_buff * skb) skb->dst = NULL; ((struct net_device_stats*)reg_dev->priv)->rx_bytes += skb->len; ((struct net_device_stats*)reg_dev->priv)->rx_packets++; -#ifdef CONFIG_NETFILTER - nf_conntrack_put(skb->nfct); - skb->nfct = NULL; -#endif + nf_reset(skb); netif_rx(skb); dev_put(reg_dev); return 0; @@ -1520,10 +1514,7 @@ static int pim_rcv(struct sk_buff * skb) ((struct net_device_stats*)reg_dev->priv)->rx_bytes += skb->len; ((struct net_device_stats*)reg_dev->priv)->rx_packets++; skb->dst = NULL; -#ifdef CONFIG_NETFILTER - nf_conntrack_put(skb->nfct); - skb->nfct = NULL; -#endif + nf_reset(skb); netif_rx(skb); dev_put(reg_dev); return 0; diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c index f6183f968b2b..b8018cb023ff 100644 --- a/net/ipv4/netfilter/ipt_REJECT.c +++ b/net/ipv4/netfilter/ipt_REJECT.c @@ -142,12 +142,8 @@ static void send_reset(struct sk_buff *oldskb, int hook) nskb->dst = &rt->u.dst; /* This packet will not be the same as the other: clear nf fields */ - nf_conntrack_put(nskb->nfct); - nskb->nfct = NULL; + nf_reset(nskb); nskb->nfcache = 0; -#ifdef CONFIG_NETFILTER_DEBUG - nskb->nf_debug = 0; -#endif nskb->nfmark = 0; #ifdef CONFIG_BRIDGE_NETFILTER nf_bridge_put(nskb->nf_bridge); diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 9e5677dd45a2..0c8db0391a78 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -722,13 +722,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) ipv6h->nexthdr = proto; ipv6_addr_copy(&ipv6h->saddr, &fl.fl6_src); ipv6_addr_copy(&ipv6h->daddr, &fl.fl6_dst); -#ifdef CONFIG_NETFILTER - nf_conntrack_put(skb->nfct); - skb->nfct = NULL; -#ifdef CONFIG_NETFILTER_DEBUG - skb->nf_debug = 0; -#endif -#endif + nf_reset(skb); pkt_len = skb->len; err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, skb->dst->dev, dst_output); diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 2fac873fdd3d..2958bb9c76fe 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -388,13 +388,7 @@ static int ipip6_rcv(struct sk_buff *skb) skb->dev = tunnel->dev; dst_release(skb->dst); skb->dst = NULL; -#ifdef CONFIG_NETFILTER - nf_conntrack_put(skb->nfct); - skb->nfct = NULL; -#ifdef CONFIG_NETFILTER_DEBUG - skb->nf_debug = 0; -#endif -#endif + nf_reset(skb); ipip6_ecn_decapsulate(iph, skb); netif_rx(skb); read_unlock(&ipip6_lock); @@ -580,13 +574,7 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) if ((iph->ttl = tiph->ttl) == 0) iph->ttl = iph6->hop_limit; -#ifdef CONFIG_NETFILTER - nf_conntrack_put(skb->nfct); - skb->nfct = NULL; -#ifdef CONFIG_NETFILTER_DEBUG - skb->nf_debug = 0; -#endif -#endif + nf_reset(skb); IPTUNNEL_XMIT(); tunnel->recursion--; -- cgit v1.2.3 From fd4daaf7b32473367b25c2936d2cc71eb72e1e72 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 21 Jun 2004 00:36:31 -0700 Subject: [NETFILTER]: Add addrtype match Signed-off-by: Patrick McHardy Signed-off-by: Harald Welte Signed-off-by: David S. Miller --- include/linux/netfilter_ipv4/ipt_addrtype.h | 11 +++++ net/ipv4/netfilter/Kconfig | 10 ++++ net/ipv4/netfilter/Makefile | 1 + net/ipv4/netfilter/ipt_addrtype.c | 77 +++++++++++++++++++++++++++++ 4 files changed, 99 insertions(+) create mode 100644 include/linux/netfilter_ipv4/ipt_addrtype.h create mode 100644 net/ipv4/netfilter/ipt_addrtype.c (limited to 'include/linux') diff --git a/include/linux/netfilter_ipv4/ipt_addrtype.h b/include/linux/netfilter_ipv4/ipt_addrtype.h new file mode 100644 index 000000000000..166ed01a8122 --- /dev/null +++ b/include/linux/netfilter_ipv4/ipt_addrtype.h @@ -0,0 +1,11 @@ +#ifndef _IPT_ADDRTYPE_H +#define _IPT_ADDRTYPE_H + +struct ipt_addrtype_info { + u_int16_t source; /* source-type mask */ + u_int16_t dest; /* dest-type mask */ + u_int32_t invert_source; + u_int32_t invert_dest; +}; + +#endif diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index f5a5110f97da..5e9b01f74c30 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -603,5 +603,15 @@ config IP_NF_RAW . If unsure, say `N'. help +config IP_NF_MATCH_ADDRTYPE + tristate 'address type match support' + depends on IP_NF_IPTABLES + help + This option allows you to match what routing thinks of an address, + eg. UNICAST, LOCAL, BROADCAST, ... + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + endmenu diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 52bedf2d7c62..5893bc654ab0 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -64,6 +64,7 @@ obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o obj-$(CONFIG_IP_NF_MATCH_STATE) += ipt_state.o obj-$(CONFIG_IP_NF_MATCH_CONNTRACK) += ipt_conntrack.o obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o +obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o obj-$(CONFIG_IP_NF_MATCH_PHYSDEV) += ipt_physdev.o diff --git a/net/ipv4/netfilter/ipt_addrtype.c b/net/ipv4/netfilter/ipt_addrtype.c new file mode 100644 index 000000000000..7392ba6bd23f --- /dev/null +++ b/net/ipv4/netfilter/ipt_addrtype.c @@ -0,0 +1,77 @@ +/* + * iptables module to match inet_addr_type() of an ip. + * + * Copyright (c) 2004 Patrick McHardy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Patrick McHardy "); +MODULE_DESCRIPTION("iptables addrtype match"); + +static inline int match_type(u_int32_t addr, u_int16_t mask) +{ + return !!(mask & (1 << inet_addr_type(addr))); +} + +static int match(const struct sk_buff *skb, const struct net_device *in, + const struct net_device *out, const void *matchinfo, + int offset, int *hotdrop) +{ + const struct ipt_addrtype_info *info = matchinfo; + const struct iphdr *iph = skb->nh.iph; + int ret = 1; + + if (info->source) + ret &= match_type(iph->saddr, info->source)^info->invert_source; + if (info->dest) + ret &= match_type(iph->daddr, info->dest)^info->invert_dest; + + return ret; +} + +static int checkentry(const char *tablename, const struct ipt_ip *ip, + void *matchinfo, unsigned int matchsize, + unsigned int hook_mask) +{ + if (matchsize != IPT_ALIGN(sizeof(struct ipt_addrtype_info))) { + printk(KERN_ERR "ipt_addrtype: invalid size (%u != %u)\n.", + matchsize, IPT_ALIGN(sizeof(struct ipt_addrtype_info))); + return 0; + } + + return 1; +} + +static struct ipt_match addrtype_match = { + .name = "addrtype", + .match = match, + .checkentry = checkentry, + .me = THIS_MODULE +}; + +static int __init init(void) +{ + return ipt_register_match(&addrtype_match); +} + +static void __exit fini(void) +{ + ipt_unregister_match(&addrtype_match); +} + +module_init(init); +module_exit(fini); -- cgit v1.2.3 From e07d39a4fe747af843ca8ec76edc5531cc2fa551 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 21 Jun 2004 00:38:44 -0700 Subject: [NETFILTER]: Add realm match Signed-off-by: Patrick McHardy Signed-off-by: Harald Welte Signed-off-by: David S. Miller --- include/linux/netfilter_ipv4/ipt_realm.h | 10 +++++ net/ipv4/netfilter/Kconfig | 14 ++++++ net/ipv4/netfilter/Makefile | 1 + net/ipv4/netfilter/ipt_realm.c | 76 ++++++++++++++++++++++++++++++++ net/sched/Kconfig | 4 +- 5 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 include/linux/netfilter_ipv4/ipt_realm.h create mode 100644 net/ipv4/netfilter/ipt_realm.c (limited to 'include/linux') diff --git a/include/linux/netfilter_ipv4/ipt_realm.h b/include/linux/netfilter_ipv4/ipt_realm.h new file mode 100644 index 000000000000..a4d6698723ac --- /dev/null +++ b/include/linux/netfilter_ipv4/ipt_realm.h @@ -0,0 +1,10 @@ +#ifndef _IPT_REALM_H +#define _IPT_REALM_H + +struct ipt_realm_info { + u_int32_t id; + u_int32_t mask; + u_int8_t invert; +}; + +#endif /* _IPT_REALM_H */ diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 5e9b01f74c30..eaf79408bc03 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -613,5 +613,19 @@ config IP_NF_MATCH_ADDRTYPE If you want to compile it as a module, say M here and read Documentation/modules.txt. If unsure, say `N'. +config IP_NF_MATCH_REALM + tristate 'realm match support' + depends on IP_NF_IPTABLES + select NET_CLS_ROUTE + help + This option adds a `realm' match, which allows you to use the realm + key from the routing subsytem inside iptables. + + This match pretty much resembles the CONFIG_NET_CLS_ROUTE4 option + in tc world. + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + endmenu diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 5893bc654ab0..bdb23fde133f 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -64,6 +64,7 @@ obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o obj-$(CONFIG_IP_NF_MATCH_STATE) += ipt_state.o obj-$(CONFIG_IP_NF_MATCH_CONNTRACK) += ipt_conntrack.o obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o +obj-$(CONFIG_IP_NF_MATCH_REALM) += ipt_realm.o obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o obj-$(CONFIG_IP_NF_MATCH_PHYSDEV) += ipt_physdev.o diff --git a/net/ipv4/netfilter/ipt_realm.c b/net/ipv4/netfilter/ipt_realm.c new file mode 100644 index 000000000000..54a6897ebaa6 --- /dev/null +++ b/net/ipv4/netfilter/ipt_realm.c @@ -0,0 +1,76 @@ +/* IP tables module for matching the routing realm + * + * $Id: ipt_realm.c,v 1.3 2004/03/05 13:25:40 laforge Exp $ + * + * (C) 2003 by Sampsa Ranta + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +#include +#include + +MODULE_AUTHOR("Sampsa Ranta "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("iptables realm match"); + +static int +match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + int *hotdrop) +{ + const struct ipt_realm_info *info = matchinfo; + struct dst_entry *dst = skb->dst; + + return (info->id == (dst->tclassid & info->mask)) ^ info->invert; +} + +static int check(const char *tablename, + const struct ipt_ip *ip, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + if (hook_mask + & ~((1 << NF_IP_POST_ROUTING) | (1 << NF_IP_FORWARD) | + (1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_LOCAL_IN))) { + printk("ipt_realm: only valid for POST_ROUTING, LOCAL_OUT, " + "LOCAL_IN or FORWARD.\n"); + return 0; + } + if (matchsize != IPT_ALIGN(sizeof(struct ipt_realm_info))) { + printk("ipt_realm: invalid matchsize.\n"); + return 0; + } + return 1; +} + +static struct ipt_match realm_match = { + .name = "realm", + .match = match, + .checkentry = check, + .me = THIS_MODULE +}; + +static int __init init(void) +{ + return ipt_register_match(&realm_match); +} + +static void __exit fini(void) +{ + ipt_unregister_match(&realm_match); +} + +module_init(init); +module_exit(fini); diff --git a/net/sched/Kconfig b/net/sched/Kconfig index 8931426e0243..293655830d98 100644 --- a/net/sched/Kconfig +++ b/net/sched/Kconfig @@ -242,6 +242,7 @@ config NET_CLS_TCINDEX config NET_CLS_ROUTE4 tristate "Routing table based classifier" depends on NET_CLS + select NET_CLS_ROUTE help If you say Y here, you will be able to classify outgoing packets according to the route table entry they matched. If unsure, say Y. @@ -251,8 +252,7 @@ config NET_CLS_ROUTE4 config NET_CLS_ROUTE bool - depends on NET_CLS_ROUTE4 - default y + default n config NET_CLS_FW tristate "Firewall based classifier" -- cgit v1.2.3 From 694b677ff8b68d1a5b6692795615f6d118e96873 Mon Sep 17 00:00:00 2001 From: Marc Singer Date: Wed, 23 Jun 2004 02:44:18 +0100 Subject: [ARM PATCH] 1913/1: lh7a40x #3 (1/2) serial Patch from Marc Singer Serial console and port driver for the LH7a40x CPUs. The only change made since the last patch was to change the PORT_ID (again). This patch superceeds two serial driver patches. --- drivers/serial/Kconfig | 23 ++ drivers/serial/Makefile | 1 + drivers/serial/serial_lh7a40x.c | 708 ++++++++++++++++++++++++++++++++++++++++ include/linux/serial_core.h | 3 + 4 files changed, 735 insertions(+) create mode 100644 drivers/serial/serial_lh7a40x.c (limited to 'include/linux') diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index e5ce98eb0378..cb005e5a5bca 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -603,5 +603,28 @@ config SERIAL_PMACZILOG_CONSOLE on your PowerMac as the console, you can do so by answering Y to this option. +config SERIAL_LH7A40X + tristate "Sharp LH7A40X embedded UART support" + depends on ARM && ARCH_LH7A40X + select SERIAL_CORE + help + This enables support for the three on-board UARTs of the + Sharp LH7A40X series CPUs. Choose Y or M. + +config SERIAL_LH7A40X_CONSOLE + bool "Support for connsole on Sharp LH7A40X serial port" + depends on SERIAL_LH7A40X=y + select SERIAL_CORE_CONSOLE + help + Say Y here if you wish to use one of the serial ports as the + system console--the system console is the device which + receives all kernel messages and warnings and which allows + logins in single user mode. + + Even if you say Y here, the currently visible framebuffer console + (/dev/tty0) will still be used as the default system console, but + you can alter that using a kernel command line, for example + "console=ttyAM1". + endmenu diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index c2eb159d8b43..ceacc99d8cd1 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -34,6 +34,7 @@ obj-$(CONFIG_SERIAL_68360) += 68360serial.o obj-$(CONFIG_SERIAL_COLDFIRE) += mcfserial.o obj-$(CONFIG_V850E_UART) += v850e_uart.o obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o +obj-$(CONFIG_SERIAL_LH7A40X) += serial_lh7a40x.o obj-$(CONFIG_SERIAL_AU1X00) += au1x00_uart.o obj-$(CONFIG_SERIAL_DZ) += dz.o obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o diff --git a/drivers/serial/serial_lh7a40x.c b/drivers/serial/serial_lh7a40x.c new file mode 100644 index 000000000000..d863368e45e2 --- /dev/null +++ b/drivers/serial/serial_lh7a40x.c @@ -0,0 +1,708 @@ +/* drivers/serial/serial_lh7a40x.c + * + * Copyright (C) 2004 Coastal Environmental Systems + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + */ + +/* Driver for Sharp LH7A40X embedded serial ports + * + * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. + * Based on drivers/serial/amba.c, by Deep Blue Solutions Ltd. + * + * --- + * + * This driver supports the embedded UARTs of the Sharp LH7A40X series + * CPUs. While similar to the 16550 and other UART chips, there is + * nothing close to register compatibility. Moreover, some of the + * modem control lines are not available, either in the chip or they + * are lacking in the board-level implementation. + * + * - Use of SIRDIS + * For simplicity, we disable the IR functions of any UART whenever + * we enable it. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#if defined(CONFIG_SERIAL_LH7A40X_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include + +#include + +#define DEV_MAJOR 204 +#define DEV_MINOR 16 +#define DEV_NR 3 + +#define ISR_LOOP_LIMIT 256 + +#define UR(p,o) _UR ((p)->membase, o) +#define _UR(b,o) (*((volatile unsigned int*)(((unsigned char*) b) + (o)))) +#define BIT_CLR(p,o,m) UR(p,o) = UR(p,o) & (~(unsigned int)m) +#define BIT_SET(p,o,m) UR(p,o) = UR(p,o) | ( (unsigned int)m) + +#define UART_REG_SIZE 32 + +#define UARTEN (0x01) /* UART enable */ +#define SIRDIS (0x02) /* Serial IR disable (UART1 only) */ + +#define RxEmpty (0x10) +#define TxEmpty (0x80) +#define TxFull (0x20) +#define nRxRdy RxEmpty +#define nTxRdy TxFull +#define TxBusy (0x08) + +#define RxBreak (0x0800) +#define RxOverrunError (0x0400) +#define RxParityError (0x0200) +#define RxFramingError (0x0100) +#define RxError (RxBreak | RxOverrunError | RxParityError | RxFramingError) + +#define DCD (0x04) +#define DSR (0x02) +#define CTS (0x01) + +#define RxInt (0x01) +#define TxInt (0x02) +#define ModemInt (0x04) +#define RxTimeoutInt (0x08) + +#define MSEOI (0x10) + +#define WLEN_8 (0x60) +#define WLEN_7 (0x40) +#define WLEN_6 (0x20) +#define WLEN_5 (0x00) +#define WLEN (0x60) /* Mask for all word-length bits */ +#define STP2 (0x08) +#define PEN (0x02) /* Parity Enable */ +#define EPS (0x04) /* Even Parity Set */ +#define FEN (0x10) /* FIFO Enable */ +#define BRK (0x01) /* Send Break */ + + +struct uart_port_lh7a40x { + struct uart_port port; + unsigned int statusPrev; /* Most recently read modem status */ +}; + +static void lh7a40xuart_stop_tx (struct uart_port* port, unsigned int tty_stop) +{ + BIT_CLR (port, UART_R_INTEN, TxInt); +} + +static void lh7a40xuart_start_tx (struct uart_port* port, + unsigned int tty_start) +{ + BIT_SET (port, UART_R_INTEN, TxInt); + + /* *** FIXME: do I need to check for startup of the + transmitter? The old driver did, but AMBA + doesn't . */ +} + +static void lh7a40xuart_stop_rx (struct uart_port* port) +{ + BIT_SET (port, UART_R_INTEN, RxTimeoutInt | RxInt); +} + +static void lh7a40xuart_enable_ms (struct uart_port* port) +{ + BIT_SET (port, UART_R_INTEN, ModemInt); +} + +static void +#ifdef SUPPORT_SYSRQ +lh7a40xuart_rx_chars (struct uart_port* port, struct pt_regs* regs) +#else +lh7a40xuart_rx_chars (struct uart_port* port) +#endif +{ + struct tty_struct* tty = port->info->tty; + int cbRxMax = 256; /* (Gross) limit on receive */ + unsigned int data; /* Received data and status */ + + while (!(UR (port, UART_R_STATUS) & nRxRdy) && --cbRxMax) { + if (tty->flip.count >= TTY_FLIPBUF_SIZE) { + tty->flip.work.func((void*)tty); + if (tty->flip.count >= TTY_FLIPBUF_SIZE) { + printk(KERN_WARNING "TTY_DONT_FLIP set\n"); + return; + } + } + + data = UR (port, UART_R_DATA); + + *tty->flip.char_buf_ptr = (unsigned char) data; + *tty->flip.flag_buf_ptr = TTY_NORMAL; + ++port->icount.rx; + + if (data & RxError) { /* Quick check, short-circuit */ + if (data & RxBreak) { + data &= ~(RxFramingError | RxParityError); + ++port->icount.brk; + if (uart_handle_break (port)) + continue; + } + else if (data & RxParityError) + ++port->icount.parity; + else if (data & RxFramingError) + ++port->icount.frame; + if (data & RxOverrunError) + ++port->icount.overrun; + + /* Mask by termios, leave Rx'd byte */ + data &= port->read_status_mask | 0xff; + + if (data & RxBreak) + *tty->flip.flag_buf_ptr = TTY_BREAK; + else if (data & RxParityError) + *tty->flip.flag_buf_ptr = TTY_PARITY; + else if (data & RxFramingError) + *tty->flip.flag_buf_ptr = TTY_FRAME; + } + + if (uart_handle_sysrq_char (port, (unsigned char) data, regs)) + continue; + + if ((data & port->ignore_status_mask) == 0) { + ++tty->flip.flag_buf_ptr; + ++tty->flip.char_buf_ptr; + ++tty->flip.count; + } + if ((data & RxOverrunError) + && tty->flip.count < TTY_FLIPBUF_SIZE) { + /* + * Overrun is special, since it's reported + * immediately, and doesn't affect the current + * character + */ + *tty->flip.char_buf_ptr++ = 0; + *tty->flip.flag_buf_ptr++ = TTY_OVERRUN; + ++tty->flip.count; + } + } + tty_flip_buffer_push (tty); + return; +} + +static void lh7a40xuart_tx_chars (struct uart_port* port) +{ + struct circ_buf* xmit = &port->info->xmit; + int cbTxMax = port->fifosize; + + if (port->x_char) { + UR (port, UART_R_DATA) = port->x_char; + ++port->icount.tx; + port->x_char = 0; + return; + } + if (uart_circ_empty (xmit) || uart_tx_stopped (port)) { + lh7a40xuart_stop_tx (port, 0); + return; + } + + /* Unlike the AMBA UART, the lh7a40x UART does not guarantee + that at least half of the FIFO is empty. Instead, we check + status for every character. Using the AMBA method causes + the transmitter to drop characters. */ + + do { + UR (port, UART_R_DATA) = xmit->buf[xmit->tail]; + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + ++port->icount.tx; + if (uart_circ_empty(xmit)) + break; + } while (!(UR (port, UART_R_STATUS) & nTxRdy) + && cbTxMax--); + + if (uart_circ_chars_pending (xmit) < WAKEUP_CHARS) + uart_write_wakeup (port); + + if (uart_circ_empty (xmit)) + lh7a40xuart_stop_tx (port, 0); +} + +static void lh7a40xuart_modem_status (struct uart_port* port) +{ + unsigned int status = UR (port, UART_R_STATUS); + unsigned int delta + = status ^ ((struct uart_port_lh7a40x*) port)->statusPrev; + + BIT_SET (port, UART_R_RAWISR, MSEOI); /* Clear modem status intr */ + + if (!delta) /* Only happens if we missed 2 transitions */ + return; + + ((struct uart_port_lh7a40x*) port)->statusPrev = status; + + if (delta & DCD) + uart_handle_dcd_change (port, status & DCD); + + if (delta & DSR) + ++port->icount.dsr; + + if (delta & CTS) + uart_handle_cts_change (port, status & CTS); + + wake_up_interruptible (&port->info->delta_msr_wait); +} + +static irqreturn_t lh7a40xuart_int (int irq, void* dev_id, + struct pt_regs* regs) +{ + struct uart_port* port = dev_id; + unsigned int cLoopLimit = ISR_LOOP_LIMIT; + unsigned int isr = UR (port, UART_R_ISR); + + + do { + if (isr & (RxInt | RxTimeoutInt)) +#ifdef SUPPORT_SYSRQ + lh7a40xuart_rx_chars(port, regs); +#else + lh7a40xuart_rx_chars(port); +#endif + if (isr & ModemInt) + lh7a40xuart_modem_status (port); + if (isr & TxInt) + lh7a40xuart_tx_chars (port); + + if (--cLoopLimit == 0) + break; + + isr = UR (port, UART_R_ISR); + } while (isr & (RxInt | TxInt | RxTimeoutInt)); + + return IRQ_HANDLED; +} + +static unsigned int lh7a40xuart_tx_empty (struct uart_port* port) +{ + return (UR (port, UART_R_STATUS) & TxEmpty) ? TIOCSER_TEMT : 0; +} + +static unsigned int lh7a40xuart_get_mctrl (struct uart_port* port) +{ + unsigned int result = 0; + unsigned int status = UR (port, UART_R_STATUS); + + if (status & DCD) + result |= TIOCM_CAR; + if (status & DSR) + result |= TIOCM_DSR; + if (status & CTS) + result |= TIOCM_CTS; + + return result; +} + +static void lh7a40xuart_set_mctrl (struct uart_port* port, unsigned int mctrl) +{ + /* None of the ports supports DTR. UART1 supports RTS through GPIO. */ + /* Note, kernel appears to be setting DTR and RTS on console. */ + + /* *** FIXME: this deserves more work. There's some work in + tracing all of the IO pins. */ +#if 0 + if( port->mapbase == UART1_PHYS) { + gpioRegs_t *gpio = (gpioRegs_t *)IO_ADDRESS(GPIO_PHYS); + + if (mctrl & TIOCM_RTS) + gpio->pbdr &= ~GPIOB_UART1_RTS; + else + gpio->pbdr |= GPIOB_UART1_RTS; + } +#endif +} + +static void lh7a40xuart_break_ctl (struct uart_port* port, int break_state) +{ + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + if (break_state == -1) + BIT_SET (port, UART_R_FCON, BRK); /* Assert break */ + else + BIT_CLR (port, UART_R_FCON, BRK); /* Deassert break */ + spin_unlock_irqrestore(&port->lock, flags); +} + +static int lh7a40xuart_startup (struct uart_port* port) +{ + int retval; + + retval = request_irq (port->irq, lh7a40xuart_int, 0, + "serial_lh7a40x", port); + if (retval) + return retval; + + /* Initial modem control-line settings */ + ((struct uart_port_lh7a40x*) port)->statusPrev + = UR (port, UART_R_STATUS); + + /* There is presently no configuration option to enable IR. + Thus, we always disable it. */ + + BIT_SET (port, UART_R_CON, UARTEN | SIRDIS); + BIT_SET (port, UART_R_INTEN, RxTimeoutInt | RxInt); + + return 0; +} + +static void lh7a40xuart_shutdown (struct uart_port* port) +{ + free_irq (port->irq, port); + BIT_CLR (port, UART_R_FCON, BRK | FEN); + BIT_CLR (port, UART_R_CON, UARTEN); +} + +static void lh7a40xuart_set_termios (struct uart_port* port, + struct termios* termios, + struct termios* old) +{ + unsigned int con; + unsigned int inten; + unsigned int fcon; + unsigned long flags; + unsigned int baud; + unsigned int quot; + + baud = uart_get_baud_rate (port, termios, old, 8, port->uartclk/16); + quot = uart_get_divisor (port, baud); /* -1 performed elsewhere */ + + switch (termios->c_cflag & CSIZE) { + case CS5: + fcon = WLEN_5; + break; + case CS6: + fcon = WLEN_6; + break; + case CS7: + fcon = WLEN_7; + break; + case CS8: + default: + fcon = WLEN_8; + break; + } + if (termios->c_cflag & CSTOPB) + fcon |= STP2; + if (termios->c_cflag & PARENB) { + fcon |= PEN; + if (!(termios->c_cflag & PARODD)) + fcon |= EPS; + } + if (port->fifosize > 1) + fcon |= FEN; + + spin_lock_irqsave (&port->lock, flags); + + uart_update_timeout (port, termios->c_cflag, baud); + + port->read_status_mask = RxOverrunError; + if (termios->c_iflag & INPCK) + port->read_status_mask |= RxFramingError | RxParityError; + if (termios->c_iflag & (BRKINT | PARMRK)) + port->read_status_mask |= RxBreak; + + /* Figure mask for status we ignore */ + port->ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= RxFramingError | RxParityError; + if (termios->c_iflag & IGNBRK) { + port->ignore_status_mask |= RxBreak; + /* Ignore overrun when ignorning parity */ + /* *** FIXME: is this in the right place? */ + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= RxOverrunError; + } + + /* Ignore all receive errors when receive disabled */ + if ((termios->c_cflag & CREAD) == 0) + port->ignore_status_mask |= RxError; + + con = UR (port, UART_R_CON); + inten = (UR (port, UART_R_INTEN) & ~ModemInt); + + if (UART_ENABLE_MS (port, termios->c_cflag)) + inten |= ModemInt; + + BIT_CLR (port, UART_R_CON, UARTEN); /* Disable UART */ + UR (port, UART_R_INTEN) = 0; /* Disable interrupts */ + UR (port, UART_R_BRCON) = quot - 1; /* Set baud rate divisor */ + UR (port, UART_R_FCON) = fcon; /* Set FIFO and frame ctrl */ + UR (port, UART_R_INTEN) = inten; /* Enable interrupts */ + UR (port, UART_R_CON) = con; /* Restore UART mode */ + + spin_unlock_irqrestore(&port->lock, flags); +} + +static const char* lh7a40xuart_type (struct uart_port* port) +{ + return port->type == PORT_LH7A40X ? "LH7A40X" : NULL; +} + +static void lh7a40xuart_release_port (struct uart_port* port) +{ + release_mem_region (port->mapbase, UART_REG_SIZE); +} + +static int lh7a40xuart_request_port (struct uart_port* port) +{ + return request_mem_region (port->mapbase, UART_REG_SIZE, + "serial_lh7a40x") != NULL + ? 0 : -EBUSY; +} + +static void lh7a40xuart_config_port (struct uart_port* port, int flags) +{ + if (flags & UART_CONFIG_TYPE) { + port->type = PORT_LH7A40X; + lh7a40xuart_request_port (port); + } +} + +static int lh7a40xuart_verify_port (struct uart_port* port, + struct serial_struct* ser) +{ + int ret = 0; + + if (ser->type != PORT_UNKNOWN && ser->type != PORT_LH7A40X) + ret = -EINVAL; + if (ser->irq < 0 || ser->irq >= NR_IRQS) + ret = -EINVAL; + if (ser->baud_base < 9600) /* *** FIXME: is this true? */ + ret = -EINVAL; + return ret; +} + +static struct uart_ops lh7a40x_uart_ops = { + .tx_empty = lh7a40xuart_tx_empty, + .set_mctrl = lh7a40xuart_set_mctrl, + .get_mctrl = lh7a40xuart_get_mctrl, + .stop_tx = lh7a40xuart_stop_tx, + .start_tx = lh7a40xuart_start_tx, + .stop_rx = lh7a40xuart_stop_rx, + .enable_ms = lh7a40xuart_enable_ms, + .break_ctl = lh7a40xuart_break_ctl, + .startup = lh7a40xuart_startup, + .shutdown = lh7a40xuart_shutdown, + .set_termios = lh7a40xuart_set_termios, + .type = lh7a40xuart_type, + .release_port = lh7a40xuart_release_port, + .request_port = lh7a40xuart_request_port, + .config_port = lh7a40xuart_config_port, + .verify_port = lh7a40xuart_verify_port, +}; + +static struct uart_port_lh7a40x lh7a40x_ports[DEV_NR] = { + { + .port = { + .membase = (void*) io_p2v (UART1_PHYS), + .mapbase = UART1_PHYS, + .iotype = SERIAL_IO_MEM, + .irq = IRQ_UART1INTR, + .uartclk = 14745600/2, + .fifosize = 16, + .ops = &lh7a40x_uart_ops, + .flags = ASYNC_BOOT_AUTOCONF, + .line = 0, + }, + }, + { + .port = { + .membase = (void*) io_p2v (UART2_PHYS), + .mapbase = UART2_PHYS, + .iotype = SERIAL_IO_MEM, + .irq = IRQ_UART2INTR, + .uartclk = 14745600/2, + .fifosize = 16, + .ops = &lh7a40x_uart_ops, + .flags = ASYNC_BOOT_AUTOCONF, + .line = 1, + }, + }, + { + .port = { + .membase = (void*) io_p2v (UART3_PHYS), + .mapbase = UART3_PHYS, + .iotype = SERIAL_IO_MEM, + .irq = IRQ_UART3INTR, + .uartclk = 14745600/2, + .fifosize = 16, + .ops = &lh7a40x_uart_ops, + .flags = ASYNC_BOOT_AUTOCONF, + .line = 2, + }, + }, +}; + +#ifndef CONFIG_SERIAL_LH7A40X_CONSOLE +# define LH7A40X_CONSOLE NULL +#else +# define LH7A40X_CONSOLE &lh7a40x_console + + +static void lh7a40xuart_console_write (struct console* co, + const char* s, + unsigned int count) +{ + struct uart_port* port = &lh7a40x_ports[co->index].port; + unsigned int con = UR (port, UART_R_CON); + unsigned int inten = UR (port, UART_R_INTEN); + + + UR (port, UART_R_INTEN) = 0; /* Disable all interrupts */ + BIT_SET (port, UART_R_CON, UARTEN | SIRDIS); /* Enable UART */ + + for (; count-- > 0; ++s) { + while (UR (port, UART_R_STATUS) & nTxRdy) + ; + UR (port, UART_R_DATA) = *s; + if (*s == '\n') { + while ((UR (port, UART_R_STATUS) & TxBusy)) + ; + UR (port, UART_R_DATA) = '\r'; + } + } + + /* Wait until all characters are sent */ + while (UR (port, UART_R_STATUS) & TxBusy) + ; + + /* Restore control and interrupt mask */ + UR (port, UART_R_CON) = con; + UR (port, UART_R_INTEN) = inten; +} + +static void __init lh7a40xuart_console_get_options (struct uart_port* port, + int* baud, + int* parity, + int* bits) +{ + if (UR (port, UART_R_CON) & UARTEN) { + unsigned int fcon = UR (port, UART_R_FCON); + unsigned int quot = UR (port, UART_R_BRCON) + 1; + + switch (fcon & (PEN | EPS)) { + default: *parity = 'n'; break; + case PEN: *parity = 'o'; break; + case PEN | EPS: *parity = 'e'; break; + } + + switch (fcon & WLEN) { + default: + case WLEN_8: *bits = 8; break; + case WLEN_7: *bits = 7; break; + case WLEN_6: *bits = 6; break; + case WLEN_5: *bits = 5; break; + } + + *baud = port->uartclk/(16*quot); + } +} + +static int __init lh7a40xuart_console_setup (struct console* co, char* options) +{ + struct uart_port* port; + int baud = 38400; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + if (co->index >= DEV_NR) /* Bounds check on device number */ + co->index = 0; + port = &lh7a40x_ports[co->index].port; + + if (options) + uart_parse_options (options, &baud, &parity, &bits, &flow); + else + lh7a40xuart_console_get_options (port, &baud, &parity, &bits); + + return uart_set_options (port, co, baud, parity, bits, flow); +} + +extern struct uart_driver lh7a40x_reg; +static struct console lh7a40x_console = { + .name = "ttyAM", + .write = lh7a40xuart_console_write, + .device = uart_console_device, + .setup = lh7a40xuart_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &lh7a40x_reg, +}; + +static int __init lh7a40xuart_console_init(void) +{ + register_console (&lh7a40x_console); + return 0; +} + +console_initcall (lh7a40xuart_console_init); + +#endif + +static struct uart_driver lh7a40x_reg = { + .owner = THIS_MODULE, + .driver_name = "ttyAM", + .dev_name = "ttyAM", + .major = DEV_MAJOR, + .minor = DEV_MINOR, + .nr = DEV_NR, + .cons = LH7A40X_CONSOLE, +}; + +static int __init lh7a40xuart_init(void) +{ + int ret; + + printk (KERN_INFO "serial: LH7A40X serial driver\n"); + + ret = uart_register_driver (&lh7a40x_reg); + + if (ret == 0) { + int i; + + for (i = 0; i < DEV_NR; i++) + uart_add_one_port (&lh7a40x_reg, + &lh7a40x_ports[i].port); + } + return ret; +} + +static void __exit lh7a40xuart_exit(void) +{ + int i; + + for (i = 0; i < DEV_NR; i++) + uart_remove_one_port (&lh7a40x_reg, &lh7a40x_ports[i].port); + + uart_unregister_driver (&lh7a40x_reg); +} + +module_init (lh7a40xuart_init); +module_exit (lh7a40xuart_exit); + +MODULE_AUTHOR ("Marc Singer"); +MODULE_DESCRIPTION ("Sharp LH7A40X serial port driver"); +MODULE_LICENSE ("GPL"); diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index f79c67d6f281..c653647073f1 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -80,6 +80,9 @@ /* SGI IP22 aka Indy / Challenge S / Indigo 2 */ #define PORT_IP22ZILOG 56 +/* Sharp LH7a40x -- an ARM9 SoC series */ +#define PORT_LH7A40X 57 + #ifdef __KERNEL__ #include -- cgit v1.2.3 From 48c1a5733d9a55cca607a762c65c88096b329bbc Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Tue, 22 Jun 2004 12:42:16 -0400 Subject: [libata sata_sil] Re-fix mod15write bug Certain early SATA drives have problems with write requests whose length satisfy the equation "sectors % 15 == 1", on the SiI 3112. Other drives, and other SiI controllers, are not affected. The fix for this problem is to avoid such requests, in one of three ways, for the affect drive+controller combos: 1) Limit all writes to 15 sectors 2) Use block layer features to avoid creating requests whose length satisfies the above equation. 3) When a request satisfies the above equation, split the request into two writes, neither of which satisfies the equation. I chose fix #1, the most simple to implement. After discussion with Silicon Image and others regarding the impact of this fix, I have decided to remain with fix #1, and will not be implementing a "better fix". This means that the affected SATA drives will see decreased performance, but set of affected drives is small and will never grow larger. Further, the complexity of implementing solution #2 or solution #3 is rather large. When implementing lba48 'large request' support, I unintentionally broke the fix for these affected drives. Kudos to Ricky Beam for noticing this. This change restores the fix, by adding a flag ATA_DFLAG_LOCK_SECTORS to indicate that the max_sectors value set by the low-level driver should never be changed. --- drivers/scsi/libata-scsi.c | 3 ++- drivers/scsi/sata_sil.c | 1 + include/linux/libata.h | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index fed311e81c50..1c24c0eefe0e 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -182,7 +182,8 @@ int ata_scsi_slave_config(struct scsi_device *sdev) * 65534 when Jens Axboe's patch for dynamically * determining max_sectors is merged. */ - if (dev->flags & ATA_DFLAG_LBA48) { + if ((dev->flags & ATA_DFLAG_LBA48) && + ((dev->flags & ATA_DFLAG_LOCK_SECTORS) == 0)) { sdev->host->max_sectors = 2048; blk_queue_max_sectors(sdev->request_queue, 2048); } diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c index 49ce4d02c1fd..12043e8f84cb 100644 --- a/drivers/scsi/sata_sil.c +++ b/drivers/scsi/sata_sil.c @@ -302,6 +302,7 @@ static void sil_dev_config(struct ata_port *ap, struct ata_device *dev) ap->id, dev->devno); ap->host->max_sectors = 15; ap->host->hostt->max_sectors = 15; + dev->flags |= ATA_DFLAG_LOCK_SECTORS; return; } diff --git a/include/linux/libata.h b/include/linux/libata.h index 787f3583729a..a40286d08e23 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -91,6 +91,7 @@ enum { ATA_DFLAG_MASTER = (1 << 2), /* is device 0? */ ATA_DFLAG_WCACHE = (1 << 3), /* has write cache we can * (hopefully) flush? */ + ATA_DFLAG_LOCK_SECTORS = (1 << 4), /* don't adjust max_sectors */ ATA_DEV_UNKNOWN = 0, /* unknown device */ ATA_DEV_ATA = 1, /* ATA device */ -- cgit v1.2.3