From 1a7500029c3fd7a559352b61ece4ee5c5c5527f2 Mon Sep 17 00:00:00 2001 From: Jon Grimm Date: Thu, 3 Jul 2003 11:17:11 -0500 Subject: [SCTP] Move rwnd accounting and I/O redrive off of the skb destructor. When the skb was shared with Ethereal, Ethereal was sometimes the last user and the destructor would get called on another CPU, not knowing anything about our sock_lock. Move our rwnd updates and I/O redrive out of the skb destructor. Also, if unable to allocate an skb for our transmission packet, walk the packet's chunks and free the control chunks. Also change list_dels to list_del_init. Fix real later, but this prevent us from a doing damage if we list_del twice. --- include/net/sctp/ulpevent.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/net/sctp/ulpevent.h b/include/net/sctp/ulpevent.h index d3ad0c86583d..5506352e3808 100644 --- a/include/net/sctp/ulpevent.h +++ b/include/net/sctp/ulpevent.h @@ -74,7 +74,9 @@ static inline struct sctp_ulpevent *sctp_skb2event(struct sk_buff *skb) struct sctp_ulpevent *sctp_ulpevent_new(int size, int flags, int gfp); struct sctp_ulpevent *sctp_ulpevent_init(struct sctp_ulpevent *, int flags); void sctp_ulpevent_free(struct sctp_ulpevent *); +void sctp_ulpevent_kfree_skb(struct sk_buff *skb); int sctp_ulpevent_is_notification(const struct sctp_ulpevent *); +void sctp_queue_purge_ulpevents(struct sk_buff_head *list); struct sctp_ulpevent *sctp_ulpevent_make_assoc_change( const struct sctp_association *asoc, -- cgit v1.2.3 From cadc0ef01d446e4747226d438ce59aa48b972cd3 Mon Sep 17 00:00:00 2001 From: Sridhar Samudrala Date: Thu, 10 Jul 2003 20:50:25 -0700 Subject: [SCTP] Fix for panic on recvmsg() with MSG_PEEK flag and some ulpevent cleanup. --- include/net/sctp/ulpevent.h | 4 +- net/sctp/socket.c | 16 +++- net/sctp/ulpevent.c | 205 +++++++++++++++++++------------------------- net/sctp/ulpqueue.c | 10 +-- 4 files changed, 110 insertions(+), 125 deletions(-) (limited to 'include') diff --git a/include/net/sctp/ulpevent.h b/include/net/sctp/ulpevent.h index 5506352e3808..6e43599919ee 100644 --- a/include/net/sctp/ulpevent.h +++ b/include/net/sctp/ulpevent.h @@ -40,6 +40,7 @@ * Jon Grimm * La Monte H.P. Yarroll * Karl Knutson + * Sridhar Samudrala * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. @@ -72,9 +73,8 @@ static inline struct sctp_ulpevent *sctp_skb2event(struct sk_buff *skb) } struct sctp_ulpevent *sctp_ulpevent_new(int size, int flags, int gfp); -struct sctp_ulpevent *sctp_ulpevent_init(struct sctp_ulpevent *, int flags); +void sctp_ulpevent_init(struct sctp_ulpevent *, int flags); void sctp_ulpevent_free(struct sctp_ulpevent *); -void sctp_ulpevent_kfree_skb(struct sk_buff *skb); int sctp_ulpevent_is_notification(const struct sctp_ulpevent *); void sctp_queue_purge_ulpevents(struct sk_buff_head *list); diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 5aea07f1d521..3d47c69a3f46 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -1342,8 +1342,7 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, /* When only partial message is copied to the user, increase * rwnd by that amount. If all the data in the skb is read, - * rwnd is updated when the skb's destructor is called via - * sctp_ulpevent_free(). + * rwnd is updated when the event is freed. */ sctp_assoc_rwnd_increase(event->asoc, copied); goto out; @@ -1354,7 +1353,18 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, msg->msg_flags &= ~MSG_EOR; out_free: - sctp_ulpevent_kfree_skb(skb); /* Free the skb. */ + if (flags & MSG_PEEK) { + /* Release the skb reference acquired after peeking the skb in + * sctp_skb_recv_datagram(). + */ + kfree_skb(skb); + } else { + /* Free the event which includes releasing the reference to + * the owner of the skb, freeing the skb and updating the + * rwnd. + */ + sctp_ulpevent_free(event); + } out: sctp_release_sock(sk); return err; diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c index e55e17500aeb..5071373e8e91 100644 --- a/net/sctp/ulpevent.c +++ b/net/sctp/ulpevent.c @@ -35,6 +35,7 @@ * Written or modified by: * Jon Grimm * La Monte H.P. Yarroll + * Sridhar Samudrala * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. @@ -46,10 +47,12 @@ #include #include -static void sctp_ulpevent_set_owner_r(struct sk_buff *skb, - struct sctp_association *asoc); -static void sctp_ulpevent_set_owner(struct sk_buff *skb, - const struct sctp_association *asoc); +static inline void sctp_ulpevent_set_owner(struct sctp_ulpevent *event, + const struct sctp_association *asoc); +static inline void sctp_ulpevent_release_owner(struct sctp_ulpevent *event); +static void sctp_ulpevent_receive_data(struct sctp_ulpevent *event, + struct sctp_association *asoc); +static void sctp_ulpevent_release_data(struct sctp_ulpevent *event); /* Create a new sctp_ulpevent. */ struct sctp_ulpevent *sctp_ulpevent_new(int size, int msg_flags, int gfp) @@ -62,31 +65,19 @@ struct sctp_ulpevent *sctp_ulpevent_new(int size, int msg_flags, int gfp) goto fail; event = sctp_skb2event(skb); - event = sctp_ulpevent_init(event, msg_flags); - if (!event) - goto fail_init; + sctp_ulpevent_init(event, msg_flags); + return event; -fail_init: - kfree_skb(skb); fail: return NULL; } /* Initialize an ULP event from an given skb. */ -struct sctp_ulpevent *sctp_ulpevent_init(struct sctp_ulpevent *event, - int msg_flags) +void sctp_ulpevent_init(struct sctp_ulpevent *event, int msg_flags) { memset(event, sizeof(struct sctp_ulpevent), 0x00); event->msg_flags = msg_flags; - return event; -} - - -/* Dispose of an event. */ -void sctp_ulpevent_free(struct sctp_ulpevent *event) -{ - kfree_skb(sctp_event2skb(event)); } /* Is this a MSG_NOTIFICATION? */ @@ -190,7 +181,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_assoc_change( * All notifications for a given association have the same association * identifier. For TCP style socket, this field is ignored. */ - sctp_ulpevent_set_owner(skb, asoc); + sctp_ulpevent_set_owner(event, asoc); sac->sac_assoc_id = sctp_assoc2id(asoc); return event; @@ -282,7 +273,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change( * All notifications for a given association have the same association * identifier. For TCP style socket, this field is ignored. */ - sctp_ulpevent_set_owner(skb, asoc); + sctp_ulpevent_set_owner(event, asoc); spc->spc_assoc_id = sctp_assoc2id(asoc); /* Sockets API Extensions for SCTP @@ -347,10 +338,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_remote_error( /* Embed the event fields inside the cloned skb. */ event = sctp_skb2event(skb); - event = sctp_ulpevent_init(event, MSG_NOTIFICATION); - - if (!event) - goto fail; + sctp_ulpevent_init(event, MSG_NOTIFICATION); sre = (struct sctp_remote_error *) skb_push(skb, sizeof(struct sctp_remote_error)); @@ -403,8 +391,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_remote_error( * All notifications for a given association have the same association * identifier. For TCP style socket, this field is ignored. */ - skb = sctp_event2skb(event); - sctp_ulpevent_set_owner(skb, asoc); + sctp_ulpevent_set_owner(event, asoc); sre->sre_assoc_id = sctp_assoc2id(asoc); return event; @@ -443,9 +430,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_send_failed( /* Embed the event fields inside the cloned skb. */ event = sctp_skb2event(skb); - event = sctp_ulpevent_init(event, MSG_NOTIFICATION); - if (!event) - goto fail; + sctp_ulpevent_init(event, MSG_NOTIFICATION); ssf = (struct sctp_send_failed *) skb_push(skb, sizeof(struct sctp_send_failed)); @@ -516,8 +501,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_send_failed( * same association identifier. For TCP style socket, this field is * ignored. */ - skb = sctp_event2skb(event); - sctp_ulpevent_set_owner(skb, asoc); + sctp_ulpevent_set_owner(event, asoc); ssf->ssf_assoc_id = sctp_assoc2id(asoc); return event; @@ -580,7 +564,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_shutdown_event( * All notifications for a given association have the same association * identifier. For TCP style socket, this field is ignored. */ - sctp_ulpevent_set_owner(skb, asoc); + sctp_ulpevent_set_owner(event, asoc); sse->sse_assoc_id = sctp_assoc2id(asoc); return event; @@ -602,7 +586,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc, { struct sctp_ulpevent *event; struct sctp_sndrcvinfo *info; - struct sk_buff *skb, *list; + struct sk_buff *skb; size_t padding, len; /* Clone the original skb, sharing the data. */ @@ -628,24 +612,15 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc, /* Fixup cloned skb with just this chunks data. */ skb_trim(skb, chunk->chunk_end - padding - skb->data); - /* Set up a destructor to do rwnd accounting. */ - sctp_ulpevent_set_owner_r(skb, asoc); - /* Embed the event fields inside the cloned skb. */ event = sctp_skb2event(skb); /* Initialize event with flags 0. */ - event = sctp_ulpevent_init(event, 0); - if (!event) - goto fail_init; + sctp_ulpevent_init(event, 0); event->iif = sctp_chunk_iif(chunk); - /* Note: Not clearing the entire event struct as - * this is just a fragment of the real event. However, - * we still need to do rwnd accounting. - */ - for (list = skb_shinfo(skb)->frag_list; list; list = list->next) - sctp_ulpevent_set_owner_r(list, asoc); + + sctp_ulpevent_receive_data(event, asoc); info = (struct sctp_sndrcvinfo *) &event->sndrcvinfo; @@ -736,9 +711,6 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc, return event; -fail_init: - kfree_skb(skb); - fail: return NULL; } @@ -794,7 +766,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_pdapi( * * The association id field, holds the identifier for the association. */ - sctp_ulpevent_set_owner(skb, asoc); + sctp_ulpevent_set_owner(event, asoc); pd->pdapi_assoc_id = sctp_assoc2id(asoc); return event; @@ -839,92 +811,95 @@ static void sctp_stub_rfree(struct sk_buff *skb) */ } -/* Do accounting for bytes just read by user. */ -static void sctp_rcvmsg_rfree(struct sk_buff *skb) -{ - struct sctp_association *asoc; - struct sctp_ulpevent *event; - struct sk_buff *frag; - - /* Current stack structures assume that the rcv buffer is - * per socket. For UDP style sockets this is not true as - * multiple associations may be on a single UDP-style socket. - * Use the local private area of the skb to track the owning - * association. - */ - - event = sctp_skb2event(skb); - asoc = event->asoc; - sctp_assoc_rwnd_increase(asoc, skb_headlen(skb)); - - /* Don't forget the fragments. */ - for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next) { - /* NOTE: skb_shinfos are recursive. */ - sctp_rcvmsg_rfree(frag); - } - sctp_association_put(asoc); -} - -/* Charge receive window for bytes received. */ -static void sctp_ulpevent_set_owner_r(struct sk_buff *skb, - struct sctp_association *asoc) +/* Hold the association in case the msg_name needs read out of + * the association. + */ +static inline void sctp_ulpevent_set_owner(struct sctp_ulpevent *event, + const struct sctp_association *asoc) { - struct sctp_ulpevent *event; + struct sk_buff *skb; - /* The current stack structures assume that the rcv buffer is - * per socket. For UDP-style sockets this is not true as - * multiple associations may be on a single UDP-style socket. - * We use the local private area of the skb to track the owning - * association. + /* Cast away the const, as we are just wanting to + * bump the reference count. */ - sctp_association_hold(asoc); + sctp_association_hold((struct sctp_association *)asoc); + skb = sctp_event2skb(event); skb->sk = asoc->base.sk; - event = sctp_skb2event(skb); - event->asoc = asoc; - + event->asoc = (struct sctp_association *)asoc; skb->destructor = sctp_stub_rfree; - sctp_assoc_rwnd_decrease(asoc, skb_headlen(skb)); } /* A simple destructor to give up the reference to the association. */ -static void sctp_ulpevent_rfree(struct sk_buff *skb) +static inline void sctp_ulpevent_release_owner(struct sctp_ulpevent *event) { - struct sctp_ulpevent *event; - event = sctp_skb2event(skb); sctp_association_put(event->asoc); } -/* Hold the association in case the msg_name needs read out of - * the association. +/* Do accounting for bytes received and hold a reference to the association + * for each skb. */ -static void sctp_ulpevent_set_owner(struct sk_buff *skb, - const struct sctp_association *asoc) +static void sctp_ulpevent_receive_data(struct sctp_ulpevent *event, + struct sctp_association *asoc) { - struct sctp_ulpevent *event; + struct sk_buff *skb, *frag; - /* Cast away the const, as we are just wanting to - * bump the reference count. + skb = sctp_event2skb(event); + /* Set the owner and charge rwnd for bytes received. */ + sctp_ulpevent_set_owner(event, asoc); + sctp_assoc_rwnd_decrease(asoc, skb_headlen(skb)); + + /* Note: Not clearing the entire event struct as this is just a + * fragment of the real event. However, we still need to do rwnd + * accounting. + * In general, the skb passed from IP can have only 1 level of + * fragments. But we allow multiple levels of fragments. */ - sctp_association_hold((struct sctp_association *)asoc); - skb->sk = asoc->base.sk; - event = sctp_skb2event(skb); - event->asoc = (struct sctp_association *)asoc; - skb->destructor = sctp_stub_rfree; + for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next) { + sctp_ulpevent_receive_data(sctp_skb2event(frag), asoc); + } } -/* Free a ulpevent that has an owner. See comments in - * sctp_stub_rfree(). - */ -void sctp_ulpevent_kfree_skb(struct sk_buff *skb) +/* Do accounting for bytes just read by user and release the references to + * the association. + */ +static void sctp_ulpevent_release_data(struct sctp_ulpevent *event) { - struct sctp_ulpevent *event; + struct sk_buff *skb, *frag; - event = sctp_skb2event(skb); + /* Current stack structures assume that the rcv buffer is + * per socket. For UDP style sockets this is not true as + * multiple associations may be on a single UDP-style socket. + * Use the local private area of the skb to track the owning + * association. + */ + + skb = sctp_event2skb(event); + sctp_assoc_rwnd_increase(event->asoc, skb_headlen(skb)); + + /* Don't forget the fragments. */ + for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next) { + /* NOTE: skb_shinfos are recursive. Although IP returns + * skb's with only 1 level of fragments, SCTP reassembly can + * increase the levels. + */ + sctp_ulpevent_release_data(sctp_skb2event(frag)); + } + sctp_ulpevent_release_owner(event); +} + +/* Free a ulpevent that has an owner. It includes releasing the reference + * to the owner, updating the rwnd in case of a DATA event and freeing the + * skb. + * See comments in sctp_stub_rfree(). + */ +void sctp_ulpevent_free(struct sctp_ulpevent *event) +{ if (sctp_ulpevent_is_notification(event)) - sctp_ulpevent_rfree(skb); + sctp_ulpevent_release_owner(event); else - sctp_rcvmsg_rfree(skb); - kfree_skb(skb); + sctp_ulpevent_release_data(event); + + kfree_skb(sctp_event2skb(event)); } /* Purge the skb lists holding ulpevents. */ @@ -932,5 +907,5 @@ void sctp_queue_purge_ulpevents(struct sk_buff_head *list) { struct sk_buff *skb; while ((skb = skb_dequeue(list)) != NULL) - sctp_ulpevent_kfree_skb(skb); + sctp_ulpevent_free(sctp_skb2event(skb)); } diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c index f32d8de7f41d..a02b2143239b 100644 --- a/net/sctp/ulpqueue.c +++ b/net/sctp/ulpqueue.c @@ -99,12 +99,12 @@ void sctp_ulpq_flush(struct sctp_ulpq *ulpq) while ((skb = __skb_dequeue(&ulpq->lobby))) { event = sctp_skb2event(skb); - sctp_ulpevent_kfree_skb(skb); + sctp_ulpevent_free(event); } while ((skb = __skb_dequeue(&ulpq->reasm))) { event = sctp_skb2event(skb); - sctp_ulpevent_kfree_skb(skb); + sctp_ulpevent_free(event); } } @@ -237,7 +237,7 @@ out_free: if (sctp_event2skb(event)->list) sctp_queue_purge_ulpevents(sctp_event2skb(event)->list); else - sctp_ulpevent_kfree_skb(sctp_event2skb(event)); + sctp_ulpevent_free(event); return 0; } @@ -696,7 +696,7 @@ static __u16 sctp_ulpq_renege_order(struct sctp_ulpq *ulpq, __u16 needed) event = sctp_skb2event(skb); tsn = event->sndrcvinfo.sinfo_tsn; - sctp_ulpevent_kfree_skb(skb); + sctp_ulpevent_free(event); sctp_tsnmap_renege(tsnmap, tsn); if (freed >= needed) return freed; @@ -722,7 +722,7 @@ static __u16 sctp_ulpq_renege_frags(struct sctp_ulpq *ulpq, __u16 needed) event = sctp_skb2event(skb); tsn = event->sndrcvinfo.sinfo_tsn; - sctp_ulpevent_kfree_skb(skb); + sctp_ulpevent_free(event); sctp_tsnmap_renege(tsnmap, tsn); if (freed >= needed) return freed; -- cgit v1.2.3 From 691eb68428db04ad52ffa8a5613977ec76786589 Mon Sep 17 00:00:00 2001 From: Sridhar Samudrala Date: Thu, 10 Jul 2003 22:02:46 -0700 Subject: [SCTP] Send SHUTDOWNs through the same path as the received DATA in SHUTDOWN-SENT state. (Ryan Layer) --- include/net/sctp/sm.h | 3 ++- net/sctp/sm_make_chunk.c | 6 +++++- net/sctp/sm_sideeffect.c | 2 +- net/sctp/sm_statefuns.c | 4 ++-- 4 files changed, 10 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/net/sctp/sm.h b/include/net/sctp/sm.h index e9814d30bd46..a779754deaf6 100644 --- a/include/net/sctp/sm.h +++ b/include/net/sctp/sm.h @@ -231,7 +231,8 @@ struct sctp_chunk *sctp_make_data_empty(struct sctp_association *, struct sctp_chunk *sctp_make_ecne(const struct sctp_association *, const __u32); struct sctp_chunk *sctp_make_sack(const struct sctp_association *); -struct sctp_chunk *sctp_make_shutdown(const struct sctp_association *asoc); +struct sctp_chunk *sctp_make_shutdown(const struct sctp_association *asoc, + const struct sctp_chunk *chunk); struct sctp_chunk *sctp_make_shutdown_ack(const struct sctp_association *asoc, const struct sctp_chunk *); struct sctp_chunk *sctp_make_shutdown_complete(const struct sctp_association *, diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index f31d900ad363..655c895b7ad8 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -667,7 +667,8 @@ nodata: } /* Make a SHUTDOWN chunk. */ -struct sctp_chunk *sctp_make_shutdown(const struct sctp_association *asoc) +struct sctp_chunk *sctp_make_shutdown(const struct sctp_association *asoc, + const struct sctp_chunk *chunk) { struct sctp_chunk *retval; sctp_shutdownhdr_t shut; @@ -683,6 +684,9 @@ struct sctp_chunk *sctp_make_shutdown(const struct sctp_association *asoc) retval->subh.shutdown_hdr = sctp_addto_chunk(retval, sizeof(shut), &shut); + + if (chunk) + retval->transport = chunk->transport; nodata: return retval; } diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index b320c1c5e670..9a99495265f8 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -962,7 +962,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, asoc->overall_error_count = 0; /* Generate a SHUTDOWN chunk. */ - new_obj = sctp_make_shutdown(asoc); + new_obj = sctp_make_shutdown(asoc, chunk); if (!new_obj) goto nomem; sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 0e3f27b90020..7a20e554de4d 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -3862,7 +3862,7 @@ sctp_disposition_t sctp_sf_do_9_2_start_shutdown( * in the Cumulative TSN Ack field the last sequential TSN it * has received from the peer. */ - reply = sctp_make_shutdown(asoc); + reply = sctp_make_shutdown(asoc, NULL); if (!reply) goto nomem; @@ -4179,7 +4179,7 @@ sctp_disposition_t sctp_sf_t2_timer_expire(const struct sctp_endpoint *ep, switch (asoc->state) { case SCTP_STATE_SHUTDOWN_SENT: - reply = sctp_make_shutdown(asoc); + reply = sctp_make_shutdown(asoc, NULL); break; case SCTP_STATE_SHUTDOWN_ACK_SENT: -- cgit v1.2.3 From 33585c7e32919b6e6e16f4d25e19a02ffaf55341 Mon Sep 17 00:00:00 2001 From: Sridhar Samudrala Date: Mon, 14 Jul 2003 09:43:40 -0700 Subject: [SCTP] Update API names to be compatible with draft-ietf-tsvwg-sctpsocket-07.txt. --- include/net/sctp/user.h | 298 ++++++++++++++++++++---------------------------- net/sctp/associola.c | 4 +- net/sctp/socket.c | 112 ++++++++---------- net/sctp/ulpevent.c | 12 +- 4 files changed, 179 insertions(+), 247 deletions(-) (limited to 'include') diff --git a/include/net/sctp/user.h b/include/net/sctp/user.h index 284ef27894ca..e51992a2fe22 100644 --- a/include/net/sctp/user.h +++ b/include/net/sctp/user.h @@ -1,38 +1,38 @@ /* SCTP kernel reference Implementation * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. - * Copyright (c) 2001 International Business Machines, Corp. - * + * Copyright (c) 2001-2003 International Business Machines, Corp. + * * This file is part of the SCTP kernel reference Implementation - * + * * This header represents the structures and constants needed to support - * the SCTP Extension to the Sockets API. - * - * The SCTP reference implementation is free software; - * you can redistribute it and/or modify it under the terms of + * the SCTP Extension to the Sockets API. + * + * The SCTP reference implementation is free software; + * you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. - * - * The SCTP reference implementation is distributed in the hope that it + * + * The SCTP reference implementation is distributed in the hope that it * will be useful, but WITHOUT ANY WARRANTY; without even the implied * ************************ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with GNU CC; see the file COPYING. If not, write to * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * + * Boston, MA 02111-1307, USA. + * * Please send any bug reports or fixes you make to the * email address(es): * lksctp developers - * + * * Or submit a bug report through the following website: * http://www.sf.net/projects/lksctp * - * Written or modified by: + * Written or modified by: * La Monte H.P. Yarroll * R. Stewart * K. Morneau @@ -41,61 +41,61 @@ * Jon Grimm * Daisy Chang * Ryan Layer - * - * + * Sridhar Samudrala + * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. */ -#include -#include #ifndef __net_sctp_user_h__ #define __net_sctp_user_h__ +#include +#include typedef void * sctp_assoc_t; /* The following symbols come from the Sockets API Extensions for - * SCTP . + * SCTP . */ enum sctp_optname { SCTP_RTOINFO, #define SCTP_RTOINFO SCTP_RTOINFO - SCTP_ASSOCRTXINFO, -#define SCTP_ASSOCRTXINFO SCTP_ASSOCRTXINFO + SCTP_ASSOCINFO, +#define SCTP_ASSOCINFO SCTP_ASSOCINFO SCTP_INITMSG, #define SCTP_INITMSG SCTP_INITMSG - SCTP_AUTO_CLOSE, -#define SCTP_AUTO_CLOSE SCTP_AUTO_CLOSE - SCTP_SET_PRIMARY_ADDR, -#define SCTP_SET_PRIMARY_ADDR SCTP_SET_PRIMARY_ADDR + SCTP_NODELAY, /* Get/set nodelay option. */ +#define SCTP_NODELAY SCTP_NODELAY + SCTP_AUTOCLOSE, +#define SCTP_AUTOCLOSE SCTP_AUTOCLOSE SCTP_SET_PEER_PRIMARY_ADDR, #define SCTP_SET_PEER_PRIMARY_ADDR SCTP_SET_PEER_PRIMARY_ADDR - SCTP_SET_ADAPTATION_LAYER, -#define SCTP_SET_ADAPTATION_LAYER SCTP_SET_ADAPTATION_LAYER - SCTP_SET_STREAM_TIMEOUTS, -#define SCTP_SET_STREAM_TIMEOUTS SCTP_SET_STREAM_TIMEOUTS + SCTP_PRIMARY_ADDR, +#define SCTP_PRIMARY_ADDR SCTP_PRIMARY_ADDR + SCTP_ADAPTION_LAYER, +#define SCTP_ADAPTION_LAYER SCTP_ADAPTION_LAYER SCTP_DISABLE_FRAGMENTS, #define SCTP_DISABLE_FRAGMENTS SCTP_DISABLE_FRAGMENTS - SCTP_SET_PEER_ADDR_PARAMS, -#define SCTP_SET_PEER_ADDR_PARAMS SCTP_SET_PEER_ADDR_PARAMS - SCTP_GET_PEER_ADDR_PARAMS, -#define SCTP_GET_PEER_ADDR_PARAMS SCTP_GET_PEER_ADDR_PARAMS + SCTP_PEER_ADDR_PARAMS, +#define SCTP_PEER_ADDR_PARAMS SCTP_PEER_ADDR_PARAMS + SCTP_DEFAULT_SEND_PARAM, +#define SCTP_DEFAULT_SEND_PARAM SCTP_DEFAULT_SEND_PARAM + SCTP_EVENTS, +#define SCTP_EVENTS SCTP_EVENTS + SCTP_I_WANT_MAPPED_V4_ADDR, /* Turn on/off mapped v4 addresses */ +#define SCTP_I_WANT_MAPPED_V4_ADDR SCTP_I_WANT_MAPPED_V4_ADDR + SCTP_MAXSEG, /* Get/set maximum fragment. */ +#define SCTP_MAXSEG SCTP_MAXSEG SCTP_STATUS, #define SCTP_STATUS SCTP_STATUS SCTP_GET_PEER_ADDR_INFO, #define SCTP_GET_PEER_ADDR_INFO SCTP_GET_PEER_ADDR_INFO - SCTP_SET_EVENTS, -#define SCTP_SET_EVENTS SCTP_SET_EVENTS - SCTP_AUTOCLOSE, -#define SCTP_AUTOCLOSE SCTP_AUTOCLOSE - SCTP_SET_DEFAULT_SEND_PARAM, -#define SCTP_SET_DEFAULT_SEND_PARAM SCTP_SET_DEFAULT_SEND_PARAM - - SCTP_SOCKOPT_DEBUG_NAME = 42, /* FIXME */ -#define SCTP_SOCKOPT_DEBUG_NAME SCTP_SOCKOPT_DEBUG_NAME - SCTP_SOCKOPT_BINDX_ADD, /* BINDX requests for adding addresses. */ + /* Internal Socket Options. Some of the sctp library functions are + * implemented using these socket options. + */ + SCTP_SOCKOPT_BINDX_ADD = 100,/* BINDX requests for adding addresses. */ #define SCTP_SOCKOPT_BINDX_ADD SCTP_SOCKOPT_BINDX_ADD SCTP_SOCKOPT_BINDX_REM, /* BINDX requests for removing addresses. */ #define SCTP_SOCKOPT_BINDX_REM SCTP_SOCKOPT_BINDX_REM @@ -109,29 +109,8 @@ enum sctp_optname { #define SCTP_GET_LOCAL_ADDRS_NUM SCTP_GET_LOCAL_ADDRS_NUM SCTP_GET_LOCAL_ADDRS, /* Get all local addresss. */ #define SCTP_GET_LOCAL_ADDRS SCTP_GET_LOCAL_ADDRS - SCTP_NODELAY, /* Get/set nodelay option. */ -#define SCTP_NODELAY SCTP_NODELAY - SCTP_I_WANT_MAPPED_V4_ADDR, /* Turn on/off mapped v4 addresses */ -#define SCTP_I_WANT_MAPPED_V4_ADDR SCTP_I_WANT_MAPPED_V4_ADDR - SCTP_MAXSEG, /* Get/set maximum fragment. */ -#define SCTP_MAXSEG SCTP_MAXSEG }; - -/* - * 5.2 SCTP msg_control Structures - * - * A key element of all SCTP-specific socket extensions is the use of - * ancillary data to specify and access SCTP-specific data via the - * struct msghdr's msg_control member used in sendmsg() and recvmsg(). - * Fine-grained control over initialization and sending parameters are - * handled with ancillary data. - * - * Each ancillary data item is preceeded by a struct cmsghdr (see - * Section 5.1), which defines the function and purpose of the data - * contained in in the cmsg_data[] member. - */ - /* * 5.2.1 SCTP Initiation Structure (SCTP_INIT) * @@ -152,7 +131,6 @@ struct sctp_initmsg { __u16 sinit_max_init_timeo; }; - /* * 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV) * @@ -214,7 +192,6 @@ typedef enum sctp_cmsg_type { * following format: * */ - struct sctp_assoc_change { __u16 sac_type; __u16 sac_flags; @@ -267,11 +244,11 @@ struct sctp_paddr_change { * event that happened to the address. They include: */ enum sctp_spc_state { - ADDRESS_AVAILABLE, - ADDRESS_UNREACHABLE, - ADDRESS_REMOVED, - ADDRESS_ADDED, - ADDRESS_MADE_PRIM, + SCTP_ADDR_REACHABLE, + SCTP_ADDR_UNREACHABLE, + SCTP_ADDR_REMOVED, + SCTP_ADDR_ADDED, + SCTP_ADDR_MADE_PRIM, }; @@ -290,7 +267,6 @@ struct sctp_remote_error { __u16 sre_flags; __u32 sre_length; __u16 sre_error; - __u16 sre_len; sctp_assoc_t sre_assoc_id; __u8 sre_data[0]; }; @@ -324,7 +300,6 @@ struct sctp_send_failed { * Note that this does not necessarily mean that the * data was (or was not) successfully delivered. */ - enum sctp_ssf_flags { SCTP_DATA_UNSENT, SCTP_DATA_SENT, @@ -336,7 +311,6 @@ enum sctp_ssf_flags { * When a peer sends a SHUTDOWN, SCTP delivers this notification to * inform the application that it should cease sending data. */ - struct sctp_shutdown_event { __u16 sse_type; __u16 sse_flags; @@ -355,8 +329,8 @@ struct sctp_adaption_event { __u16 sai_type; __u16 sai_flags; __u32 sai_length; - __u32 sai_adaptation_bits; - sctp_assoc_t sse_assoc_id; + __u32 sai_adaption_ind; + sctp_assoc_t sai_assoc_id; }; /* @@ -366,8 +340,7 @@ struct sctp_adaption_event { * message this notification will be used to inidicate * various events. */ - -struct sctp_rcv_pdapi_event { +struct sctp_pdapi_event { __u16 pdapi_type; __u16 pdapi_flags; __u32 pdapi_length; @@ -404,14 +377,14 @@ union sctp_notification { __u16 sn_type; /* Notification type. */ __u16 sn_flags; __u32 sn_length; - } h; + } sn_header; struct sctp_assoc_change sn_assoc_change; - struct sctp_paddr_change sn_padr_change; + struct sctp_paddr_change sn_paddr_change; struct sctp_remote_error sn_remote_error; struct sctp_send_failed sn_send_failed; struct sctp_shutdown_event sn_shutdown_event; struct sctp_adaption_event sn_adaption_event; - struct sctp_rcv_pdapi_event sn_rcv_pdapi_event; + struct sctp_pdapi_event sn_pdapi_event; }; /* Section 5.3.1 @@ -447,76 +420,26 @@ typedef enum sctp_sn_error { SCTP_PEER_FAULTY, } sctp_sn_error_t; -/* - * - * 7.1.14 Peer Address Parameters - * - * Applications can enable or disable heartbeats for any peer address - * of an association, modify an address's heartbeat interval, force a - * heartbeat to be sent immediately, and adjust the address's maximum - * number of retransmissions sent before an address is considered - * unreachable. The following structure is used to access and modify an - * address's parameters: - */ - -struct sctp_paddrparams { - struct sockaddr_storage spp_address; - __u32 spp_hbinterval; - __u16 spp_pathmaxrxt; - sctp_assoc_t spp_assoc_id; -}; - -/* - * 7.2.2 Peer Address Information - * - * Applications can retrieve information about a specific peer address - * of an association, including its reachability state, congestion - * window, and retransmission timer values. This information is - * read-only. The following structure is used to access this - * information: - */ - -struct sctp_paddrinfo { - sctp_assoc_t spinfo_assoc_id; - struct sockaddr_storage spinfo_address; - __s32 spinfo_state; - __u32 spinfo_cwnd; - __u32 spinfo_srtt; - __u32 spinfo_rto; - __u32 spinfo_mtu; -}; - -/* Peer addresses's state. */ -enum sctp_spinfo_state { - SCTP_INACTIVE, - SCTP_ACTIVE, -}; - /* * 7.1.1 Retransmission Timeout Parameters (SCTP_RTOINFO) * * The protocol parameters used to initialize and bound retransmission * timeout (RTO) are tunable. See [SCTP] for more information on how - * these parameters are used in RTO calculation. The peer address - * parameter is ignored for TCP style socket. + * these parameters are used in RTO calculation. */ - struct sctp_rtoinfo { + sctp_assoc_t srto_assoc_id; __u32 srto_initial; __u32 srto_max; __u32 srto_min; - sctp_assoc_t srto_assoc_id; }; /* - * 7.1.2 Association Retransmission Parameter (SCTP_ASSOCRTXINFO) + * 7.1.2 Association Parameters (SCTP_ASSOCINFO) * - * The protocol parameter used to set the number of retransmissions - * sent before an association is considered unreachable. - * See [SCTP] for more information on how this parameter is used. The - * peer address parameter is ignored for TCP style socket. + * This option is used to both examine and set various association and + * endpoint parameters. */ - struct sctp_assocparams { sctp_assoc_t sasoc_assoc_id; __u16 sasoc_asocmaxrxt; @@ -527,31 +450,81 @@ struct sctp_assocparams { }; /* - * 7.1.9 Set Primary Address (SCTP_SET_PRIMARY_ADDR) + * 7.1.9 Set Peer Primary Address (SCTP_SET_PEER_PRIMARY_ADDR) * * Requests that the peer mark the enclosed address as the association * primary. The enclosed address must be one of the association's * locally bound addresses. The following structure is used to make a * set primary request: */ - -struct sctp_setprim { - struct sockaddr_storage ssp_addr; - sctp_assoc_t ssp_assoc_id; +struct sctp_setpeerprim { + sctp_assoc_t sspp_assoc_id; + struct sockaddr_storage sspp_addr; }; /* - * 7.1.10 Set Peer Primary Address (SCTP_SET_PEER_PRIMARY_ADDR) + * 7.1.10 Set Primary Address (SCTP_PRIMARY_ADDR) * * Requests that the local SCTP stack use the enclosed peer address as * the association primary. The enclosed address must be one of the * association peer's addresses. The following structure is used to * make a set peer primary request: */ +struct sctp_prim { + sctp_assoc_t ssp_assoc_id; + struct sockaddr_storage ssp_addr; +}; -struct sctp_setpeerprim { - struct sockaddr_storage sspp_addr; - sctp_assoc_t sspp_assoc_id; +/* + * 7.1.11 Set Adaption Layer Indicator (SCTP_ADAPTION_LAYER) + * + * Requests that the local endpoint set the specified Adaption Layer + * Indication parameter for all future INIT and INIT-ACK exchanges. + */ +struct sctp_setadaption { + __u32 ssb_adaption_ind; +}; + +/* + * 7.1.13 Peer Address Parameters (SCTP_PEER_ADDR_PARAMS) + * + * Applications can enable or disable heartbeats for any peer address + * of an association, modify an address's heartbeat interval, force a + * heartbeat to be sent immediately, and adjust the address's maximum + * number of retransmissions sent before an address is considered + * unreachable. The following structure is used to access and modify an + * address's parameters: + */ +struct sctp_paddrparams { + sctp_assoc_t spp_assoc_id; + struct sockaddr_storage spp_address; + __u32 spp_hbinterval; + __u16 spp_pathmaxrxt; +}; + +/* + * 7.2.2 Peer Address Information + * + * Applications can retrieve information about a specific peer address + * of an association, including its reachability state, congestion + * window, and retransmission timer values. This information is + * read-only. The following structure is used to access this + * information: + */ +struct sctp_paddrinfo { + sctp_assoc_t spinfo_assoc_id; + struct sockaddr_storage spinfo_address; + __s32 spinfo_state; + __u32 spinfo_cwnd; + __u32 spinfo_srtt; + __u32 spinfo_rto; + __u32 spinfo_mtu; +}; + +/* Peer addresses's state. */ +enum sctp_spinfo_state { + SCTP_INACTIVE, + SCTP_ACTIVE, }; /* @@ -575,34 +548,8 @@ struct sctp_status { struct sctp_paddrinfo sstat_primary; }; - -/* - * 7.1.12 Set Adaption Layer Indicator - * - * Requests that the local endpoint set the specified Adaption Layer - * Indication parameter for all future - * INIT and INIT-ACK exchanges. - */ - -struct sctp_setadaption { - __u32 ssb_adaption_ind; -}; - -/* - * 7.1.12 Set default message time outs (SCTP_SET_STREAM_TIMEOUTS) - * - * This option requests that the requested stream apply a - * default time-out for messages in queue. - */ -struct sctp_setstrm_timeout { - sctp_assoc_t ssto_assoc_id; - __u32 ssto_timeout; - __u16 ssto_streamid_start; - __u16 ssto_streamid_end; -}; - /* - * 8.3 8.5 get all peer/local addresses on a socket + * 8.3, 8.5 get all peer/local addresses on a socket * This parameter struct is for getsockopt */ struct sctp_getaddrs { @@ -624,8 +571,8 @@ enum sctp_msg_flags { * The flags parameter is formed from the bitwise OR of zero or more of the * following currently defined flags: */ -#define BINDX_ADD_ADDR 0x01 -#define BINDX_REM_ADDR 0x02 +#define SCTP_BINDX_ADD_ADDR 0x01 +#define SCTP_BINDX_REM_ADDR 0x02 /* This is the structure that is passed as an argument(optval) to * getsockopt(SCTP_SOCKOPT_PEELOFF). @@ -636,6 +583,3 @@ typedef struct { } sctp_peeloff_arg_t; #endif /* __net_sctp_user_h__ */ - - - diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 8b6558cf7aa2..fa9ecdd2d856 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -556,12 +556,12 @@ void sctp_assoc_control_transport(struct sctp_association *asoc, switch (command) { case SCTP_TRANSPORT_UP: transport->active = SCTP_ACTIVE; - spc_state = ADDRESS_AVAILABLE; + spc_state = SCTP_ADDR_REACHABLE; break; case SCTP_TRANSPORT_DOWN: transport->active = SCTP_INACTIVE; - spc_state = ADDRESS_UNREACHABLE; + spc_state = SCTP_ADDR_UNREACHABLE; break; default: diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 3d47c69a3f46..db8071ffe478 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -365,15 +365,15 @@ static int __sctp_bindx(struct sock *sk, struct sockaddr_storage *addrs, SCTP_DEBUG_PRINTK("__sctp_bindx(sk: %p, addrs: %p, addrcnt: %d, " "flags: %s)\n", sk, addrs, addrcnt, - (BINDX_ADD_ADDR == flags) ? "ADD" : - ((BINDX_REM_ADDR == flags) ? "REM" : "BOGUS")); + (SCTP_BINDX_ADD_ADDR == flags) ? "ADD" : + ((SCTP_BINDX_REM_ADDR == flags) ? "REM" : "BOGUS")); switch (flags) { - case BINDX_ADD_ADDR: + case SCTP_BINDX_ADD_ADDR: retval = sctp_bindx_add(sk, addrs, addrcnt); break; - case BINDX_REM_ADDR: + case SCTP_BINDX_REM_ADDR: retval = sctp_bindx_rem(sk, addrs, addrcnt); break; @@ -1431,7 +1431,7 @@ static int sctp_setsockopt_autoclose(struct sock *sk, char *optval, return 0; } -/* 7.1.13 Peer Address Parameters (SCTP_SET_PEER_ADDR_PARAMS) +/* 7.1.13 Peer Address Parameters (SCTP_PEER_ADDR_PARAMS) * * Applications can enable or disable heartbeats for any peer address of * an association, modify an address's heartbeat interval, force a @@ -1581,24 +1581,25 @@ static int sctp_setsockopt_default_send_param(struct sock *sk, return 0; } -/* 7.1.10 Set Peer Primary Address (SCTP_SET_PEER_PRIMARY_ADDR) +/* 7.1.10 Set Peer Primary Address (SCTP_PRIMARY_ADDR) * * Requests that the local SCTP stack use the enclosed peer address as * the association primary. The enclosed address must be one of the * association peer's addresses. */ -static int sctp_setsockopt_peer_prim(struct sock *sk, char *optval, int optlen) +static int sctp_setsockopt_primary_addr(struct sock *sk, char *optval, + int optlen) { - struct sctp_setpeerprim prim; + struct sctp_prim prim; struct sctp_transport *trans; - if (optlen != sizeof(struct sctp_setpeerprim)) + if (optlen != sizeof(struct sctp_prim)) return -EINVAL; - if (copy_from_user(&prim, optval, sizeof(struct sctp_setpeerprim))) + if (copy_from_user(&prim, optval, sizeof(struct sctp_prim))) return -EFAULT; - trans = sctp_addr_id2transport(sk, &prim.sspp_addr, prim.sspp_assoc_id); + trans = sctp_addr_id2transport(sk, &prim.ssp_addr, prim.ssp_assoc_id); if (!trans) return -EINVAL; @@ -1692,8 +1693,8 @@ static int sctp_setsockopt_rtoinfo(struct sock *sk, char *optval, int optlen) { * See [SCTP] for more information. * */ -static int sctp_setsockopt_assocrtx(struct sock *sk, char *optval, - int optlen) { +static int sctp_setsockopt_associnfo(struct sock *sk, char *optval, int optlen) +{ struct sctp_assocparams assocparams; struct sctp_association *asoc; @@ -1804,7 +1805,6 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen) { int retval = 0; - char *tmp; SCTP_DEBUG_PRINTK("sctp_setsockopt(sk: %p... optname: %d)\n", sk, optname); @@ -1824,38 +1824,25 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname, sctp_lock_sock(sk); switch (optname) { - case SCTP_SOCKOPT_DEBUG_NAME: - /* BUG! we don't ever seem to free this memory. --jgrimm */ - if (NULL == (tmp = kmalloc(optlen + 1, GFP_KERNEL))) { - retval = -ENOMEM; - goto out_unlock; - } - - if (copy_from_user(tmp, optval, optlen)) { - retval = -EFAULT; - goto out_unlock; - } - tmp[optlen] = '\000'; - sctp_sk(sk)->ep->debug_name = tmp; - break; - case SCTP_SOCKOPT_BINDX_ADD: /* 'optlen' is the size of the addresses buffer. */ retval = sctp_setsockopt_bindx(sk, (struct sockaddr_storage *) - optval, optlen, BINDX_ADD_ADDR); + optval, optlen, + SCTP_BINDX_ADD_ADDR); break; case SCTP_SOCKOPT_BINDX_REM: /* 'optlen' is the size of the addresses buffer. */ retval = sctp_setsockopt_bindx(sk, (struct sockaddr_storage *) - optval, optlen, BINDX_REM_ADDR); + optval, optlen, + SCTP_BINDX_REM_ADDR); break; case SCTP_DISABLE_FRAGMENTS: retval = sctp_setsockopt_disable_fragments(sk, optval, optlen); break; - case SCTP_SET_EVENTS: + case SCTP_EVENTS: retval = sctp_setsockopt_events(sk, optval, optlen); break; @@ -1863,19 +1850,19 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname, retval = sctp_setsockopt_autoclose(sk, optval, optlen); break; - case SCTP_SET_PEER_ADDR_PARAMS: + case SCTP_PEER_ADDR_PARAMS: retval = sctp_setsockopt_peer_addr_params(sk, optval, optlen); break; case SCTP_INITMSG: retval = sctp_setsockopt_initmsg(sk, optval, optlen); break; - case SCTP_SET_DEFAULT_SEND_PARAM: + case SCTP_DEFAULT_SEND_PARAM: retval = sctp_setsockopt_default_send_param(sk, optval, optlen); break; - case SCTP_SET_PEER_PRIMARY_ADDR: - retval = sctp_setsockopt_peer_prim(sk, optval, optlen); + case SCTP_PRIMARY_ADDR: + retval = sctp_setsockopt_primary_addr(sk, optval, optlen); break; case SCTP_NODELAY: retval = sctp_setsockopt_nodelay(sk, optval, optlen); @@ -1883,8 +1870,8 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname, case SCTP_RTOINFO: retval = sctp_setsockopt_rtoinfo(sk, optval, optlen); break; - case SCTP_ASSOCRTXINFO: - retval = sctp_setsockopt_assocrtx(sk, optval, optlen); + case SCTP_ASSOCINFO: + retval = sctp_setsockopt_associnfo(sk, optval, optlen); break; case SCTP_I_WANT_MAPPED_V4_ADDR: retval = sctp_setsockopt_mappedv4(sk, optval, optlen); @@ -1897,7 +1884,6 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname, break; }; -out_unlock: sctp_release_sock(sk); out_nounlock: @@ -2173,7 +2159,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) } /* Default Peer Address Parameters. These defaults can - * be modified via SCTP_SET_PEER_ADDR_PARAMS + * be modified via SCTP_PEER_ADDR_PARAMS */ sp->paddrparam.spp_hbinterval = (sctp_hb_interval / HZ) * 1000; sp->paddrparam.spp_pathmaxrxt = sctp_max_retrans_path; @@ -2418,12 +2404,13 @@ static int sctp_getsockopt_disable_fragments(struct sock *sk, int len, return 0; } -/* 7.1.15 Set notification and ancillary events (SCTP_SET_EVENTS) +/* 7.1.15 Set notification and ancillary events (SCTP_EVENTS) * * This socket option is used to specify various notifications and * ancillary data the user wishes to receive. */ -static int sctp_getsockopt_set_events(struct sock *sk, int len, char *optval, int *optlen) +static int sctp_getsockopt_events(struct sock *sk, int len, char *optval, + int *optlen) { if (len != sizeof(struct sctp_event_subscribe)) return -EINVAL; @@ -2526,7 +2513,7 @@ out: return retval; } -/* 7.1.13 Peer Address Parameters (SCTP_SET_PEER_ADDR_PARAMS) +/* 7.1.13 Peer Address Parameters (SCTP_PEER_ADDR_PARAMS) * * Applications can enable or disable heartbeats for any peer address of * an association, modify an address's heartbeat interval, force a @@ -2776,35 +2763,35 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, return 0; } -/* 7.1.10 Set Peer Primary Address (SCTP_SET_PEER_PRIMARY_ADDR) +/* 7.1.10 Set Primary Address (SCTP_PRIMARY_ADDR) * * Requests that the local SCTP stack use the enclosed peer address as * the association primary. The enclosed address must be one of the * association peer's addresses. */ -static int sctp_getsockopt_peer_prim(struct sock *sk, int len, - char *optval, int *optlen) +static int sctp_getsockopt_primary_addr(struct sock *sk, int len, + char *optval, int *optlen) { - struct sctp_setpeerprim prim; + struct sctp_prim prim; struct sctp_association *asoc; - if (len != sizeof(struct sctp_setpeerprim)) + if (len != sizeof(struct sctp_prim)) return -EINVAL; - if (copy_from_user(&prim, optval, sizeof(struct sctp_setpeerprim))) + if (copy_from_user(&prim, optval, sizeof(struct sctp_prim))) return -EFAULT; - asoc = sctp_id2assoc(sk, prim.sspp_assoc_id); + asoc = sctp_id2assoc(sk, prim.ssp_assoc_id); if (!asoc) return -EINVAL; if (!asoc->peer.primary_path) return -ENOTCONN; - memcpy(&prim.sspp_addr, &asoc->peer.primary_path->ipaddr, + memcpy(&prim.ssp_addr, &asoc->peer.primary_path->ipaddr, sizeof(union sctp_addr)); - if (copy_to_user(optval, &prim, sizeof(struct sctp_setpeerprim))) + if (copy_to_user(optval, &prim, sizeof(struct sctp_prim))) return -EFAULT; return 0; @@ -2952,8 +2939,9 @@ static int sctp_getsockopt_rtoinfo(struct sock *sk, int len, char *optval, * See [SCTP] for more information. * */ -static int sctp_getsockopt_assocrtx(struct sock *sk, int len, char *optval, - int *optlen) { +static int sctp_getsockopt_associnfo(struct sock *sk, int len, char *optval, + int *optlen) +{ struct sctp_assocparams assocparams; struct sctp_association *asoc; @@ -3101,8 +3089,8 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, retval = sctp_getsockopt_disable_fragments(sk, len, optval, optlen); break; - case SCTP_SET_EVENTS: - retval = sctp_getsockopt_set_events(sk, len, optval, optlen); + case SCTP_EVENTS: + retval = sctp_getsockopt_events(sk, len, optval, optlen); break; case SCTP_AUTOCLOSE: retval = sctp_getsockopt_autoclose(sk, len, optval, optlen); @@ -3110,7 +3098,7 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, case SCTP_SOCKOPT_PEELOFF: retval = sctp_getsockopt_peeloff(sk, len, optval, optlen); break; - case SCTP_GET_PEER_ADDR_PARAMS: + case SCTP_PEER_ADDR_PARAMS: retval = sctp_getsockopt_peer_addr_params(sk, len, optval, optlen); break; @@ -3133,12 +3121,12 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, retval = sctp_getsockopt_local_addrs(sk, len, optval, optlen); break; - case SCTP_SET_DEFAULT_SEND_PARAM: + case SCTP_DEFAULT_SEND_PARAM: retval = sctp_getsockopt_default_send_param(sk, len, optval, optlen); break; - case SCTP_SET_PEER_PRIMARY_ADDR: - retval = sctp_getsockopt_peer_prim(sk, len, optval, optlen); + case SCTP_PRIMARY_ADDR: + retval = sctp_getsockopt_primary_addr(sk, len, optval, optlen); break; case SCTP_NODELAY: retval = sctp_getsockopt_nodelay(sk, len, optval, optlen); @@ -3146,8 +3134,8 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, case SCTP_RTOINFO: retval = sctp_getsockopt_rtoinfo(sk, len, optval, optlen); break; - case SCTP_ASSOCRTXINFO: - retval = sctp_getsockopt_assocrtx(sk, len, optval, optlen); + case SCTP_ASSOCINFO: + retval = sctp_getsockopt_associnfo(sk, len, optval, optlen); break; case SCTP_I_WANT_MAPPED_V4_ADDR: retval = sctp_getsockopt_mappedv4(sk, len, optval, optlen); diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c index 5071373e8e91..64421cc78471 100644 --- a/net/sctp/ulpevent.c +++ b/net/sctp/ulpevent.c @@ -727,7 +727,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_pdapi( const struct sctp_association *asoc, __u32 indication, int gfp) { struct sctp_ulpevent *event; - struct sctp_rcv_pdapi_event *pd; + struct sctp_pdapi_event *pd; struct sk_buff *skb; event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change), @@ -736,8 +736,8 @@ struct sctp_ulpevent *sctp_ulpevent_make_pdapi( goto fail; skb = sctp_event2skb(event); - pd = (struct sctp_rcv_pdapi_event *) - skb_put(skb, sizeof(struct sctp_rcv_pdapi_event)); + pd = (struct sctp_pdapi_event *) + skb_put(skb, sizeof(struct sctp_pdapi_event)); /* pdapi_type * It should be SCTP_PARTIAL_DELIVERY_EVENT @@ -752,9 +752,9 @@ struct sctp_ulpevent *sctp_ulpevent_make_pdapi( * * This field is the total length of the notification data, including * the notification header. It will generally be sizeof (struct - * sctp_rcv_pdapi_event). + * sctp_pdapi_event). */ - pd->pdapi_length = sizeof(struct sctp_rcv_pdapi_event); + pd->pdapi_length = sizeof(struct sctp_pdapi_event); /* pdapi_indication: 32 bits (unsigned integer) * @@ -784,7 +784,7 @@ __u16 sctp_ulpevent_get_notification_type(const struct sctp_ulpevent *event) skb = sctp_event2skb((struct sctp_ulpevent *)event); notification = (union sctp_notification *) skb->data; - return notification->h.sn_type; + return notification->sn_header.sn_type; } /* Copy out the sndrcvinfo into a msghdr. */ -- cgit v1.2.3 From 845ddb449836d43b741d5c5000e4a79a9358e562 Mon Sep 17 00:00:00 2001 From: Jon Grimm Date: Tue, 15 Jul 2003 03:53:43 -0500 Subject: [SCTP] Support v4-mapped-v6 addresses (Ardelle Fan) --- include/net/sctp/sctp.h | 19 ++++++++ include/net/sctp/structs.h | 9 ++-- include/net/sctp/user.h | 2 + net/sctp/input.c | 2 +- net/sctp/ipv6.c | 116 +++++++++++++++++++++++++++++++++------------ net/sctp/protocol.c | 15 ++++-- net/sctp/socket.c | 43 +++++++++++++---- net/sctp/ulpevent.c | 6 +++ 8 files changed, 165 insertions(+), 47 deletions(-) (limited to 'include') diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index 3793352764c0..68f550019491 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -611,4 +611,23 @@ int static inline __sctp_sstate(const struct sock *sk, sctp_sock_state_t state) return sk->sk_state == state; } +/* Map v4-mapped v6 address back to v4 address */ +static inline void sctp_v6_map_v4(union sctp_addr *addr) +{ + addr->v4.sin_family = AF_INET; + addr->v4.sin_port = addr->v6.sin6_port; + addr->v4.sin_addr.s_addr = addr->v6.sin6_addr.s6_addr32[3]; +} + +/* Map v4 address to v4-mapped v6 address */ +static inline void sctp_v4_map_v6(union sctp_addr *addr) +{ + addr->v6.sin6_family = AF_INET6; + addr->v6.sin6_port = addr->v4.sin_port; + addr->v6.sin6_addr.s6_addr32[3] = addr->v4.sin_addr.s_addr; + addr->v6.sin6_addr.s6_addr32[0] = 0; + addr->v6.sin6_addr.s6_addr32[1] = 0; + addr->v6.sin6_addr.s6_addr32[2] = htonl(0x0000ffff); +} + #endif /* __net_sctp_h__ */ diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 94bebc0b7ce0..aae255de586b 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -260,11 +260,13 @@ struct sctp_af { struct sock *sk); void (*to_sk_daddr) (union sctp_addr *, struct sock *sk); - int (*addr_valid) (union sctp_addr *); + int (*addr_valid) (union sctp_addr *, + struct sctp_opt *); sctp_scope_t (*scope) (union sctp_addr *); void (*inaddr_any) (union sctp_addr *, unsigned short); int (*is_any) (const union sctp_addr *); - int (*available) (const union sctp_addr *); + int (*available) (union sctp_addr *, + struct sctp_opt *); int (*skb_iif) (const struct sk_buff *sk); int (*is_ce) (const struct sk_buff *sk); void (*seq_dump_addr)(struct seq_file *seq, @@ -282,7 +284,7 @@ int sctp_register_af(struct sctp_af *); struct sctp_pf { void (*event_msgname)(struct sctp_ulpevent *, char *, int *); void (*skb_msgname) (struct sk_buff *, char *, int *); - int (*af_supported) (sa_family_t); + int (*af_supported) (sa_family_t, struct sctp_opt *); int (*cmp_addr) (const union sctp_addr *, const union sctp_addr *, struct sctp_opt *); @@ -291,6 +293,7 @@ struct sctp_pf { int (*supported_addrs)(const struct sctp_opt *, __u16 *); struct sock *(*create_accept_sk) (struct sock *sk, struct sctp_association *asoc); + void (*addr_v4map) (struct sctp_opt *, union sctp_addr *); struct sctp_af *af; }; diff --git a/include/net/sctp/user.h b/include/net/sctp/user.h index e51992a2fe22..da96859dba92 100644 --- a/include/net/sctp/user.h +++ b/include/net/sctp/user.h @@ -2,6 +2,7 @@ * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 2001-2003 International Business Machines, Corp. + * Copyright (c) 2002 Intel Corp. * * This file is part of the SCTP kernel reference Implementation * @@ -41,6 +42,7 @@ * Jon Grimm * Daisy Chang * Ryan Layer + * Ardelle Fan * Sridhar Samudrala * * Any bugs reported given to us we will try to fix... any fixes shared will diff --git a/net/sctp/input.c b/net/sctp/input.c index 8c4cc2c233a6..014327be95d1 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -150,7 +150,7 @@ int sctp_rcv(struct sk_buff *skb) * IP broadcast addresses cannot be used in an SCTP transport * address." */ - if (!af->addr_valid(&src) || !af->addr_valid(&dest)) + if (!af->addr_valid(&src, NULL) || !af->addr_valid(&dest, NULL)) goto discard_it; asoc = __sctp_rcv_lookup(skb, &src, &dest, &transport); diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 858f3b922ad3..9bce347a4510 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -2,6 +2,7 @@ * Copyright (c) 2001 Nokia, Inc. * Copyright (c) 2001 La Monte H.P. Yarroll * Copyright (c) 2002-2003 International Business Machines, Corp. + * Copyright (c) 2002-2003 Intel Corp. * * This file is part of the SCTP kernel reference Implementation * @@ -15,7 +16,7 @@ * * The SCTP reference implementation is distributed in the hope that it * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * ************************ + * ************************ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * @@ -32,14 +33,15 @@ * http://www.sf.net/projects/lksctp * * Written or modified by: - * Le Yanqun + * Le Yanqun * Hui Huang * La Monte H.P. Yarroll * Sridhar Samudrala - * Jon Grimm + * Jon Grimm + * Ardelle Fan * * Based on: - * linux/net/ipv6/tcp_ipv6.c + * linux/net/ipv6/tcp_ipv6.c * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. @@ -172,7 +174,7 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport, SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, " "src:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x " "dst:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", - __FUNCTION__, skb, skb->len, + __FUNCTION__, skb, skb->len, NIP6(fl.fl6_src), NIP6(fl.fl6_dst)); SCTP_INC_STATS(SctpOutSCTPPacks); @@ -370,13 +372,28 @@ static void sctp_v6_from_sk(union sctp_addr *addr, struct sock *sk) /* Initialize sk->sk_rcv_saddr from sctp_addr. */ static void sctp_v6_to_sk_saddr(union sctp_addr *addr, struct sock *sk) { - inet6_sk(sk)->rcv_saddr = addr->v6.sin6_addr; + if (addr->sa.sa_family == AF_INET && sctp_sk(sk)->v4mapped) { + inet6_sk(sk)->rcv_saddr.s6_addr32[0] = 0; + inet6_sk(sk)->rcv_saddr.s6_addr32[1] = 0; + inet6_sk(sk)->rcv_saddr.s6_addr32[2] = htonl(0x0000ffff); + inet6_sk(sk)->rcv_saddr.s6_addr32[3] = + addr->v4.sin_addr.s_addr; + } else { + inet6_sk(sk)->rcv_saddr = addr->v6.sin6_addr; + } } /* Initialize sk->sk_daddr from sctp_addr. */ static void sctp_v6_to_sk_daddr(union sctp_addr *addr, struct sock *sk) { - inet6_sk(sk)->daddr = addr->v6.sin6_addr; + if (addr->sa.sa_family == AF_INET && sctp_sk(sk)->v4mapped) { + inet6_sk(sk)->daddr.s6_addr32[0] = 0; + inet6_sk(sk)->daddr.s6_addr32[1] = 0; + inet6_sk(sk)->daddr.s6_addr32[2] = htonl(0x0000ffff); + inet6_sk(sk)->daddr.s6_addr32[3] = addr->v4.sin_addr.s_addr; + } else { + inet6_sk(sk)->daddr = addr->v6.sin6_addr; + } } /* Initialize a sctp_addr from a dst_entry. */ @@ -390,13 +407,30 @@ static void sctp_v6_dst_saddr(union sctp_addr *addr, struct dst_entry *dst, } /* Compare addresses exactly. - * FIXME: v4-mapped-v6. + * v4-mapped-v6 is also in consideration. */ static int sctp_v6_cmp_addr(const union sctp_addr *addr1, const union sctp_addr *addr2) { - if (addr1->sa.sa_family != addr2->sa.sa_family) + if (addr1->sa.sa_family != addr2->sa.sa_family) { + if (addr1->sa.sa_family == AF_INET && + addr2->sa.sa_family == AF_INET6 && + IPV6_ADDR_MAPPED == ipv6_addr_type(&addr2->v6.sin6_addr)) { + if (addr2->v6.sin6_port == addr1->v4.sin_port && + addr2->v6.sin6_addr.s6_addr32[3] == + addr1->v4.sin_addr.s_addr) + return 1; + } + if (addr2->sa.sa_family == AF_INET && + addr1->sa.sa_family == AF_INET6 && + IPV6_ADDR_MAPPED == ipv6_addr_type(&addr1->v6.sin6_addr)) { + if (addr1->v6.sin6_port == addr2->v4.sin_port && + addr1->v6.sin6_addr.s6_addr32[3] == + addr2->v4.sin_addr.s_addr) + return 1; + } return 0; + } if (ipv6_addr_cmp(&addr1->v6.sin6_addr, &addr2->v6.sin6_addr)) return 0; /* If this is a linklocal address, compare the scope_id. */ @@ -427,7 +461,7 @@ static int sctp_v6_is_any(const union sctp_addr *addr) } /* Should this be available for binding? */ -static int sctp_v6_available(const union sctp_addr *addr) +static int sctp_v6_available(union sctp_addr *addr, struct sctp_opt *sp) { int type; struct in6_addr *in6 = (struct in6_addr *)&addr->v6.sin6_addr; @@ -435,6 +469,12 @@ static int sctp_v6_available(const union sctp_addr *addr) type = ipv6_addr_type(in6); if (IPV6_ADDR_ANY == type) return 1; + if (type == IPV6_ADDR_MAPPED) { + if (sp && !sp->v4mapped) + return 0; + sctp_v6_map_v4(addr); + return sctp_get_af_specific(AF_INET)->available(addr, sp); + } if (!(type & IPV6_ADDR_UNICAST)) return 0; @@ -448,11 +488,20 @@ static int sctp_v6_available(const union sctp_addr *addr) * Return 0 - If the address is a non-unicast or an illegal address. * Return 1 - If the address is a unicast. */ -static int sctp_v6_addr_valid(union sctp_addr *addr) +static int sctp_v6_addr_valid(union sctp_addr *addr, struct sctp_opt *sp) { int ret = ipv6_addr_type(&addr->v6.sin6_addr); - /* FIXME: v4-mapped-v6 address support. */ + /* Support v4-mapped-v6 address. */ + if (ret == IPV6_ADDR_MAPPED) { + /* Note: This routine is used in input, so v4-mapped-v6 + * are disallowed here when there is no sctp_opt. + */ + if (!sp || !sp->v4mapped) + return 0; + sctp_v6_map_v4(addr); + return sctp_get_af_specific(AF_INET)->addr_valid(addr, sp); + } /* Is this a non-unicast address */ if (!(ret & IPV6_ADDR_UNICAST)) @@ -536,7 +585,7 @@ struct sock *sctp_v6_create_accept_sk(struct sock *sk, newnp->saddr = np->saddr; newnp->rcv_saddr = np->rcv_saddr; newinet->dport = htons(asoc->peer.port); - newnp->daddr = asoc->peer.primary_addr.v6.sin6_addr; + sctp_v6_to_sk_daddr(&asoc->peer.primary_addr, newsk); /* Init the ipv4 part of the socket since we can have sockets * using v6 API for ipv4. @@ -566,6 +615,13 @@ out: return newsk; } +/* Map v4 address to mapped v6 address */ +static void sctp_v6_addr_v4map(struct sctp_opt *sp, union sctp_addr *addr) +{ + if (sp->v4mapped && AF_INET == addr->sa.sa_family) + sctp_v4_map_v6(addr); +} + /* Where did this skb come from? */ static int sctp_v6_skb_iif(const struct sk_buff *skb) { @@ -617,10 +673,11 @@ static void sctp_inet6_event_msgname(struct sctp_ulpevent *event, */ /* Map ipv4 address into v4-mapped-on-v6 address. */ - if (AF_INET == addr->sa.sa_family) { - /* FIXME: Easy, but there was no way to test this - * yet. - */ + if (sctp_sk(event->asoc->base.sk)->v4mapped && + AF_INET == addr->sa.sa_family) { + sctp_v4_map_v6((union sctp_addr *)sin6); + sin6->sin6_addr.s6_addr32[3] = + addr->v4.sin_addr.s_addr; return; } @@ -644,16 +701,15 @@ static void sctp_inet6_skb_msgname(struct sk_buff *skb, char *msgname, sh = (struct sctphdr *)skb->h.raw; sin6->sin6_port = sh->source; - /* FIXME: Map ipv4 address into v4-mapped-on-v6 address. */ - if (__constant_htons(ETH_P_IP) == skb->protocol) { - /* FIXME: The latest I-D added options for two - * behaviors. - */ + /* Map ipv4 address into v4-mapped-on-v6 address. */ + if (sctp_sk(skb->sk)->v4mapped && + skb->nh.iph->version == 4) { + sctp_v4_map_v6((union sctp_addr *)sin6); + sin6->sin6_addr.s6_addr32[3] = skb->nh.iph->saddr; return; } /* Otherwise, just copy the v6 address. */ - ipv6_addr_copy(&sin6->sin6_addr, &skb->nh.ipv6h->saddr); if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) { struct sctp_ulpevent *ev = sctp_skb2event(skb); @@ -663,16 +719,15 @@ static void sctp_inet6_skb_msgname(struct sk_buff *skb, char *msgname, } /* Do we support this AF? */ -static int sctp_inet6_af_supported(sa_family_t family) +static int sctp_inet6_af_supported(sa_family_t family, struct sctp_opt *sp) { - /* FIXME: v4-mapped-v6 addresses. The I-D is still waffling - * on what to do with sockaddr formats for PF_INET6 sockets. - * For now assume we'll support both. - */ switch (family) { case AF_INET6: - case AF_INET: return 1; + /* v4-mapped-v6 addresses */ + case AF_INET: + if (sp->v4mapped) + return 1; default: return 0; } @@ -730,7 +785,7 @@ static int sctp_inet6_bind_verify(struct sctp_opt *opt, union sctp_addr *addr) } af = opt->pf->af; } - return af->available(addr); + return af->available(addr, opt); } /* Verify that the provided sockaddr looks bindable. Common verification, @@ -863,6 +918,7 @@ static struct sctp_pf sctp_pf_inet6_specific = { .send_verify = sctp_inet6_send_verify, .supported_addrs = sctp_inet6_supported_addrs, .create_accept_sk = sctp_v6_create_accept_sk, + .addr_v4map = sctp_v6_addr_v4map, .af = &sctp_ipv6_specific, }; diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 604215bd21d4..ba90deb6e025 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -340,7 +340,7 @@ static int sctp_v4_is_any(const union sctp_addr *addr) * Return 0 - If the address is a non-unicast or an illegal address. * Return 1 - If the address is a unicast. */ -static int sctp_v4_addr_valid(union sctp_addr *addr) +static int sctp_v4_addr_valid(union sctp_addr *addr, struct sctp_opt *sp) { /* Is this a non-unicast address or a unusable SCTP address? */ if (IS_IPV4_UNUSABLE_ADDRESS(&addr->v4.sin_addr.s_addr)) @@ -350,7 +350,7 @@ static int sctp_v4_addr_valid(union sctp_addr *addr) } /* Should this be available for binding? */ -static int sctp_v4_available(const union sctp_addr *addr) +static int sctp_v4_available(union sctp_addr *addr, struct sctp_opt *sp) { int ret = inet_addr_type(addr->v4.sin_addr.s_addr); @@ -580,6 +580,12 @@ out: return newsk; } +/* Map address, empty for v4 family */ +static void sctp_v4_addr_v4map(struct sctp_opt *sp, union sctp_addr *addr) +{ + /* Empty */ +} + /* Dump the v4 addr to the seq file. */ static void sctp_v4_seq_dump_addr(struct seq_file *seq, union sctp_addr *addr) { @@ -709,7 +715,7 @@ static void sctp_inet_skb_msgname(struct sk_buff *skb, char *msgname, int *len) } /* Do we support this AF? */ -static int sctp_inet_af_supported(sa_family_t family) +static int sctp_inet_af_supported(sa_family_t family, struct sctp_opt *sp) { /* PF_INET only supports AF_INET addresses. */ return (AF_INET == family); @@ -737,7 +743,7 @@ static int sctp_inet_cmp_addr(const union sctp_addr *addr1, */ static int sctp_inet_bind_verify(struct sctp_opt *opt, union sctp_addr *addr) { - return sctp_v4_available(addr); + return sctp_v4_available(addr, opt); } /* Verify that sockaddr looks sendable. Common verification has already @@ -783,6 +789,7 @@ static struct sctp_pf sctp_pf_inet = { .send_verify = sctp_inet_send_verify, .supported_addrs = sctp_inet_supported_addrs, .create_accept_sk = sctp_v4_create_accept_sk, + .addr_v4map = sctp_v4_addr_v4map, .af = &sctp_ipv4_specific, }; diff --git a/net/sctp/socket.c b/net/sctp/socket.c index db8071ffe478..237bc513730b 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -156,6 +156,9 @@ struct sctp_transport *sctp_addr_id2transport(struct sock *sk, if (id_asoc && (id_asoc != addr_asoc)) return NULL; + sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk), + (union sctp_addr *)addr); + return transport; } @@ -206,7 +209,7 @@ static struct sctp_af *sctp_sockaddr_af(struct sctp_opt *opt, return NULL; /* Does this PF support this AF? */ - if (!opt->pf->af_supported(addr->sa.sa_family)) + if (!opt->pf->af_supported(addr->sa.sa_family, opt)) return NULL; /* If we get this far, af is valid. */ @@ -1362,7 +1365,7 @@ out_free: /* Free the event which includes releasing the reference to * the owner of the skb, freeing the skb and updating the * rwnd. - */ + */ sctp_ulpevent_free(event); } out: @@ -1747,14 +1750,18 @@ static int sctp_setsockopt_associnfo(struct sock *sk, char *optval, int optlen) static int sctp_setsockopt_mappedv4(struct sock *sk, char *optval, int optlen) { int val; + struct sctp_opt *sp = sctp_sk(sk); if (optlen < sizeof(int)) return -EINVAL; if (get_user(val, (int *)optval)) return -EFAULT; - /* FIXME: Put real support here. */ + if (val) + sp->v4mapped = 1; + else + sp->v4mapped = 0; - return -ENOPROTOOPT; + return 0; } /* @@ -2305,6 +2312,9 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval, status.sstat_primary.spinfo_assoc_id = sctp_assoc2id(transport->asoc); memcpy(&status.sstat_primary.spinfo_address, &(transport->ipaddr), sizeof(union sctp_addr)); + /* Map ipv4 address into v4-mapped-on-v6 address. */ + sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk), + (union sctp_addr *)&status.sstat_primary.spinfo_address); status.sstat_primary.spinfo_state = transport->active; status.sstat_primary.spinfo_cwnd = transport->cwnd; status.sstat_primary.spinfo_srtt = transport->srtt; @@ -2642,6 +2652,8 @@ static int sctp_getsockopt_peer_addrs(struct sock *sk, int len, struct sctp_getaddrs getaddrs; struct sctp_transport *from; struct sockaddr_storage *to; + union sctp_addr temp; + struct sctp_opt *sp = sctp_sk(sk); if (len != sizeof(struct sctp_getaddrs)) return -EINVAL; @@ -2660,7 +2672,9 @@ static int sctp_getsockopt_peer_addrs(struct sock *sk, int len, to = getaddrs.addrs; list_for_each(pos, &asoc->peer.transport_addr_list) { from = list_entry(pos, struct sctp_transport, transports); - if (copy_to_user(to, &from->ipaddr, sizeof(from->ipaddr))) + memcpy(&temp, &from->ipaddr, sizeof(temp)); + sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp); + if (copy_to_user(to, &temp, sizeof(temp))) return -EFAULT; to ++; cnt ++; @@ -2722,6 +2736,8 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, struct sctp_getaddrs getaddrs; struct sctp_sockaddr_entry *from; struct sockaddr_storage *to; + union sctp_addr temp; + struct sctp_opt *sp = sctp_sk(sk); if (len != sizeof(struct sctp_getaddrs)) return -EINVAL; @@ -2750,7 +2766,9 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, from = list_entry(pos, struct sctp_sockaddr_entry, list); - if (copy_to_user(to, &from->a, sizeof(from->a))) + memcpy(&temp, &from->a, sizeof(temp)); + sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp); + if (copy_to_user(to, &temp, sizeof(temp))) return -EFAULT; to ++; cnt ++; @@ -2774,6 +2792,7 @@ static int sctp_getsockopt_primary_addr(struct sock *sk, int len, { struct sctp_prim prim; struct sctp_association *asoc; + struct sctp_opt *sp = sctp_sk(sk); if (len != sizeof(struct sctp_prim)) return -EINVAL; @@ -2791,6 +2810,9 @@ static int sctp_getsockopt_primary_addr(struct sock *sk, int len, memcpy(&prim.ssp_addr, &asoc->peer.primary_path->ipaddr, sizeof(union sctp_addr)); + sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, + (union sctp_addr *)&prim.ssp_addr); + if (copy_to_user(optval, &prim, sizeof(struct sctp_prim))) return -EFAULT; @@ -2805,6 +2827,8 @@ static int sctp_getsockopt_primary_addr(struct sock *sk, int len, * specify a default set of parameters that would normally be supplied * through the inclusion of ancillary data. This socket option allows * such an application to set the default sctp_sndrcvinfo structure. + + * The application that wishes to use this socket option simply passes * in to this call the sctp_sndrcvinfo structure defined in Section * 5.2.2) The input parameters accepted by this call include @@ -3012,12 +3036,13 @@ static int sctp_getsockopt_mappedv4(struct sock *sk, int len, char *optval, int *optlen) { int val; + struct sctp_opt *sp = sctp_sk(sk); + if (len < sizeof(int)) return -EINVAL; len = sizeof(int); - /* FIXME: Until we have support, return disabled. */ - val = 0; + val = sp->v4mapped; if (put_user(len, optlen)) return -EFAULT; if (copy_to_user(optval, &val, len)) @@ -3863,7 +3888,7 @@ static inline int sctp_verify_addr(struct sock *sk, union sctp_addr *addr, return -EINVAL; /* Is this a valid SCTP address? */ - if (!af->addr_valid(addr)) + if (!af->addr_valid(addr, sctp_sk(sk))) return -EINVAL; if (!sctp_sk(sk)->pf->send_verify(sctp_sk(sk), (addr))) diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c index 64421cc78471..982a4824b6c5 100644 --- a/net/sctp/ulpevent.c +++ b/net/sctp/ulpevent.c @@ -35,6 +35,7 @@ * Written or modified by: * Jon Grimm * La Monte H.P. Yarroll + * Ardelle Fan * Sridhar Samudrala * * Any bugs reported given to us we will try to fix... any fixes shared will @@ -286,6 +287,11 @@ struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change( */ memcpy(&spc->spc_aaddr, aaddr, sizeof(struct sockaddr_storage)); + /* Map ipv4 address into v4-mapped-on-v6 address. */ + sctp_get_pf_specific(asoc->base.sk->sk_family)->addr_v4map( + sctp_sk(asoc->base.sk), + (union sctp_addr *)&spc->spc_aaddr); + return event; fail: -- cgit v1.2.3 From 2766297cbfd0111d00e35cbff1a025e61874299b Mon Sep 17 00:00:00 2001 From: Sridhar Samudrala Date: Tue, 15 Jul 2003 21:10:08 -0700 Subject: [SCTP] Reduce the size of struct sctp_ulpevent so that it fits in skb->cb even on 64-bit systems. Removed the redundant 'asoc' field in struct sctp_ulpevent and instead use sinfo_assoc_id which is present within the other field 'sndrcvinfo'. This makes the size of struct sctp_ulpevent to be less than the size of skb->cb[](48 bytes) even on 64-bit systems. --- include/net/sctp/ulpevent.h | 1 - net/sctp/ipv6.c | 10 ++++++---- net/sctp/protocol.c | 7 +++++-- net/sctp/socket.c | 7 ++++--- net/sctp/ulpevent.c | 7 ++++--- 5 files changed, 19 insertions(+), 13 deletions(-) (limited to 'include') diff --git a/include/net/sctp/ulpevent.h b/include/net/sctp/ulpevent.h index 6e43599919ee..949a23835584 100644 --- a/include/net/sctp/ulpevent.h +++ b/include/net/sctp/ulpevent.h @@ -54,7 +54,6 @@ * growing this structure as it is at the maximum limit now. */ struct sctp_ulpevent { - struct sctp_association *asoc; struct sctp_sndrcvinfo sndrcvinfo; int msg_flags; int iif; diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 9bce347a4510..9155a06e2acd 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -662,18 +662,20 @@ static void sctp_inet6_event_msgname(struct sctp_ulpevent *event, if (msgname) { union sctp_addr *addr; + struct sctp_association *asoc; + asoc = event->sndrcvinfo.sinfo_assoc_id; sctp_inet6_msgname(msgname, addrlen); sin6 = (struct sockaddr_in6 *)msgname; - sin6->sin6_port = htons(event->asoc->peer.port); - addr = &event->asoc->peer.primary_addr; + sin6->sin6_port = htons(asoc->peer.port); + addr = &asoc->peer.primary_addr; /* Note: If we go to a common v6 format, this code * will change. */ /* Map ipv4 address into v4-mapped-on-v6 address. */ - if (sctp_sk(event->asoc->base.sk)->v4mapped && + if (sctp_sk(asoc->base.sk)->v4mapped && AF_INET == addr->sa.sa_family) { sctp_v4_map_v6((union sctp_addr *)sin6); sin6->sin6_addr.s6_addr32[3] = @@ -681,7 +683,7 @@ static void sctp_inet6_event_msgname(struct sctp_ulpevent *event, return; } - sin6from = &event->asoc->peer.primary_addr.v6; + sin6from = &asoc->peer.primary_addr.v6; ipv6_addr_copy(&sin6->sin6_addr, &sin6from->sin6_addr); if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) sin6->sin6_scope_id = sin6from->sin6_scope_id; diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index ba90deb6e025..5e0c6aa9d100 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -691,10 +691,13 @@ static void sctp_inet_event_msgname(struct sctp_ulpevent *event, char *msgname, struct sockaddr_in *sin, *sinfrom; if (msgname) { + struct sctp_association *asoc; + + asoc = event->sndrcvinfo.sinfo_assoc_id; sctp_inet_msgname(msgname, addr_len); sin = (struct sockaddr_in *)msgname; - sinfrom = &event->asoc->peer.primary_addr.v4; - sin->sin_port = htons(event->asoc->peer.port); + sinfrom = &asoc->peer.primary_addr.v4; + sin->sin_port = htons(asoc->peer.port); sin->sin_addr.s_addr = sinfrom->sin_addr.s_addr; } } diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 237bc513730b..962699973875 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -1347,7 +1347,8 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, * rwnd by that amount. If all the data in the skb is read, * rwnd is updated when the event is freed. */ - sctp_assoc_rwnd_increase(event->asoc, copied); + sctp_assoc_rwnd_increase(event->sndrcvinfo.sinfo_assoc_id, + copied); goto out; } else if ((event->msg_flags & MSG_NOTIFICATION) || (event->msg_flags & MSG_EOR)) @@ -4233,7 +4234,7 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, */ sctp_skb_for_each(skb, &oldsk->sk_receive_queue, tmp) { event = sctp_skb2event(skb); - if (event->asoc == assoc) { + if (event->sndrcvinfo.sinfo_assoc_id == assoc) { __skb_unlink(skb, skb->list); __skb_queue_tail(&newsk->sk_receive_queue, skb); } @@ -4262,7 +4263,7 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, */ sctp_skb_for_each(skb, &oldsp->pd_lobby, tmp) { event = sctp_skb2event(skb); - if (event->asoc == assoc) { + if (event->sndrcvinfo.sinfo_assoc_id == assoc) { __skb_unlink(skb, skb->list); __skb_queue_tail(queue, skb); } diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c index 982a4824b6c5..e56e1fdb156c 100644 --- a/net/sctp/ulpevent.c +++ b/net/sctp/ulpevent.c @@ -831,14 +831,14 @@ static inline void sctp_ulpevent_set_owner(struct sctp_ulpevent *event, sctp_association_hold((struct sctp_association *)asoc); skb = sctp_event2skb(event); skb->sk = asoc->base.sk; - event->asoc = (struct sctp_association *)asoc; + event->sndrcvinfo.sinfo_assoc_id = sctp_assoc2id(asoc); skb->destructor = sctp_stub_rfree; } /* A simple destructor to give up the reference to the association. */ static inline void sctp_ulpevent_release_owner(struct sctp_ulpevent *event) { - sctp_association_put(event->asoc); + sctp_association_put(event->sndrcvinfo.sinfo_assoc_id); } /* Do accounting for bytes received and hold a reference to the association @@ -880,7 +880,8 @@ static void sctp_ulpevent_release_data(struct sctp_ulpevent *event) */ skb = sctp_event2skb(event); - sctp_assoc_rwnd_increase(event->asoc, skb_headlen(skb)); + sctp_assoc_rwnd_increase(event->sndrcvinfo.sinfo_assoc_id, + skb_headlen(skb)); /* Don't forget the fragments. */ for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next) { -- cgit v1.2.3 From 911e72b5a6b5492938e6763798ca120353ea9355 Mon Sep 17 00:00:00 2001 From: Bart De Schuymer Date: Thu, 17 Jul 2003 09:42:48 -0700 Subject: [BRIDGE/EBTABLES]: Add stp packet matching. --- include/linux/netfilter_bridge/ebt_stp.h | 46 ++++++++ net/bridge/netfilter/Kconfig | 10 ++ net/bridge/netfilter/Makefile | 1 + net/bridge/netfilter/ebt_stp.c | 190 +++++++++++++++++++++++++++++++ 4 files changed, 247 insertions(+) create mode 100644 include/linux/netfilter_bridge/ebt_stp.h create mode 100644 net/bridge/netfilter/ebt_stp.c (limited to 'include') diff --git a/include/linux/netfilter_bridge/ebt_stp.h b/include/linux/netfilter_bridge/ebt_stp.h new file mode 100644 index 000000000000..e5fd67850f4d --- /dev/null +++ b/include/linux/netfilter_bridge/ebt_stp.h @@ -0,0 +1,46 @@ +#ifndef __LINUX_BRIDGE_EBT_STP_H +#define __LINUX_BRIDGE_EBT_STP_H + +#define EBT_STP_TYPE 0x0001 + +#define EBT_STP_FLAGS 0x0002 +#define EBT_STP_ROOTPRIO 0x0004 +#define EBT_STP_ROOTADDR 0x0008 +#define EBT_STP_ROOTCOST 0x0010 +#define EBT_STP_SENDERPRIO 0x0020 +#define EBT_STP_SENDERADDR 0x0040 +#define EBT_STP_PORT 0x0080 +#define EBT_STP_MSGAGE 0x0100 +#define EBT_STP_MAXAGE 0x0200 +#define EBT_STP_HELLOTIME 0x0400 +#define EBT_STP_FWDD 0x0800 + +#define EBT_STP_MASK 0x0fff +#define EBT_STP_CONFIG_MASK 0x0ffe + +#define EBT_STP_MATCH "stp" + +struct ebt_stp_config_info +{ + uint8_t flags; + uint16_t root_priol, root_priou; + char root_addr[6], root_addrmsk[6]; + uint32_t root_costl, root_costu; + uint16_t sender_priol, sender_priou; + char sender_addr[6], sender_addrmsk[6]; + uint16_t portl, portu; + uint16_t msg_agel, msg_ageu; + uint16_t max_agel, max_ageu; + uint16_t hello_timel, hello_timeu; + uint16_t forward_delayl, forward_delayu; +}; + +struct ebt_stp_info +{ + uint8_t type; + struct ebt_stp_config_info config; + uint16_t bitmask; + uint16_t invflags; +}; + +#endif diff --git a/net/bridge/netfilter/Kconfig b/net/bridge/netfilter/Kconfig index 4b6a1ed9367c..f04d9c9ee855 100644 --- a/net/bridge/netfilter/Kconfig +++ b/net/bridge/netfilter/Kconfig @@ -103,6 +103,16 @@ config BRIDGE_EBT_PKTTYPE If you want to compile it as a module, say M here and read . If unsure, say `N'. +config BRIDGE_EBT_STP + tristate "ebt: STP filter support" + depends on BRIDGE_NF_EBTABLES + help + This option adds the Spanning Tree Protocol match, which + allows STP header field filtering. + + If you want to compile it as a module, say M here and read + . If unsure, say `N'. + config BRIDGE_EBT_SNAT tristate "ebt: snat target support" depends on BRIDGE_NF_EBTABLES diff --git a/net/bridge/netfilter/Makefile b/net/bridge/netfilter/Makefile index 871252bdb903..8da3110178a3 100644 --- a/net/bridge/netfilter/Makefile +++ b/net/bridge/netfilter/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_BRIDGE_EBT_ARP) += ebt_arp.o obj-$(CONFIG_BRIDGE_EBT_VLAN) += ebt_vlan.o obj-$(CONFIG_BRIDGE_EBT_MARK) += ebt_mark_m.o obj-$(CONFIG_BRIDGE_EBT_PKTTYPE) += ebt_pkttype.o +obj-$(CONFIG_BRIDGE_EBT_STP) += ebt_stp.o obj-$(CONFIG_BRIDGE_EBT_LOG) += ebt_log.o obj-$(CONFIG_BRIDGE_EBT_SNAT) += ebt_snat.o obj-$(CONFIG_BRIDGE_EBT_DNAT) += ebt_dnat.o diff --git a/net/bridge/netfilter/ebt_stp.c b/net/bridge/netfilter/ebt_stp.c new file mode 100644 index 000000000000..8be478935ba8 --- /dev/null +++ b/net/bridge/netfilter/ebt_stp.c @@ -0,0 +1,190 @@ +/* + * ebt_stp + * + * Authors: + * Bart De Schuymer + * Stephen Hemminger + * + * July, 2003 + */ + +#include +#include +#include + +#define BPDU_TYPE_CONFIG 0 +#define BPDU_TYPE_TCN 0x80 + +struct stp_header { + uint8_t dsap; + uint8_t ssap; + uint8_t ctrl; + uint8_t pid; + uint8_t vers; + uint8_t type; +}; + +struct stp_config_pdu { + uint8_t flags; + uint8_t root[8]; + uint8_t root_cost[4]; + uint8_t sender[8]; + uint8_t port[2]; + uint8_t msg_age[2]; + uint8_t max_age[2]; + uint8_t hello_time[2]; + uint8_t forward_delay[2]; +}; + +#define NR16(p) (p[0] << 8 | p[1]) +#define NR32(p) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]) + +static int ebt_filter_config(struct ebt_stp_info *info, + struct stp_config_pdu *stpc) +{ + struct ebt_stp_config_info *c; + uint16_t v16; + uint32_t v32; + int verdict, i; + + c = &info->config; + if ((info->bitmask & EBT_STP_FLAGS) && + FWINV(c->flags != stpc->flags, EBT_STP_FLAGS)) + return EBT_NOMATCH; + if (info->bitmask & EBT_STP_ROOTPRIO) { + v16 = NR16(stpc->root); + if (FWINV(v16 < c->root_priol || + v16 > c->root_priou, EBT_STP_ROOTPRIO)) + return EBT_NOMATCH; + } + if (info->bitmask & EBT_STP_ROOTADDR) { + verdict = 0; + for (i = 0; i < 6; i++) + verdict |= (stpc->root[2+i] ^ c->root_addr[i]) & + c->root_addrmsk[i]; + if (FWINV(verdict != 0, EBT_STP_ROOTADDR)) + return EBT_NOMATCH; + } + if (info->bitmask & EBT_STP_ROOTCOST) { + v32 = NR32(stpc->root_cost); + if (FWINV(v32 < c->root_costl || + v32 > c->root_costu, EBT_STP_ROOTCOST)) + return EBT_NOMATCH; + } + if (info->bitmask & EBT_STP_SENDERPRIO) { + v16 = NR16(stpc->sender); + if (FWINV(v16 < c->sender_priol || + v16 > c->sender_priou, EBT_STP_SENDERPRIO)) + return EBT_NOMATCH; + } + if (info->bitmask & EBT_STP_SENDERADDR) { + verdict = 0; + for (i = 0; i < 6; i++) + verdict |= (stpc->sender[2+i] ^ c->sender_addr[i]) & + c->sender_addrmsk[i]; + if (FWINV(verdict != 0, EBT_STP_SENDERADDR)) + return EBT_NOMATCH; + } + if (info->bitmask & EBT_STP_PORT) { + v16 = NR16(stpc->port); + if (FWINV(v16 < c->portl || + v16 > c->portu, EBT_STP_PORT)) + return EBT_NOMATCH; + } + if (info->bitmask & EBT_STP_MSGAGE) { + v16 = NR16(stpc->msg_age); + if (FWINV(v16 < c->msg_agel || + v16 > c->msg_ageu, EBT_STP_MSGAGE)) + return EBT_NOMATCH; + } + if (info->bitmask & EBT_STP_MAXAGE) { + v16 = NR16(stpc->max_age); + if (FWINV(v16 < c->max_agel || + v16 > c->max_ageu, EBT_STP_MAXAGE)) + return EBT_NOMATCH; + } + if (info->bitmask & EBT_STP_HELLOTIME) { + v16 = NR16(stpc->hello_time); + if (FWINV(v16 < c->hello_timel || + v16 > c->hello_timeu, EBT_STP_HELLOTIME)) + return EBT_NOMATCH; + } + if (info->bitmask & EBT_STP_FWDD) { + v16 = NR16(stpc->forward_delay); + if (FWINV(v16 < c->forward_delayl || + v16 > c->forward_delayu, EBT_STP_FWDD)) + return EBT_NOMATCH; + } + return EBT_MATCH; +} + +static int ebt_filter_stp(const struct sk_buff *skb, const struct net_device *in, + const struct net_device *out, const void *data, unsigned int datalen) +{ + struct ebt_stp_info *info = (struct ebt_stp_info *)data; + struct stp_header stph; + uint8_t header[6] = {0x42, 0x42, 0x03, 0x00, 0x00, 0x00}; + if (skb_copy_bits(skb, 0, &stph, sizeof(stph))) + return EBT_NOMATCH; + + /* The stp code only considers these */ + if (memcmp(&stph, header, sizeof(header))) + return EBT_NOMATCH; + + if (info->bitmask & EBT_STP_TYPE + && FWINV(info->type != stph.type, EBT_STP_TYPE)) + return EBT_NOMATCH; + + if (stph.type == BPDU_TYPE_CONFIG && + info->bitmask & EBT_STP_CONFIG_MASK) { + struct stp_config_pdu stpc; + + if (skb_copy_bits(skb, sizeof(stph), &stpc, sizeof(stpc))) + return EBT_NOMATCH; + return ebt_filter_config(info, &stpc); + } + return EBT_MATCH; +} + +static int ebt_stp_check(const char *tablename, unsigned int hookmask, + const struct ebt_entry *e, void *data, unsigned int datalen) +{ + struct ebt_stp_info *info = (struct ebt_stp_info *)data; + int len = sizeof(struct ebt_stp_info); + uint8_t bridge_ula[6] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }; + uint8_t msk[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + + if (info->bitmask & ~EBT_STP_MASK || info->invflags & ~EBT_STP_MASK || + !(info->bitmask & EBT_STP_MASK)) + return -EINVAL; + if (datalen != len) + return -EINVAL; + /* Make sure the match only receives stp frames */ + if (memcmp(e->destmac, bridge_ula, ETH_ALEN) || + memcmp(e->destmsk, msk, ETH_ALEN) || !(e->bitmask & EBT_DESTMAC)) + return -EINVAL; + + return 0; +} + +static struct ebt_match filter_stp = +{ + .name = EBT_STP_MATCH, + .match = ebt_filter_stp, + .check = ebt_stp_check, + .me = THIS_MODULE, +}; + +static int __init init(void) +{ + return ebt_register_match(&filter_stp); +} + +static void __exit fini(void) +{ + ebt_unregister_match(&filter_stp); +} + +module_init(init); +module_exit(fini); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 9bb688143058b9eae52d2f77219dd4fdd612ccb0 Mon Sep 17 00:00:00 2001 From: Sridhar Samudrala Date: Fri, 18 Jul 2003 00:54:17 -0700 Subject: [SCTP] Support for IPV6_V6ONLY socket option. (Ardelle.fan) --- include/net/sctp/sctp.h | 1 + net/sctp/ipv6.c | 10 +++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index 68f550019491..506fd2cb1305 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -588,6 +588,7 @@ struct sctp6_sock { #endif /* CONFIG_IPV6 */ #define sctp_sk(__sk) (&((struct sctp_sock *)__sk)->sctp) +#define sctp_opt2sk(__sp) &container_of(__sp, struct sctp_sock, sctp)->sk /* Is a socket of this style? */ #define sctp_style(sk, style) __sctp_style((sk), (SCTP_SOCKET_##style)) diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index dd017dd7132f..3bce456b895f 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -475,6 +475,8 @@ static int sctp_v6_available(union sctp_addr *addr, struct sctp_opt *sp) if (type == IPV6_ADDR_MAPPED) { if (sp && !sp->v4mapped) return 0; + if (sp && ipv6_only_sock(sctp_opt2sk(sp))) + return 0; sctp_v6_map_v4(addr); return sctp_get_af_specific(AF_INET)->available(addr, sp); } @@ -502,6 +504,8 @@ static int sctp_v6_addr_valid(union sctp_addr *addr, struct sctp_opt *sp) */ if (!sp || !sp->v4mapped) return 0; + if (sp && ipv6_only_sock(sctp_opt2sk(sp))) + return 0; sctp_v6_map_v4(addr); return sctp_get_af_specific(AF_INET)->addr_valid(addr, sp); } @@ -731,7 +735,7 @@ static int sctp_inet6_af_supported(sa_family_t family, struct sctp_opt *sp) return 1; /* v4-mapped-v6 addresses */ case AF_INET: - if (sp->v4mapped) + if (!__ipv6_only_sock(sctp_opt2sk(sp)) && sp->v4mapped) return 1; default: return 0; @@ -776,7 +780,7 @@ static int sctp_inet6_bind_verify(struct sctp_opt *opt, union sctp_addr *addr) else { struct sock *sk; int type = ipv6_addr_type(&addr->v6.sin6_addr); - sk = &container_of(opt, struct sctp6_sock, sctp)->sk; + sk = sctp_opt2sk(opt); if (type & IPV6_ADDR_LINKLOCAL) { /* Note: Behavior similar to af_inet6.c: * 1) Overrides previous bound_dev_if @@ -806,7 +810,7 @@ static int sctp_inet6_send_verify(struct sctp_opt *opt, union sctp_addr *addr) else { struct sock *sk; int type = ipv6_addr_type(&addr->v6.sin6_addr); - sk = &container_of(opt, struct sctp6_sock, sctp)->sk; + sk = sctp_opt2sk(opt); if (type & IPV6_ADDR_LINKLOCAL) { /* Note: Behavior similar to af_inet6.c: * 1) Overrides previous bound_dev_if -- cgit v1.2.3 From 0cc526e0e801dd0a372641bfbefb20f74e881cb9 Mon Sep 17 00:00:00 2001 From: Alexey Kuznetsov Date: Fri, 18 Jul 2003 09:44:04 -0700 Subject: [IPV6]: Fix anycast usage. - Recognition of reserved anycasts is removed from ipv6_addr_type() Flag IPV6_ADDR_ANYCAST is removed as well. - Some meaningless noop code checking for anycast which are not going to happen is removed from ndisc.c - ipv6_unicast_destination() replaces suboptimal ipv6_chk_acast_addr() in data paths --- include/net/ip6_route.h | 10 +++++++++- include/net/ipv6.h | 3 +-- net/ipv6/addrconf.c | 13 +++---------- net/ipv6/anycast.c | 25 ++++++++++++++----------- net/ipv6/icmp.c | 3 +-- net/ipv6/ndisc.c | 6 ++---- net/ipv6/route.c | 4 +++- net/ipv6/tcp_ipv6.c | 5 ++--- 8 files changed, 35 insertions(+), 34 deletions(-) (limited to 'include') diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index c421186227f7..8654632ff46f 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -45,7 +45,8 @@ extern int ip6_del_rt(struct rt6_info *, void *rtattr); extern int ip6_rt_addr_add(struct in6_addr *addr, - struct net_device *dev); + struct net_device *dev, + int anycast); extern int ip6_rt_addr_del(struct in6_addr *addr, struct net_device *dev); @@ -118,5 +119,12 @@ static inline void ip6_dst_store(struct sock *sk, struct dst_entry *dst, write_unlock(&sk->sk_dst_lock); } +static inline int ipv6_unicast_destination(struct sk_buff *skb) +{ + struct rt6_info *rt = (struct rt6_info *) skb->dst; + + return rt->rt6i_flags & RTF_LOCAL; +} + #endif #endif diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 5c6546accda9..8aeb974d8592 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -51,7 +51,7 @@ /* * Addr type * - * type - unicast | multicast | anycast + * type - unicast | multicast * scope - local | site | global * v4 - compat * v4mapped @@ -63,7 +63,6 @@ #define IPV6_ADDR_UNICAST 0x0001U #define IPV6_ADDR_MULTICAST 0x0002U -#define IPV6_ADDR_ANYCAST 0x0004U #define IPV6_ADDR_LOOPBACK 0x0010U #define IPV6_ADDR_LINKLOCAL 0x0020U diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index b0c186efccd3..649df9f76068 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -209,15 +209,8 @@ int ipv6_addr_type(const struct in6_addr *addr) }; return type; } - /* check for reserved anycast addresses */ - - if ((st & htonl(0xE0000000)) && - ((addr->s6_addr32[2] == htonl(0xFDFFFFFF) && - (addr->s6_addr32[3] | htonl(0x7F)) == (u32)~0) || - (addr->s6_addr32[2] == 0 && addr->s6_addr32[3] == 0))) - type = IPV6_ADDR_ANYCAST; - else - type = IPV6_ADDR_UNICAST; + + type = IPV6_ADDR_UNICAST; /* Consider all addresses with the first three bits different of 000 and 111 as finished. @@ -2552,7 +2545,7 @@ static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) switch (event) { case RTM_NEWADDR: - ip6_rt_addr_add(&ifp->addr, ifp->idev->dev); + ip6_rt_addr_add(&ifp->addr, ifp->idev->dev, 0); break; case RTM_DELADDR: addrconf_leave_solict(ifp->idev->dev, &ifp->addr); diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c index 1dc5b9da2e2b..f36fee99a37c 100644 --- a/net/ipv6/anycast.c +++ b/net/ipv6/anycast.c @@ -96,7 +96,6 @@ ip6_onlink(struct in6_addr *addr, struct net_device *dev) return onlink; } - /* * socket join an anycast group */ @@ -110,8 +109,12 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, struct in6_addr *addr) int ishost = !ipv6_devconf.forwarding; int err = 0; + if (!capable(CAP_NET_ADMIN)) + return -EPERM; if (ipv6_addr_type(addr) & IPV6_ADDR_MULTICAST) return -EINVAL; + if (ipv6_chk_addr(addr, NULL)) + return -EINVAL; pac = sock_kmalloc(sk, sizeof(struct ipv6_ac_socklist), GFP_KERNEL); if (pac == NULL) @@ -161,21 +164,12 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, struct in6_addr *addr) * For hosts, allow link-local or matching prefix anycasts. * This obviates the need for propagating anycast routes while * still allowing some non-router anycast participation. - * - * allow anyone to join anycasts that don't require a special route - * and can't be spoofs of unicast addresses (reserved anycast only) */ if (!ip6_onlink(addr, dev)) { if (ishost) err = -EADDRNOTAVAIL; - else if (!capable(CAP_NET_ADMIN)) - err = -EPERM; if (err) goto out_dev_put; - } else if (!(ipv6_addr_type(addr) & IPV6_ADDR_ANYCAST) && - !capable(CAP_NET_ADMIN)) { - err = -EPERM; - goto out_dev_put; } err = ipv6_dev_ac_inc(dev, addr); @@ -266,6 +260,13 @@ void ipv6_sock_ac_close(struct sock *sk) dev_put(dev); } +#if 0 +/* The function is not used, which is funny. Apparently, author + * supposed to use it to filter out datagrams inside udp/raw but forgot. + * + * It is OK, anycasts are not special comparing to delivery to unicasts. + */ + int inet6_ac_check(struct sock *sk, struct in6_addr *addr, int ifindex) { struct ipv6_ac_socklist *pac; @@ -286,6 +287,8 @@ int inet6_ac_check(struct sock *sk, struct in6_addr *addr, int ifindex) return found; } +#endif + static void aca_put(struct ifacaddr6 *ac) { if (atomic_dec_and_test(&ac->aca_refcnt)) { @@ -347,7 +350,7 @@ int ipv6_dev_ac_inc(struct net_device *dev, struct in6_addr *addr) idev->ac_list = aca; write_unlock_bh(&idev->lock); - ip6_rt_addr_add(&aca->aca_addr, dev); + ip6_rt_addr_add(&aca->aca_addr, dev, 1); addrconf_join_solict(dev, &aca->aca_addr); diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 5cfc70535e35..727b681325aa 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -415,8 +415,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb) saddr = &skb->nh.ipv6h->daddr; - if (ipv6_addr_type(saddr) & IPV6_ADDR_MULTICAST || - ipv6_chk_acast_addr(0, saddr)) + if (!ipv6_unicast_destination(skb)) saddr = NULL; memcpy(&tmp_hdr, icmph, sizeof(tmp_hdr)); diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 75a9eeaa05d0..95772c3e915a 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -785,8 +785,7 @@ static void ndisc_recv_ns(struct sk_buff *skb) ipv6_addr_all_nodes(&maddr); ndisc_send_na(dev, NULL, &maddr, &ifp->addr, ifp->idev->cnf.forwarding, 0, - ipv6_addr_type(&ifp->addr)&IPV6_ADDR_ANYCAST ? 0 : 1, - 1); + 1, 1); in6_ifa_put(ifp); return; } @@ -809,8 +808,7 @@ static void ndisc_recv_ns(struct sk_buff *skb) if (neigh || !dev->hard_header) { ndisc_send_na(dev, neigh, saddr, &ifp->addr, ifp->idev->cnf.forwarding, 1, - ipv6_addr_type(&ifp->addr)&IPV6_ADDR_ANYCAST ? 0 : 1, - 1); + 1, 1); if (neigh) neigh_release(neigh); } diff --git a/net/ipv6/route.c b/net/ipv6/route.c index ac76e702faa2..69d7791712f8 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1261,7 +1261,7 @@ int ip6_pkt_discard(struct sk_buff *skb) * Add address */ -int ip6_rt_addr_add(struct in6_addr *addr, struct net_device *dev) +int ip6_rt_addr_add(struct in6_addr *addr, struct net_device *dev, int anycast) { struct rt6_info *rt = ip6_dst_alloc(); @@ -1280,6 +1280,8 @@ int ip6_rt_addr_add(struct in6_addr *addr, struct net_device *dev) rt->u.dst.obsolete = -1; rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP; + if (!anycast) + rt->rt6i_flags |= RTF_LOCAL; rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_gateway); if (rt->rt6i_nexthop == NULL) { dst_free((struct dst_entry *) rt); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 21b165ec5339..e5cd4c372577 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -971,7 +971,7 @@ static void tcp_v6_send_reset(struct sk_buff *skb) if (th->rst) return; - if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr)) + if (!ipv6_unicast_destination(skb)) return; /* @@ -1175,8 +1175,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) if (skb->protocol == htons(ETH_P_IP)) return tcp_v4_conn_request(sk, skb); - /* FIXME: do the same check for anycast */ - if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr)) + if (!ipv6_unicast_destination(skb)) goto drop; /* -- cgit v1.2.3 From 6d6fc05f9210a750bc03793f6d1de27b347e5c01 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Sat, 19 Jul 2003 04:37:41 -0400 Subject: [PATCH] add ethtool TSO get/set * Add TSO get/set command to ethtool interface. Applies to both 2.4/2.5. Ethtool application patch sent under separate cover. --- include/linux/ethtool.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index 55a3278ae951..f82118e5a618 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -281,6 +281,8 @@ struct ethtool_stats { #define ETHTOOL_GSTRINGS 0x0000001b /* get specified string set */ #define ETHTOOL_PHYS_ID 0x0000001c /* identify the NIC */ #define ETHTOOL_GSTATS 0x0000001d /* get NIC-specific statistics */ +#define ETHTOOL_GTSO 0x0000001e /* Get TSO enable (ethtool_value) */ +#define ETHTOOL_STSO 0x0000001f /* Set TSO enable (ethtool_value) */ /* compatibility with older code */ #define SPARC_ETH_GSET ETHTOOL_GSET -- cgit v1.2.3 From c46236ee2409d4bb3b55a5f794fde46f14ed6481 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 20 Jul 2003 14:50:02 -0700 Subject: [IPSEC]: Make reqids 32-bits. --- include/linux/pfkeyv2.h | 4 +++- include/linux/xfrm.h | 4 ++-- include/net/xfrm.h | 8 ++++---- net/ipv4/xfrm4_state.c | 2 +- net/ipv6/xfrm6_state.c | 2 +- net/key/af_key.c | 11 ++++++----- net/xfrm/xfrm_state.c | 2 +- 7 files changed, 18 insertions(+), 15 deletions(-) (limited to 'include') diff --git a/include/linux/pfkeyv2.h b/include/linux/pfkeyv2.h index cf3a2f162239..fbfa0f52fdc9 100644 --- a/include/linux/pfkeyv2.h +++ b/include/linux/pfkeyv2.h @@ -190,7 +190,9 @@ struct sadb_x_ipsecrequest { uint16_t sadb_x_ipsecrequest_proto; uint8_t sadb_x_ipsecrequest_mode; uint8_t sadb_x_ipsecrequest_level; - uint16_t sadb_x_ipsecrequest_reqid; + uint16_t sadb_x_ipsecrequest_reserved1; + uint32_t sadb_x_ipsecrequest_reqid; + uint32_t sadb_x_ipsecrequest_reserved2; } __attribute__((packed)); /* sizeof(struct sadb_x_ipsecrequest) == 16 */ diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h index d660c5f97c58..64ea125f3562 100644 --- a/include/linux/xfrm.h +++ b/include/linux/xfrm.h @@ -126,7 +126,7 @@ enum struct xfrm_user_tmpl { struct xfrm_id id; xfrm_address_t saddr; - __u16 reqid; + __u32 reqid; __u8 mode; __u8 share; __u8 optional; @@ -162,8 +162,8 @@ struct xfrm_usersa_info { struct xfrm_lifetime_cur curlft; struct xfrm_stats stats; __u32 seq; + __u32 reqid; __u16 family; - __u16 reqid; __u8 mode; /* 0=transport,1=tunnel */ __u8 replay_window; }; diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 4cb71a1e0313..e4618023716d 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -104,10 +104,10 @@ struct xfrm_state /* Parameters of this state. */ struct { + u32 reqid; u8 mode; u8 replay_window; u8 aalgo, ealgo, calgo; - u16 reqid; u16 family; xfrm_address_t saddr; int header_len; @@ -193,7 +193,7 @@ struct xfrm_state_afinfo { struct xfrm_tmpl *tmpl, xfrm_address_t *daddr, xfrm_address_t *saddr); struct xfrm_state *(*state_lookup)(xfrm_address_t *daddr, u32 spi, u8 proto); - struct xfrm_state *(*find_acq)(u8 mode, u16 reqid, u8 proto, + struct xfrm_state *(*find_acq)(u8 mode, u32 reqid, u8 proto, xfrm_address_t *daddr, xfrm_address_t *saddr, int create); }; @@ -244,7 +244,7 @@ struct xfrm_tmpl /* Source address of tunnel. Ignored, if it is not a tunnel. */ xfrm_address_t saddr; - __u16 reqid; + __u32 reqid; /* Mode: transport/tunnel */ __u8 mode; @@ -801,7 +801,7 @@ struct xfrm_policy *xfrm_policy_byid(int dir, u32 id, int delete); void xfrm_policy_flush(void); u32 xfrm_get_acqseq(void); void xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi); -struct xfrm_state * xfrm_find_acq(u8 mode, u16 reqid, u8 proto, +struct xfrm_state * xfrm_find_acq(u8 mode, u32 reqid, u8 proto, xfrm_address_t *daddr, xfrm_address_t *saddr, int create, unsigned short family); extern void xfrm_policy_flush(void); diff --git a/net/ipv4/xfrm4_state.c b/net/ipv4/xfrm4_state.c index 5d51b9daa0d5..cd78fa0d6b88 100644 --- a/net/ipv4/xfrm4_state.c +++ b/net/ipv4/xfrm4_state.c @@ -58,7 +58,7 @@ __xfrm4_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto) } static struct xfrm_state * -__xfrm4_find_acq(u8 mode, u16 reqid, u8 proto, +__xfrm4_find_acq(u8 mode, u32 reqid, u8 proto, xfrm_address_t *daddr, xfrm_address_t *saddr, int create) { diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c index cd1ef86b57f5..c00c8ef25d83 100644 --- a/net/ipv6/xfrm6_state.c +++ b/net/ipv6/xfrm6_state.c @@ -65,7 +65,7 @@ __xfrm6_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto) } static struct xfrm_state * -__xfrm6_find_acq(u8 mode, u16 reqid, u8 proto, +__xfrm6_find_acq(u8 mode, u32 reqid, u8 proto, xfrm_address_t *daddr, xfrm_address_t *saddr, int create) { diff --git a/net/key/af_key.c b/net/key/af_key.c index a6e913e5f11d..f481a136dad4 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -1099,7 +1099,7 @@ static int pfkey_getspi(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h struct sadb_msg *out_hdr; struct xfrm_state *x = NULL; u8 mode; - u16 reqid; + u32 reqid; u8 proto; unsigned short family; xfrm_address_t *xsaddr = NULL, *xdaddr = NULL; @@ -1496,7 +1496,7 @@ static int pfkey_promisc(struct sock *sk, struct sk_buff *skb, struct sadb_msg * static int check_reqid(struct xfrm_policy *xp, int dir, int count, void *ptr) { int i; - u16 reqid = *(u16*)ptr; + u32 reqid = *(u32*)ptr; for (i=0; ixfrm_nr; i++) { if (xp->xfrm_vec[i].reqid == reqid) @@ -1505,10 +1505,10 @@ static int check_reqid(struct xfrm_policy *xp, int dir, int count, void *ptr) return 0; } -static u16 gen_reqid(void) +static u32 gen_reqid(void) { - u16 start; - static u16 reqid = IPSEC_MANUAL_REQID_MAX; + u32 start; + static u32 reqid = IPSEC_MANUAL_REQID_MAX; start = reqid; do { @@ -1771,6 +1771,7 @@ static void pfkey_xfrm_policy2msg(struct sk_buff *skb, struct xfrm_policy *xp, i size -= 2*socklen; rq = (void*)skb_put(skb, req_size); pol->sadb_x_policy_len += req_size/8; + memset(rq, 0, sizeof(*rq)); rq->sadb_x_ipsecrequest_len = req_size; rq->sadb_x_ipsecrequest_proto = t->id.proto; rq->sadb_x_ipsecrequest_mode = t->mode+1; diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index aa6bb0eb2e66..86bd26e1cb19 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -554,7 +554,7 @@ xfrm_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto, } struct xfrm_state * -xfrm_find_acq(u8 mode, u16 reqid, u8 proto, +xfrm_find_acq(u8 mode, u32 reqid, u8 proto, xfrm_address_t *daddr, xfrm_address_t *saddr, int create, unsigned short family) { -- cgit v1.2.3 From 03eb6d115a81b00d3bd01ed2fc2618dfaed416b7 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 20 Jul 2003 15:31:16 -0700 Subject: [ARCNET]: Fix module refcounting. --- drivers/net/arcnet/arc-rimi.c | 12 +----------- drivers/net/arcnet/arcnet.c | 18 +++++++++++++----- drivers/net/arcnet/com20020-isa.c | 10 +--------- drivers/net/arcnet/com20020-pci.c | 10 +--------- drivers/net/arcnet/com20020.c | 17 +++++------------ drivers/net/arcnet/com90io.c | 11 +---------- drivers/net/arcnet/com90xx.c | 13 +------------ include/linux/arcdevice.h | 6 +++--- 8 files changed, 26 insertions(+), 71 deletions(-) (limited to 'include') diff --git a/drivers/net/arcnet/arc-rimi.c b/drivers/net/arcnet/arc-rimi.c index 3ff5688314d8..db091f95f553 100644 --- a/drivers/net/arcnet/arc-rimi.c +++ b/drivers/net/arcnet/arc-rimi.c @@ -47,7 +47,6 @@ static void arcrimi_command(struct net_device *dev, int command); static int arcrimi_status(struct net_device *dev); static void arcrimi_setmask(struct net_device *dev, int mask); static int arcrimi_reset(struct net_device *dev, int really_reset); -static void arcrimi_openclose(struct net_device *dev, bool open); static void arcrimi_copy_to_card(struct net_device *dev, int bufnum, int offset, void *buf, int count); static void arcrimi_copy_from_card(struct net_device *dev, int bufnum, int offset, @@ -179,7 +178,7 @@ static int __init arcrimi_found(struct net_device *dev) lp->hw.status = arcrimi_status; lp->hw.intmask = arcrimi_setmask; lp->hw.reset = arcrimi_reset; - lp->hw.open_close = arcrimi_openclose; + lp->hw.owner = THIS_MODULE; lp->hw.copy_to_card = arcrimi_copy_to_card; lp->hw.copy_from_card = arcrimi_copy_from_card; lp->mem_start = ioremap(dev->mem_start, dev->mem_end - dev->mem_start + 1); @@ -254,15 +253,6 @@ static int arcrimi_reset(struct net_device *dev, int really_reset) return 0; } - -static void arcrimi_openclose(struct net_device *dev, int open) -{ - if (open) - MOD_INC_USE_COUNT; - else - MOD_DEC_USE_COUNT; -} - static void arcrimi_setmask(struct net_device *dev, int mask) { struct arcnet_local *lp = (struct arcnet_local *) dev->priv; diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c index 59857e6ce402..992f4cc8cf53 100644 --- a/drivers/net/arcnet/arcnet.c +++ b/drivers/net/arcnet/arcnet.c @@ -343,7 +343,10 @@ void arcdev_setup(struct net_device *dev) static int arcnet_open(struct net_device *dev) { struct arcnet_local *lp = (struct arcnet_local *) dev->priv; - int count, newmtu; + int count, newmtu, error; + + if (!try_module_get(lp->hw.owner)) + return -ENODEV; BUGLVL(D_PROTO) { int count; @@ -360,8 +363,9 @@ static int arcnet_open(struct net_device *dev) /* try to put the card in a defined state - if it fails the first * time, actually reset it. */ + error = -ENODEV; if (ARCRESET(0) && ARCRESET(1)) - return -ENODEV; + goto out_module_put; newmtu = choose_mtu(); if (newmtu < dev->mtu) @@ -391,7 +395,7 @@ static int arcnet_open(struct net_device *dev) lp->rfc1201.sequence = 1; /* bring up the hardware driver */ - ARCOPEN(1); + lp->hw.open(dev); if (dev->dev_addr[0] == 0) BUGMSG(D_NORMAL, "WARNING! Station address 00 is reserved " @@ -415,6 +419,10 @@ static int arcnet_open(struct net_device *dev) netif_start_queue(dev); return 0; + + out_module_put: + module_put(lp->hw.owner); + return error; } @@ -432,8 +440,8 @@ static int arcnet_close(struct net_device *dev) mdelay(1); /* shut down the card */ - ARCOPEN(0); - + lp->hw.close(dev); + module_put(lp->hw.owner); return 0; } diff --git a/drivers/net/arcnet/com20020-isa.c b/drivers/net/arcnet/com20020-isa.c index 5e6e3f54c7f2..8cc69625cc10 100644 --- a/drivers/net/arcnet/com20020-isa.c +++ b/drivers/net/arcnet/com20020-isa.c @@ -131,14 +131,6 @@ MODULE_PARM(clockp, "i"); MODULE_PARM(clockm, "i"); MODULE_LICENSE("GPL"); -static void com20020isa_open_close(struct net_device *dev, bool open) -{ - if (open) - MOD_INC_USE_COUNT; - else - MOD_DEC_USE_COUNT; -} - int init_module(void) { struct net_device *dev; @@ -160,7 +152,7 @@ int init_module(void) lp->clockp = clockp & 7; lp->clockm = clockm & 3; lp->timeout = timeout & 3; - lp->hw.open_close_ll = com20020isa_open_close; + lp->owner = THIS_MODULE; dev->base_addr = io; dev->irq = irq; diff --git a/drivers/net/arcnet/com20020-pci.c b/drivers/net/arcnet/com20020-pci.c index aa0a3626194c..f0c41c94ec05 100644 --- a/drivers/net/arcnet/com20020-pci.c +++ b/drivers/net/arcnet/com20020-pci.c @@ -60,14 +60,6 @@ MODULE_PARM(clockp, "i"); MODULE_PARM(clockm, "i"); MODULE_LICENSE("GPL"); -static void com20020pci_open_close(struct net_device *dev, bool open) -{ - if (open) - MOD_INC_USE_COUNT; - else - MOD_DEC_USE_COUNT; -} - static int __devinit com20020pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct net_device *dev; @@ -111,7 +103,7 @@ static int __devinit com20020pci_probe(struct pci_dev *pdev, const struct pci_de lp->clockp = clockp & 7; lp->clockm = clockm & 3; lp->timeout = timeout; - lp->hw.open_close_ll = com20020pci_open_close; + lp->hw.owner = THIS_MODULE; if (check_region(ioaddr, ARCNET_TOTAL_SIZE)) { BUGMSG(D_INIT, "IO region %xh-%xh already allocated.\n", diff --git a/drivers/net/arcnet/com20020.c b/drivers/net/arcnet/com20020.c index c37a1f6c9456..650bec307c7c 100644 --- a/drivers/net/arcnet/com20020.c +++ b/drivers/net/arcnet/com20020.c @@ -50,13 +50,12 @@ static void com20020_command(struct net_device *dev, int command); static int com20020_status(struct net_device *dev); static void com20020_setmask(struct net_device *dev, int mask); static int com20020_reset(struct net_device *dev, int really_reset); -static void com20020_openclose(struct net_device *dev, bool open); static void com20020_copy_to_card(struct net_device *dev, int bufnum, int offset, void *buf, int count); static void com20020_copy_from_card(struct net_device *dev, int bufnum, int offset, void *buf, int count); static void com20020_set_mc_list(struct net_device *dev); - +static void com20020_close(struct net_device *, bool); static void com20020_copy_from_card(struct net_device *dev, int bufnum, int offset, void *buf, int count) @@ -162,13 +161,14 @@ int __devinit com20020_found(struct net_device *dev, int shared) lp = (struct arcnet_local *) dev->priv; + lp->hw.owner = THIS_MODULE; lp->hw.command = com20020_command; lp->hw.status = com20020_status; lp->hw.intmask = com20020_setmask; lp->hw.reset = com20020_reset; - lp->hw.open_close = com20020_openclose; lp->hw.copy_to_card = com20020_copy_to_card; lp->hw.copy_from_card = com20020_copy_from_card; + lp->hw.close = com20020_close; dev->set_multicast_list = com20020_set_mc_list; @@ -298,25 +298,18 @@ static int com20020_status(struct net_device *dev) return ASTATUS(); } - -static void com20020_openclose(struct net_device *dev, bool open) +static void com20020_close(struct net_device *dev, bool open) { struct arcnet_local *lp = (struct arcnet_local *) dev->priv; int ioaddr = dev->base_addr; - if (open) { - MOD_INC_USE_COUNT; - } - else { + if (!open) { /* disable transmitter */ lp->config &= ~TXENcfg; SETCONF; - MOD_DEC_USE_COUNT; } - lp->hw.open_close_ll(dev, open); } - /* Set or clear the multicast filter for this adaptor. * num_addrs == -1 Promiscuous mode, receive all packets * num_addrs == 0 Normal mode, clear multicast list diff --git a/drivers/net/arcnet/com90io.c b/drivers/net/arcnet/com90io.c index 4ff5287daf9b..1d18fc62f7a7 100644 --- a/drivers/net/arcnet/com90io.c +++ b/drivers/net/arcnet/com90io.c @@ -47,7 +47,6 @@ static void com90io_command(struct net_device *dev, int command); static int com90io_status(struct net_device *dev); static void com90io_setmask(struct net_device *dev, int mask); static int com90io_reset(struct net_device *dev, int really_reset); -static void com90io_openclose(struct net_device *dev, bool open); static void com90io_copy_to_card(struct net_device *dev, int bufnum, int offset, void *buf, int count); static void com90io_copy_from_card(struct net_device *dev, int bufnum, int offset, @@ -257,7 +256,7 @@ static int __init com90io_found(struct net_device *dev) lp->hw.status = com90io_status; lp->hw.intmask = com90io_setmask; lp->hw.reset = com90io_reset; - lp->hw.open_close = com90io_openclose; + lp->hw.owner = THIS_MODULE; lp->hw.copy_to_card = com90io_copy_to_card; lp->hw.copy_from_card = com90io_copy_from_card; @@ -344,14 +343,6 @@ static void com90io_setmask(struct net_device *dev, int mask) AINTMASK(mask); } -static void com90io_openclose(struct net_device *dev, int open) -{ - if (open) - MOD_INC_USE_COUNT; - else - MOD_DEC_USE_COUNT; -} - static void com90io_copy_to_card(struct net_device *dev, int bufnum, int offset, void *buf, int count) { diff --git a/drivers/net/arcnet/com90xx.c b/drivers/net/arcnet/com90xx.c index 8c50eccf1540..f87660123972 100644 --- a/drivers/net/arcnet/com90xx.c +++ b/drivers/net/arcnet/com90xx.c @@ -58,7 +58,6 @@ static void com90xx_command(struct net_device *dev, int command); static int com90xx_status(struct net_device *dev); static void com90xx_setmask(struct net_device *dev, int mask); static int com90xx_reset(struct net_device *dev, int really_reset); -static void com90xx_openclose(struct net_device *dev, bool open); static void com90xx_copy_to_card(struct net_device *dev, int bufnum, int offset, void *buf, int count); static void com90xx_copy_from_card(struct net_device *dev, int bufnum, int offset, @@ -450,7 +449,7 @@ static int __init com90xx_found(struct net_device *dev0, int ioaddr, int airq, lp->hw.status = com90xx_status; lp->hw.intmask = com90xx_setmask; lp->hw.reset = com90xx_reset; - lp->hw.open_close = com90xx_openclose; + lp->hw.owner = THIS_MODULE; lp->hw.copy_to_card = com90xx_copy_to_card; lp->hw.copy_from_card = com90xx_copy_from_card; lp->mem_start = ioremap(dev->mem_start, dev->mem_end - dev->mem_start + 1); @@ -570,16 +569,6 @@ int com90xx_reset(struct net_device *dev, int really_reset) return 0; } - -static void com90xx_openclose(struct net_device *dev, bool open) -{ - if (open) - MOD_INC_USE_COUNT; - else - MOD_DEC_USE_COUNT; -} - - static void com90xx_copy_to_card(struct net_device *dev, int bufnum, int offset, void *buf, int count) { diff --git a/include/linux/arcdevice.h b/include/linux/arcdevice.h index a8672f0ddeb6..66c7495e1834 100644 --- a/include/linux/arcdevice.h +++ b/include/linux/arcdevice.h @@ -291,12 +291,13 @@ struct arcnet_local { /* hardware-specific functions */ struct { + struct module *owner; void (*command) (struct net_device * dev, int cmd); int (*status) (struct net_device * dev); void (*intmask) (struct net_device * dev, int mask); bool (*reset) (struct net_device * dev, bool really_reset); - void (*open_close) (struct net_device * dev, bool open); - void (*open_close_ll) (struct net_device * dev, bool open); + void (*open) (struct net_device * dev); + void (*close) (struct net_device * dev); void (*copy_to_card) (struct net_device * dev, int bufnum, int offset, void *buf, int count); @@ -312,7 +313,6 @@ struct arcnet_local { #define ACOMMAND(x) (lp->hw.command(dev, (x))) #define ASTATUS() (lp->hw.status(dev)) #define AINTMASK(x) (lp->hw.intmask(dev, (x))) -#define ARCOPEN(x) (lp->hw.open_close(dev, (x))) -- cgit v1.2.3 From 4ded327245dc3fa0db79f7576e7b61b27044b28f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 21 Jul 2003 09:44:35 -0700 Subject: [ALPHA] Add asm/sections.h. --- include/asm-alpha/sections.h | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 include/asm-alpha/sections.h (limited to 'include') diff --git a/include/asm-alpha/sections.h b/include/asm-alpha/sections.h new file mode 100644 index 000000000000..43b40edd6e44 --- /dev/null +++ b/include/asm-alpha/sections.h @@ -0,0 +1,7 @@ +#ifndef _ALPHA_SECTIONS_H +#define _ALPHA_SECTIONS_H + +/* nothing to see, move along */ +#include + +#endif -- cgit v1.2.3 From 8184c812b4a9de8dd98d7fd85c6a35df82c52624 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 21 Jul 2003 09:46:09 -0700 Subject: [ALPHA] Add atomic64_t. --- include/asm-alpha/atomic.h | 85 ++++++++++++++++++++++++++++++++++++++++++++-- include/asm-alpha/local.h | 40 ++++++++++++++++++++++ 2 files changed, 123 insertions(+), 2 deletions(-) create mode 100644 include/asm-alpha/local.h (limited to 'include') diff --git a/include/asm-alpha/atomic.h b/include/asm-alpha/atomic.h index 349cd5613f56..cd253c8c6c7b 100644 --- a/include/asm-alpha/atomic.h +++ b/include/asm-alpha/atomic.h @@ -16,11 +16,16 @@ * the user gave us, not some alias that contains the same information. */ typedef struct { volatile int counter; } atomic_t; +typedef struct { volatile long counter; } atomic64_t; -#define ATOMIC_INIT(i) ( (atomic_t) { (i) } ) +#define ATOMIC_INIT(i) ( (atomic_t) { (i) } ) +#define ATOMIC64_INIT(i) ( (atomic64_t) { (i) } ) + +#define atomic_read(v) ((v)->counter + 0) +#define atomic64_read(v) ((v)->counter + 0) -#define atomic_read(v) ((v)->counter) #define atomic_set(v,i) ((v)->counter = (i)) +#define atomic64_set(v,i) ((v)->counter = (i)) /* * To get proper branch prediction for the main line, we must branch @@ -43,6 +48,21 @@ static __inline__ void atomic_add(int i, atomic_t * v) :"Ir" (i), "m" (v->counter)); } +static __inline__ void atomic64_add(long i, atomic64_t * v) +{ + unsigned long temp; + __asm__ __volatile__( + "1: ldq_l %0,%1\n" + " addq %0,%2,%0\n" + " stq_c %0,%1\n" + " beq %0,2f\n" + ".subsection 2\n" + "2: br 1b\n" + ".previous" + :"=&r" (temp), "=m" (v->counter) + :"Ir" (i), "m" (v->counter)); +} + static __inline__ void atomic_sub(int i, atomic_t * v) { unsigned long temp; @@ -58,6 +78,22 @@ static __inline__ void atomic_sub(int i, atomic_t * v) :"Ir" (i), "m" (v->counter)); } +static __inline__ void atomic64_sub(long i, atomic64_t * v) +{ + unsigned long temp; + __asm__ __volatile__( + "1: ldq_l %0,%1\n" + " subq %0,%2,%0\n" + " stq_c %0,%1\n" + " beq %0,2f\n" + ".subsection 2\n" + "2: br 1b\n" + ".previous" + :"=&r" (temp), "=m" (v->counter) + :"Ir" (i), "m" (v->counter)); +} + + /* * Same as above, but return the result value */ @@ -79,6 +115,24 @@ static __inline__ long atomic_add_return(int i, atomic_t * v) return result; } +static __inline__ long atomic64_add_return(long i, atomic64_t * v) +{ + long temp, result; + __asm__ __volatile__( + "1: ldq_l %0,%1\n" + " addq %0,%3,%2\n" + " addq %0,%3,%0\n" + " stq_c %0,%1\n" + " beq %0,2f\n" + " mb\n" + ".subsection 2\n" + "2: br 1b\n" + ".previous" + :"=&r" (temp), "=m" (v->counter), "=&r" (result) + :"Ir" (i), "m" (v->counter) : "memory"); + return result; +} + static __inline__ long atomic_sub_return(int i, atomic_t * v) { long temp, result; @@ -97,14 +151,41 @@ static __inline__ long atomic_sub_return(int i, atomic_t * v) return result; } +static __inline__ long atomic64_sub_return(long i, atomic64_t * v) +{ + long temp, result; + __asm__ __volatile__( + "1: ldq_l %0,%1\n" + " subq %0,%3,%2\n" + " subq %0,%3,%0\n" + " stq_c %0,%1\n" + " beq %0,2f\n" + " mb\n" + ".subsection 2\n" + "2: br 1b\n" + ".previous" + :"=&r" (temp), "=m" (v->counter), "=&r" (result) + :"Ir" (i), "m" (v->counter) : "memory"); + return result; +} + #define atomic_dec_return(v) atomic_sub_return(1,(v)) +#define atomic64_dec_return(v) atomic64_sub_return(1,(v)) + #define atomic_inc_return(v) atomic_add_return(1,(v)) +#define atomic64_inc_return(v) atomic64_add_return(1,(v)) #define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0) +#define atomic64_sub_and_test(i,v) (atomic64_sub_return((i), (v)) == 0) + #define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0) +#define atomic64_dec_and_test(v) (atomic64_sub_return(1, (v)) == 0) #define atomic_inc(v) atomic_add(1,(v)) +#define atomic64_inc(v) atomic64_add(1,(v)) + #define atomic_dec(v) atomic_sub(1,(v)) +#define atomic64_dec(v) atomic64_sub(1,(v)) #define smp_mb__before_atomic_dec() smp_mb() #define smp_mb__after_atomic_dec() smp_mb() diff --git a/include/asm-alpha/local.h b/include/asm-alpha/local.h new file mode 100644 index 000000000000..49f543a8f11e --- /dev/null +++ b/include/asm-alpha/local.h @@ -0,0 +1,40 @@ +#ifndef _ARCH_SPARC64_LOCAL_H +#define _ARCH_SPARC64_LOCAL_H + +#include +#include + +typedef atomic64_t local_t; + +#define LOCAL_INIT(i) ATOMIC64_INIT(i) +#define local_read(v) atomic64_read(v) +#define local_set(v,i) atomic64_set(v,i) + +#define local_inc(v) atomic64_inc(v) +#define local_dec(v) atomic64_inc(v) +#define local_add(i, v) atomic64_add(i, v) +#define local_sub(i, v) atomic64_sub(i, v) + +#define __local_inc(v) ((v)->counter++) +#define __local_dec(v) ((v)->counter++) +#define __local_add(i,v) ((v)->counter+=(i)) +#define __local_sub(i,v) ((v)->counter-=(i)) + +/* Use these for per-cpu local_t variables: on some archs they are + * much more efficient than these naive implementations. Note they take + * a variable, not an address. + */ +#define cpu_local_read(v) local_read(&__get_cpu_var(v)) +#define cpu_local_set(v, i) local_set(&__get_cpu_var(v), (i)) + +#define cpu_local_inc(v) local_inc(&__get_cpu_var(v)) +#define cpu_local_dec(v) local_dec(&__get_cpu_var(v)) +#define cpu_local_add(i, v) local_add((i), &__get_cpu_var(v)) +#define cpu_local_sub(i, v) local_sub((i), &__get_cpu_var(v)) + +#define __cpu_local_inc(v) __local_inc(&__get_cpu_var(v)) +#define __cpu_local_dec(v) __local_dec(&__get_cpu_var(v)) +#define __cpu_local_add(i, v) __local_add((i), &__get_cpu_var(v)) +#define __cpu_local_sub(i, v) __local_sub((i), &__get_cpu_var(v)) + +#endif /* _ARCH_SPARC64_LOCAL_H */ -- cgit v1.2.3 From 50682916abe6fc0298e04632b4d017117f325410 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 21 Jul 2003 09:56:56 -0700 Subject: [ALPHA] Finish adding asm/local.h. --- include/asm-alpha/local.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/asm-alpha/local.h b/include/asm-alpha/local.h index 49f543a8f11e..7babc457b921 100644 --- a/include/asm-alpha/local.h +++ b/include/asm-alpha/local.h @@ -1,5 +1,5 @@ -#ifndef _ARCH_SPARC64_LOCAL_H -#define _ARCH_SPARC64_LOCAL_H +#ifndef _ALPHA_LOCAL_H +#define _ALPHA_LOCAL_H #include #include @@ -37,4 +37,4 @@ typedef atomic64_t local_t; #define __cpu_local_add(i, v) __local_add((i), &__get_cpu_var(v)) #define __cpu_local_sub(i, v) __local_sub((i), &__get_cpu_var(v)) -#endif /* _ARCH_SPARC64_LOCAL_H */ +#endif /* _ALPHA_LOCAL_H */ -- cgit v1.2.3 From e45635ccc6445e19ca197853ea9ec555ec5ca25a Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 25 Jul 2003 00:39:23 -0700 Subject: [PATCH] read-ahead and failfast Here's the patch to enable failfast flag in the bio submission code, and use it for multipath and readahead. --- drivers/block/ll_rw_blk.c | 18 +++++++++++++++--- drivers/ide/ide-cd.c | 3 +++ drivers/ide/ide-disk.c | 2 +- drivers/ide/ide-io.c | 10 ++++++++-- drivers/md/multipath.c | 1 + include/linux/bio.h | 2 ++ include/linux/blkdev.h | 31 ++++++++++++++++--------------- include/linux/sched.h | 1 + mm/readahead.c | 13 ++++++++++--- 9 files changed, 57 insertions(+), 24 deletions(-) (limited to 'include') diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index f9678d95a043..f6ca4f797e73 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -689,7 +689,7 @@ void blk_queue_invalidate_tags(request_queue_t *q) static char *rq_flags[] = { "REQ_RW", - "REQ_RW_AHEAD", + "REQ_FAILFAST", "REQ_SOFTBARRIER", "REQ_HARDBARRIER", "REQ_CMD", @@ -706,6 +706,10 @@ static char *rq_flags[] = { "REQ_DRIVE_CMD", "REQ_DRIVE_TASK", "REQ_DRIVE_TASKFILE", + "REQ_PREEMPT", + "REQ_PM_SUSPEND", + "REQ_PM_RESUME", + "REQ_PM_SHUTDOWN", }; void blk_dump_rq_flags(struct request *rq, char *msg) @@ -1793,7 +1797,7 @@ void __blk_attempt_remerge(request_queue_t *q, struct request *rq) static int __make_request(request_queue_t *q, struct bio *bio) { struct request *req, *freereq = NULL; - int el_ret, rw, nr_sectors, cur_nr_sectors, barrier; + int el_ret, rw, nr_sectors, cur_nr_sectors, barrier, ra; struct list_head *insert_here; sector_t sector; @@ -1814,6 +1818,8 @@ static int __make_request(request_queue_t *q, struct bio *bio) barrier = test_bit(BIO_RW_BARRIER, &bio->bi_rw); + ra = bio_flagged(bio, BIO_RW_AHEAD) || current->flags & PF_READAHEAD; + again: insert_here = NULL; spin_lock_irq(q->queue_lock); @@ -1901,7 +1907,7 @@ get_rq: /* * READA bit set */ - if (bio_flagged(bio, BIO_RW_AHEAD)) + if (ra) goto end_io; freereq = get_request_wait(q, rw); @@ -1921,6 +1927,12 @@ get_rq: if (barrier) req->flags |= (REQ_HARDBARRIER | REQ_NOMERGE); + /* + * don't stack up retries for read ahead + */ + if (ra) + req->flags |= REQ_FAILFAST; + req->errors = 0; req->hard_sector = req->sector = sector; req->hard_nr_sectors = req->nr_sectors = nr_sectors; diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index ea211467f652..bfa975636ede 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -767,6 +767,9 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret) } else if (blk_fs_request(rq)) { /* Handle errors from READ and WRITE requests. */ + if (blk_noretry_request(rq)) + cdrom_end_request(drive, 0); + if (sense_key == NOT_READY) { /* Tray open. */ cdrom_saw_media_change (drive); diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index 2a90ce3aed3f..6bfd1ded67f6 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -907,7 +907,7 @@ ide_startstop_t idedisk_error (ide_drive_t *drive, const char *msg, u8 stat) /* force an abort */ hwif->OUTB(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG); } - if (rq->errors >= ERROR_MAX) + if (rq->errors >= ERROR_MAX || blk_noretry_request(rq)) DRIVER(drive)->end_request(drive, 0, 0); else { if ((rq->errors & ERROR_RESET) == ERROR_RESET) { diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index acac8e3dfeea..515018c7b261 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -58,8 +58,7 @@ #if (DISK_RECOVERY_TIME > 0) -Error So the User Has To Fix the Compilation And Stop Hacking Port 0x43 -Does anyone ever use this anyway ?? +#error So the User Has To Fix the Compilation And Stop Hacking Port 0x43. Does anyone ever use this anyway ?? /* * For really screwy hardware (hey, at least it *can* be used with Linux) @@ -113,6 +112,13 @@ int ide_end_request (ide_drive_t *drive, int uptodate, int nr_sectors) if (!nr_sectors) nr_sectors = rq->hard_cur_sectors; + /* + * if failfast is set on a request, override number of sectors and + * complete the whole request right now + */ + if (blk_noretry_request(rq) && !uptodate) + nr_sectors = rq->hard_nr_sectors; + /* * decide whether to reenable DMA -- 3 is a random magic for now, * if we DMA timeout more than 3 times, just stay in PIO diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index eeab0139520c..8d0413844101 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -179,6 +179,7 @@ static int multipath_make_request (request_queue_t *q, struct bio * bio) mp_bh->bio = *bio; mp_bh->bio.bi_bdev = multipath->rdev->bdev; + mp_bh->bio.bi_flags |= (1 << BIO_RW_FAILFAST); mp_bh->bio.bi_end_io = multipath_end_request; mp_bh->bio.bi_private = mp_bh; generic_make_request(&mp_bh->bio); diff --git a/include/linux/bio.h b/include/linux/bio.h index d3f47b1b0f6a..6ad6d20d3778 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -119,10 +119,12 @@ struct bio { * bit 0 -- read (not set) or write (set) * bit 1 -- rw-ahead when set * bit 2 -- barrier + * bit 3 -- fail fast, don't want low level driver retries */ #define BIO_RW 0 #define BIO_RW_AHEAD 1 #define BIO_RW_BARRIER 2 +#define BIO_RW_FAILFAST 3 /* * various member access, note that bio_data should of course not be used diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index d951995038e5..fa14b066b2bb 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -165,25 +165,25 @@ struct request { * first three bits match BIO_RW* bits, important */ enum rq_flag_bits { - __REQ_RW, /* not set, read. set, write */ - __REQ_RW_AHEAD, /* READA */ + __REQ_RW, /* not set, read. set, write */ + __REQ_FAILFAST, /* no low level driver retries */ __REQ_SOFTBARRIER, /* may not be passed by ioscheduler */ __REQ_HARDBARRIER, /* may not be passed by drive either */ - __REQ_CMD, /* is a regular fs rw request */ - __REQ_NOMERGE, /* don't touch this for merging */ - __REQ_STARTED, /* drive already may have started this one */ - __REQ_DONTPREP, /* don't call prep for this one */ - __REQ_QUEUED, /* uses queueing */ + __REQ_CMD, /* is a regular fs rw request */ + __REQ_NOMERGE, /* don't touch this for merging */ + __REQ_STARTED, /* drive already may have started this one */ + __REQ_DONTPREP, /* don't call prep for this one */ + __REQ_QUEUED, /* uses queueing */ /* * for ATA/ATAPI devices */ - __REQ_PC, /* packet command (special) */ - __REQ_BLOCK_PC, /* queued down pc from block layer */ - __REQ_SENSE, /* sense retrival */ + __REQ_PC, /* packet command (special) */ + __REQ_BLOCK_PC, /* queued down pc from block layer */ + __REQ_SENSE, /* sense retrival */ - __REQ_FAILED, /* set if the request failed */ - __REQ_QUIET, /* don't worry about errors */ - __REQ_SPECIAL, /* driver suplied command */ + __REQ_FAILED, /* set if the request failed */ + __REQ_QUIET, /* don't worry about errors */ + __REQ_SPECIAL, /* driver suplied command */ __REQ_DRIVE_CMD, __REQ_DRIVE_TASK, __REQ_DRIVE_TASKFILE, @@ -191,11 +191,11 @@ enum rq_flag_bits { __REQ_PM_SUSPEND, /* suspend request */ __REQ_PM_RESUME, /* resume request */ __REQ_PM_SHUTDOWN, /* shutdown request */ - __REQ_NR_BITS, /* stops here */ + __REQ_NR_BITS, /* stops here */ }; #define REQ_RW (1 << __REQ_RW) -#define REQ_RW_AHEAD (1 << __REQ_RW_AHEAD) +#define REQ_FAILFAST (1 << __REQ_FAILFAST) #define REQ_SOFTBARRIER (1 << __REQ_SOFTBARRIER) #define REQ_HARDBARRIER (1 << __REQ_HARDBARRIER) #define REQ_CMD (1 << __REQ_CMD) @@ -364,6 +364,7 @@ struct request_queue #define blk_queue_tagged(q) test_bit(QUEUE_FLAG_QUEUED, &(q)->queue_flags) #define blk_fs_request(rq) ((rq)->flags & REQ_CMD) #define blk_pc_request(rq) ((rq)->flags & REQ_BLOCK_PC) +#define blk_noretry_request(rq) ((rq)->flags & REQ_FAILFAST) #define blk_pm_suspend_request(rq) ((rq)->flags & REQ_PM_SUSPEND) #define blk_pm_resume_request(rq) ((rq)->flags & REQ_PM_RESUME) diff --git a/include/linux/sched.h b/include/linux/sched.h index bf740af246c0..b20db4e5fbfa 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -487,6 +487,7 @@ do { if (atomic_dec_and_test(&(tsk)->usage)) __put_task_struct(tsk); } while(0) #define PF_SWAPOFF 0x00080000 /* I am in swapoff */ #define PF_LESS_THROTTLE 0x01000000 /* Throttle me less: I clena memory */ #define PF_SYNCWRITE 0x00200000 /* I am doing a sync write */ +#define PF_READAHEAD 0x00400000 /* I am doing read-ahead */ #ifdef CONFIG_SMP extern int set_cpus_allowed(task_t *p, unsigned long new_mask); diff --git a/mm/readahead.c b/mm/readahead.c index 08d7e877ca97..d5db6345b4c1 100644 --- a/mm/readahead.c +++ b/mm/readahead.c @@ -94,9 +94,14 @@ static int read_pages(struct address_space *mapping, struct file *filp, { unsigned page_idx; struct pagevec lru_pvec; + int ret = 0; + + current->flags |= PF_READAHEAD; - if (mapping->a_ops->readpages) - return mapping->a_ops->readpages(filp, mapping, pages, nr_pages); + if (mapping->a_ops->readpages) { + ret = mapping->a_ops->readpages(filp, mapping, pages, nr_pages); + goto out; + } pagevec_init(&lru_pvec, 0); for (page_idx = 0; page_idx < nr_pages; page_idx++) { @@ -112,7 +117,9 @@ static int read_pages(struct address_space *mapping, struct file *filp, } } pagevec_lru_add(&lru_pvec); - return 0; +out: + current->flags &= ~PF_READAHEAD; + return ret; } /* -- cgit v1.2.3 From 314635e1132bddd57d293550f34dca8f3c19d20a Mon Sep 17 00:00:00 2001 From: Krzysztof Halasa Date: Fri, 25 Jul 2003 01:24:04 -0700 Subject: [PATCH] HDLC update This updates generic HDLC from 1.14 to 1.15. - fix a kernel panic caused by a recent change to unregister_netdevice() (struct net_device * can't be kfreed before rtnl_unlock()) - adds carrier_* support - hw drivers report DCD status and higher level protocols use that info, and do netif_carrier_{on,off}() according to DCD and (Cisco and FR) link management status. - moves Frame-Relay constants etc. from include/linux/hdlc.h to hdlc_fr.c. They are internal FR things and are not needed in the global header. - protocol hooks are slighty changed to allow zeroing (memset). - removes CONFIG_HDLC_DEBUG_* variables. Users tend to make very wrong use of them. Now setting them requires changing .c #define. Anyway they are development-only things. - misc style corrections etc. --- drivers/net/wan/Kconfig | 31 ----- drivers/net/wan/c101.c | 64 +++++++-- drivers/net/wan/hd64570.h | 3 + drivers/net/wan/hd6457x.c | 90 ++++++++----- drivers/net/wan/hdlc_cisco.c | 29 +++-- drivers/net/wan/hdlc_fr.c | 287 +++++++++++++++++++++++++++++++---------- drivers/net/wan/hdlc_generic.c | 119 ++++++++++++++++- drivers/net/wan/hdlc_ppp.c | 11 +- drivers/net/wan/hdlc_raw.c | 9 +- drivers/net/wan/hdlc_raw_eth.c | 9 +- drivers/net/wan/hdlc_x25.c | 12 +- drivers/net/wan/n2.c | 13 +- include/linux/hdlc.h | 151 +++++----------------- 13 files changed, 515 insertions(+), 313 deletions(-) (limited to 'include') diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig index 77f5ace58eaa..929ca4813194 100644 --- a/drivers/net/wan/Kconfig +++ b/drivers/net/wan/Kconfig @@ -401,37 +401,6 @@ config FARSYNC should add "alias hdlcX farsync" to /etc/modules.conf for each interface, where X is 0, 1, 2, ... -config HDLC_DEBUG_PKT - bool "Debug received/transmitted packets" - depends on HDLC - help - This option is for developers only - do NOT use on production - systems. - -config HDLC_DEBUG_HARD_HEADER - bool "Debug hard_header routines" - depends on HDLC - help - This option is for developers only - do NOT use on production - systems. - -config HDLC_DEBUG_ECN - bool "Debug FECN/BECN conditions" - depends on HDLC - help - This option is for developers only - do NOT use on production - systems. - -config HDLC_DEBUG_RINGS - bool "Debug RX/TX packet rings" - depends on HDLC - help - If you answer Y here you will be able to get a diagnostic dump of - port's TX and RX packet rings, using "sethdlc hdlcX private" - command. It does not affect normal operations. - - If unsure, say Y here. - config DLCI tristate "Frame relay DLCI support" depends on WAN diff --git a/drivers/net/wan/c101.c b/drivers/net/wan/c101.c index 0854ade71ca9..f47cd918ea56 100644 --- a/drivers/net/wan/c101.c +++ b/drivers/net/wan/c101.c @@ -14,7 +14,6 @@ * Moxa C101 User's Manual */ -#include #include #include #include @@ -31,9 +30,12 @@ #include "hd64570.h" -static const char* version = "Moxa C101 driver version: 1.14"; +static const char* version = "Moxa C101 driver version: 1.15"; static const char* devname = "C101"; +#undef DEBUG_PKT +#define DEBUG_RINGS + #define C101_PAGE 0x1D00 #define C101_DTR 0x1E00 #define C101_SCA 0x1F00 @@ -95,7 +97,8 @@ static card_t **new_card = &first_card; #define winsize(card) (C101_WINDOW_SIZE) #define win0base(card) ((card)->win0base) #define winbase(card) ((card)->win0base + 0x2000) -#define get_port(card, port) ((port) == 0 ? (card) : NULL) +#define get_port(card, port) (card) +static void sca_msci_intr(port_t *port); static inline u8 sca_get_page(card_t *card) @@ -116,9 +119,30 @@ static inline void openwin(card_t *card, u8 page) #include "hd6457x.c" +static void sca_msci_intr(port_t *port) +{ + card_t* card = port_to_card(port); + u8 stat = sca_in(MSCI1_OFFSET + ST1, card); /* read MSCI ST1 status */ + + /* Reset MSCI TX underrun status bit */ + sca_out(stat & ST1_UDRN, MSCI0_OFFSET + ST1, card); + + if (stat & ST1_UDRN) { + port->hdlc.stats.tx_errors++; /* TX Underrun error detected */ + port->hdlc.stats.tx_fifo_errors++; + } + + /* Reset MSCI CDCD status bit - uses ch#2 DCD input */ + sca_out(stat & ST1_CDCD, MSCI1_OFFSET + ST1, card); + + if (stat & ST1_CDCD) + hdlc_set_carrier(!(sca_in(MSCI1_OFFSET + ST3, card) & ST3_DCD), + &port->hdlc); +} + + static void c101_set_iface(port_t *port) { - u8 msci = get_msci(port); u8 rxs = port->rxs & CLK_BRG_MASK; u8 txs = port->txs & CLK_BRG_MASK; @@ -145,8 +169,8 @@ static void c101_set_iface(port_t *port) port->rxs = rxs; port->txs = txs; - sca_out(rxs, msci + RXS, port); - sca_out(txs, msci + TXS, port); + sca_out(rxs, MSCI1_OFFSET + RXS, port); + sca_out(txs, MSCI1_OFFSET + TXS, port); sca_set_port(port); } @@ -164,6 +188,17 @@ static int c101_open(struct net_device *dev) writeb(1, port->win0base + C101_DTR); sca_out(0, MSCI1_OFFSET + CTL, port); /* RTS uses ch#2 output */ sca_open(hdlc); + /* DCD is connected to port 2 !@#$%^& - disable MSCI0 CDCD interrupt */ + sca_out(IE1_UDRN, MSCI0_OFFSET + IE1, port); + sca_out(IE0_TXINT, MSCI0_OFFSET + IE0, port); + + hdlc_set_carrier(!(sca_in(MSCI1_OFFSET + ST3, port) & ST3_DCD), hdlc); + printk(KERN_DEBUG "0x%X\n", sca_in(MSCI1_OFFSET + ST3, port)); + + /* enable MSCI1 CDCD interrupt */ + sca_out(IE1_CDCD, MSCI1_OFFSET + IE1, port); + sca_out(IE0_RXINTA, MSCI1_OFFSET + IE0, port); + sca_out(0x48, IER0, port); /* TXINT #0 and RXINT #1 */ c101_set_iface(port); return 0; } @@ -189,9 +224,14 @@ static int c101_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) hdlc_device *hdlc = dev_to_hdlc(dev); port_t *port = hdlc_to_port(hdlc); -#ifdef CONFIG_HDLC_DEBUG_RINGS +#ifdef DEBUG_RINGS if (cmd == SIOCDEVPRIVATE) { sca_dump_rings(hdlc); + printk(KERN_DEBUG "MSCI1: ST: %02x %02x %02x %02x\n", + sca_in(MSCI1_OFFSET + ST0, port), + sca_in(MSCI1_OFFSET + ST1, port), + sca_in(MSCI1_OFFSET + ST2, port), + sca_in(MSCI1_OFFSET + ST3, port)); return 0; } #endif @@ -298,9 +338,6 @@ static int __init c101_run(unsigned long irq, unsigned long winbase) card->tx_ring_buffers = TX_RING_BUFFERS; card->rx_ring_buffers = RX_RING_BUFFERS; - printk(KERN_DEBUG "c101: using %u TX + %u RX packets rings\n", - card->tx_ring_buffers, card->rx_ring_buffers); - card->buff_offset = C101_WINDOW_SIZE; /* Bytes 1D00-1FFF reserved */ readb(card->win0base + C101_PAGE); /* Resets SCA? */ @@ -333,6 +370,13 @@ static int __init c101_run(unsigned long irq, unsigned long winbase) } sca_init_sync_port(card); /* Set up C101 memory */ + hdlc_set_carrier(!(sca_in(MSCI1_OFFSET + ST3, card) & ST3_DCD), + &card->hdlc); + + printk(KERN_INFO "%s: Moxa C101 on IRQ%u," + " using %u TX + %u RX packets rings\n", + hdlc_to_name(&card->hdlc), card->irq, + card->tx_ring_buffers, card->rx_ring_buffers); *new_card = card; new_card = &card->next_card; diff --git a/drivers/net/wan/hd64570.h b/drivers/net/wan/hd64570.h index cd3fcf86d6cf..3839662ff201 100644 --- a/drivers/net/wan/hd64570.h +++ b/drivers/net/wan/hd64570.h @@ -217,12 +217,15 @@ typedef struct { #define ST0_RXRDY 0x01 /* RX ready */ #define ST1_UDRN 0x80 /* MSCI TX underrun */ +#define ST1_CDCD 0x04 /* DCD level changed */ #define ST3_CTS 0x08 /* modem input - /CTS */ #define ST3_DCD 0x04 /* modem input - /DCD */ #define IE0_TXINT 0x80 /* TX INT MSCI interrupt enable */ +#define IE0_RXINTA 0x40 /* RX INT A MSCI interrupt enable */ #define IE1_UDRN 0x80 /* TX underrun MSCI interrupt enable */ +#define IE1_CDCD 0x04 /* DCD level changed */ #define DCR_ABORT 0x01 /* Software abort command */ #define DCR_CLEAR_EOF 0x02 /* Clear EOF interrupt */ diff --git a/drivers/net/wan/hd6457x.c b/drivers/net/wan/hd6457x.c index f85ae029f419..561216c1a4eb 100644 --- a/drivers/net/wan/hd6457x.c +++ b/drivers/net/wan/hd6457x.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include #include @@ -244,10 +243,14 @@ static void sca_init_sync_port(port_t *port) sca_out(DIR_BOFE, DIR_TX(phy_node(port)), card); } } + + hdlc_set_carrier(!(sca_in(get_msci(port) + ST3, card) & ST3_DCD), + &port->hdlc); } +#ifdef NEED_SCA_MSCI_INTR /* MSCI interrupt service */ static inline void sca_msci_intr(port_t *port) { @@ -255,17 +258,19 @@ static inline void sca_msci_intr(port_t *port) card_t* card = port_to_card(port); u8 stat = sca_in(msci + ST1, card); /* read MSCI ST1 status */ - /* printk(KERN_DEBUG "MSCI INT: ST1=%02X ILAR=%02X\n", - stat, sca_in(ILAR, card)); */ - - /* Reset MSCI TX underrun status bit */ - sca_out(stat & ST1_UDRN, msci + ST1, card); + /* Reset MSCI TX underrun and CDCD status bit */ + sca_out(stat & (ST1_UDRN | ST1_CDCD), msci + ST1, card); if (stat & ST1_UDRN) { port->hdlc.stats.tx_errors++; /* TX Underrun error detected */ port->hdlc.stats.tx_fifo_errors++; } + + if (stat & ST1_CDCD) + hdlc_set_carrier(!(sca_in(msci + ST3, card) & ST3_DCD), + &port->hdlc); } +#endif @@ -307,7 +312,7 @@ static inline void sca_rx(card_t *card, port_t *port, pkt_desc *desc, u16 rxin) openwin(card, 0); #endif skb_put(skb, len); -#ifdef CONFIG_HDLC_DEBUG_PKT +#ifdef DEBUG_PKT printk(KERN_DEBUG "%s RX(%i):", hdlc_to_name(&port->hdlc), skb->len); debug_frame(skb); #endif @@ -560,25 +565,28 @@ static void sca_open(hdlc_device *hdlc) #endif /* We're using the following interrupts: - - TXINT (DMAC completed all transmisions, underflow or CTS change) + - TXINT (DMAC completed all transmisions, underrun or DCD change) - all DMA interrupts */ + hdlc_set_carrier(!(sca_in(msci + ST3, card) & ST3_DCD), hdlc); + #ifdef __HD64570_H - /* MSCI TX INT IRQ enable */ - sca_out(IE0_TXINT, msci + IE0, card); - sca_out(IE1_UDRN, msci + IE1, card); /* TX underrun -> TXINT */ - sca_out(sca_in(IER0, card) | (phy_node(port) ? 0x80 : 0x08), - IER0, card); - /* DMA IRQ enable */ + /* MSCI TX INT and RX INT A IRQ enable */ + sca_out(IE0_TXINT | IE0_RXINTA, msci + IE0, card); + sca_out(IE1_UDRN | IE1_CDCD, msci + IE1, card); + sca_out(sca_in(IER0, card) | (phy_node(port) ? 0xC0 : 0x0C), + IER0, card); /* TXINT and RXINT */ + /* enable DMA IRQ */ sca_out(sca_in(IER1, card) | (phy_node(port) ? 0xF0 : 0x0F), IER1, card); #else - /* MSCI TX INT IRQ enable */ - sca_outl(IE0_TXINT | IE0_UDRN, msci + IE0, card); + /* MSCI TXINT and RXINTA interrupt enable */ + sca_outl(IE0_TXINT | IE0_RXINTA | IE0_UDRN | IE0_CDCD, msci + IE0, + card); /* DMA & MSCI IRQ enable */ - sca_outl(sca_in(IER0, card) | - (phy_node(port) ? 0x02006600 : 0x00020066), IER0, card); + sca_outl(sca_inl(IER0, card) | + (phy_node(port) ? 0x0A006600 : 0x000A0066), IER0, card); #endif #ifdef __HD64570_H @@ -600,10 +608,23 @@ static void sca_open(hdlc_device *hdlc) static void sca_close(hdlc_device *hdlc) { port_t *port = hdlc_to_port(hdlc); + card_t* card = port_to_card(port); /* reset channel */ netif_stop_queue(hdlc_to_dev(hdlc)); sca_out(CMD_RESET, get_msci(port) + CMD, port_to_card(port)); +#ifdef __HD64570_H + /* disable MSCI interrupts */ + sca_out(sca_in(IER0, card) & (phy_node(port) ? 0x0F : 0xF0), + IER0, card); + /* disable DMA interrupts */ + sca_out(sca_in(IER1, card) & (phy_node(port) ? 0x0F : 0xF0), + IER1, card); +#else + /* disable DMA & MSCI IRQ */ + sca_outl(sca_inl(IER0, card) & + (phy_node(port) ? 0x00FF00FF : 0xFF00FF00), IER0, card); +#endif } @@ -636,7 +657,7 @@ static int sca_attach(hdlc_device *hdlc, unsigned short encoding, -#ifdef CONFIG_HDLC_DEBUG_RINGS +#ifdef DEBUG_RINGS static void sca_dump_rings(hdlc_device *hdlc) { port_t *port = hdlc_to_port(hdlc); @@ -651,30 +672,26 @@ static void sca_dump_rings(hdlc_device *hdlc) openwin(card, 0); #endif - printk(KERN_ERR "RX ring: CDA=%u EDA=%u DSR=%02X in=%u %sactive", + printk(KERN_DEBUG "RX ring: CDA=%u EDA=%u DSR=%02X in=%u %sactive", sca_ina(get_dmac_rx(port) + CDAL, card), sca_ina(get_dmac_rx(port) + EDAL, card), - sca_in(DSR_RX(phy_node(port)), card), - port->rxin, + sca_in(DSR_RX(phy_node(port)), card), port->rxin, sca_in(DSR_RX(phy_node(port)), card) & DSR_DE?"":"in"); for (cnt = 0; cnt < port_to_card(port)->rx_ring_buffers; cnt++) - printk(" %02X", - readb(&(desc_address(port, cnt, 0)->stat))); + printk(" %02X", readb(&(desc_address(port, cnt, 0)->stat))); - printk("\n" KERN_ERR "TX ring: CDA=%u EDA=%u DSR=%02X in=%u " + printk("\n" KERN_DEBUG "TX ring: CDA=%u EDA=%u DSR=%02X in=%u " "last=%u %sactive", sca_ina(get_dmac_tx(port) + CDAL, card), sca_ina(get_dmac_tx(port) + EDAL, card), - sca_in(DSR_TX(phy_node(port)), card), port->txin, - port->txlast, + sca_in(DSR_TX(phy_node(port)), card), port->txin, port->txlast, sca_in(DSR_TX(phy_node(port)), card) & DSR_DE ? "" : "in"); for (cnt = 0; cnt < port_to_card(port)->tx_ring_buffers; cnt++) - printk(" %02X", - readb(&(desc_address(port, cnt, 1)->stat))); + printk(" %02X", readb(&(desc_address(port, cnt, 1)->stat))); printk("\n"); - printk(KERN_ERR "MSCI: MD: %02x %02x %02x, " + printk(KERN_DEBUG "MSCI: MD: %02x %02x %02x, " "ST: %02x %02x %02x %02x" #ifdef __HD64572_H " %02x" @@ -695,14 +712,18 @@ static void sca_dump_rings(hdlc_device *hdlc) sca_in(get_msci(port) + CST1, card)); #ifdef __HD64572_H - printk(KERN_ERR "ILAR: %02x\n", sca_in(ILAR, card)); + printk(KERN_DEBUG "ILAR: %02x ISR: %08x %08x\n", sca_in(ILAR, card), + sca_inl(ISR0, card), sca_inl(ISR1, card)); +#else + printk(KERN_DEBUG "ISR: %02x %02x %02x\n", sca_in(ISR0, card), + sca_in(ISR1, card), sca_in(ISR2, card)); #endif #if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED) openwin(card, page); /* Restore original page */ #endif } -#endif /* CONFIG_HDLC_DEBUG_RINGS */ +#endif /* DEBUG_RINGS */ @@ -723,7 +744,7 @@ static int sca_xmit(struct sk_buff *skb, struct net_device *dev) desc = desc_address(port, port->txin + 1, 1); if (readb(&desc->stat)) { /* allow 1 packet gap */ /* should never happen - previous xmit should stop queue */ -#ifdef CONFIG_HDLC_DEBUG_PKT +#ifdef DEBUG_PKT printk(KERN_DEBUG "%s: transmitter buffer full\n", dev->name); #endif netif_stop_queue(dev); @@ -731,7 +752,7 @@ static int sca_xmit(struct sk_buff *skb, struct net_device *dev) return 1; /* request packet to be queued */ } -#ifdef CONFIG_HDLC_DEBUG_PKT +#ifdef DEBUG_PKT printk(KERN_DEBUG "%s TX(%i):", hdlc_to_name(hdlc), skb->len); debug_frame(skb); #endif @@ -828,7 +849,6 @@ static void __devinit sca_init(card_t *card, int wait_states) sca_out(0, DMER, card); /* DMA Master disable */ sca_out(0x03, PCR, card); /* DMA priority */ - sca_out(0, IER1, card); /* DMA interrupt disable */ sca_out(0, DSR_RX(0), card); /* DMA disable - to halt state */ sca_out(0, DSR_TX(0), card); sca_out(0, DSR_RX(1), card); diff --git a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c index f6234c5a64cc..c639524042c5 100644 --- a/drivers/net/wan/hdlc_cisco.c +++ b/drivers/net/wan/hdlc_cisco.c @@ -9,7 +9,6 @@ * as published by the Free Software Foundation. */ -#include #include #include #include @@ -24,6 +23,7 @@ #include #include +#undef DEBUG_HARD_HEADER #define CISCO_MULTICAST 0x8F /* Cisco multicast address */ #define CISCO_UNICAST 0x0F /* Cisco unicast address */ @@ -39,7 +39,7 @@ static int cisco_hard_header(struct sk_buff *skb, struct net_device *dev, unsigned int len) { hdlc_header *data; -#ifdef CONFIG_HDLC_DEBUG_HARD_HEADER +#ifdef DEBUG_HARD_HEADER printk(KERN_DEBUG "%s: cisco_hard_header called\n", dev->name); #endif @@ -182,7 +182,7 @@ static void cisco_rx(struct sk_buff *skb) case CISCO_KEEPALIVE_REQ: hdlc->state.cisco.rxseq = ntohl(cisco_data->par1); - if (ntohl(cisco_data->par2) == hdlc->state.cisco.txseq) { + if (ntohl(cisco_data->par2)==hdlc->state.cisco.txseq) { hdlc->state.cisco.last_poll = jiffies; if (!hdlc->state.cisco.up) { u32 sec, min, hrs, days; @@ -219,11 +219,12 @@ static void cisco_timer(unsigned long arg) { hdlc_device *hdlc = (hdlc_device*)arg; - if (hdlc->state.cisco.up && - jiffies - hdlc->state.cisco.last_poll >= + if (hdlc->state.cisco.up && jiffies - hdlc->state.cisco.last_poll >= hdlc->state.cisco.settings.timeout * HZ) { hdlc->state.cisco.up = 0; printk(KERN_INFO "%s: Link down\n", hdlc_to_name(hdlc)); + if (netif_carrier_ok(&hdlc->netdev)) + netif_carrier_off(&hdlc->netdev); } cisco_keepalive_send(hdlc, CISCO_KEEPALIVE_REQ, @@ -238,7 +239,7 @@ static void cisco_timer(unsigned long arg) -static int cisco_open(hdlc_device *hdlc) +static void cisco_start(hdlc_device *hdlc) { hdlc->state.cisco.last_poll = 0; hdlc->state.cisco.up = 0; @@ -249,14 +250,15 @@ static int cisco_open(hdlc_device *hdlc) hdlc->state.cisco.timer.function = cisco_timer; hdlc->state.cisco.timer.data = (unsigned long)hdlc; add_timer(&hdlc->state.cisco.timer); - return 0; } -static void cisco_close(hdlc_device *hdlc) +static void cisco_stop(hdlc_device *hdlc) { del_timer_sync(&hdlc->state.cisco.timer); + if (netif_carrier_ok(&hdlc->netdev)) + netif_carrier_off(&hdlc->netdev); } @@ -301,12 +303,13 @@ int hdlc_cisco_ioctl(hdlc_device *hdlc, struct ifreq *ifr) hdlc_proto_detach(hdlc); memcpy(&hdlc->state.cisco.settings, &new_settings, size); + memset(&hdlc->proto, 0, sizeof(hdlc->proto)); - hdlc->open = cisco_open; - hdlc->stop = cisco_close; - hdlc->netif_rx = cisco_rx; - hdlc->type_trans = cisco_type_trans; - hdlc->proto = IF_PROTO_CISCO; + hdlc->proto.start = cisco_start; + hdlc->proto.stop = cisco_stop; + hdlc->proto.netif_rx = cisco_rx; + hdlc->proto.type_trans = cisco_type_trans; + hdlc->proto.id = IF_PROTO_CISCO; dev->hard_start_xmit = hdlc->xmit; dev->hard_header = cisco_hard_header; dev->type = ARPHRD_CISCO; diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c index c0b5f1821043..45cbde46c34f 100644 --- a/drivers/net/wan/hdlc_fr.c +++ b/drivers/net/wan/hdlc_fr.c @@ -9,7 +9,9 @@ * as published by the Free Software Foundation. * - Theory of PVC state in DCE mode: + Theory of PVC state + + DCE mode: (exist,new) -> 0,0 when "PVC create" or if "link unreliable" 0,x -> 1,1 if "link reliable" when sending FULL STATUS @@ -17,9 +19,16 @@ (active) -> 0 when "ifconfig PVC down" or "link unreliable" or "PVC create" -> 1 when "PVC up" and (exist,new) = 1,0 + + DTE mode: + (exist,new,active) = FULL STATUS if "link reliable" + = 0, 0, 0 if "link unreliable" + No LMI: + active = open and "link reliable" + exist = new = not used + */ -#include #include #include #include @@ -36,12 +45,96 @@ #include #include +#undef DEBUG_PKT +#undef DEBUG_ECN +#undef DEBUG_LINK + +#define MAXLEN_LMISTAT 20 /* max size of status enquiry frame */ + +#define PVC_STATE_NEW 0x01 +#define PVC_STATE_ACTIVE 0x02 +#define PVC_STATE_FECN 0x08 /* FECN condition */ +#define PVC_STATE_BECN 0x10 /* BECN condition */ + + +#define FR_UI 0x03 +#define FR_PAD 0x00 + +#define NLPID_IP 0xCC +#define NLPID_IPV6 0x8E +#define NLPID_SNAP 0x80 +#define NLPID_PAD 0x00 +#define NLPID_Q933 0x08 + + +#define LMI_DLCI 0 /* LMI DLCI */ +#define LMI_PROTO 0x08 +#define LMI_CALLREF 0x00 /* Call Reference */ +#define LMI_ANSI_LOCKSHIFT 0x95 /* ANSI lockshift */ +#define LMI_REPTYPE 1 /* report type */ +#define LMI_CCITT_REPTYPE 0x51 +#define LMI_ALIVE 3 /* keep alive */ +#define LMI_CCITT_ALIVE 0x53 +#define LMI_PVCSTAT 7 /* pvc status */ +#define LMI_CCITT_PVCSTAT 0x57 +#define LMI_FULLREP 0 /* full report */ +#define LMI_INTEGRITY 1 /* link integrity report */ +#define LMI_SINGLE 2 /* single pvc report */ +#define LMI_STATUS_ENQUIRY 0x75 +#define LMI_STATUS 0x7D /* reply */ + +#define LMI_REPT_LEN 1 /* report type element length */ +#define LMI_INTEG_LEN 2 /* link integrity element length */ + +#define LMI_LENGTH 13 /* standard LMI frame length */ +#define LMI_ANSI_LENGTH 14 + + +typedef struct { +#if defined(__LITTLE_ENDIAN_BITFIELD) + unsigned ea1: 1; + unsigned cr: 1; + unsigned dlcih: 6; + + unsigned ea2: 1; + unsigned de: 1; + unsigned becn: 1; + unsigned fecn: 1; + unsigned dlcil: 4; +#else + unsigned dlcih: 6; + unsigned cr: 1; + unsigned ea1: 1; + + unsigned dlcil: 4; + unsigned fecn: 1; + unsigned becn: 1; + unsigned de: 1; + unsigned ea2: 1; +#endif +}__attribute__ ((packed)) fr_hdr; + -__inline__ pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci) +static inline u16 q922_to_dlci(u8 *hdr) +{ + return ((hdr[0] & 0xFC) << 2) | ((hdr[1] & 0xF0) >> 4); +} + + + +static inline void dlci_to_q922(u8 *hdr, u16 dlci) +{ + hdr[0] = (dlci >> 2) & 0xFC; + hdr[1] = ((dlci << 4) & 0xF0) | 0x01; +} + + + +static inline pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci) { pvc_device *pvc = hdlc->state.fr.first_pvc; - while(pvc) { + while (pvc) { if (pvc->dlci == dlci) return pvc; if (pvc->dlci > dlci) @@ -53,15 +146,15 @@ __inline__ pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci) } -__inline__ pvc_device* add_pvc(hdlc_device *hdlc, u16 dlci) +static inline pvc_device* add_pvc(hdlc_device *hdlc, u16 dlci) { pvc_device *pvc, **pvc_p = &hdlc->state.fr.first_pvc; - while(*pvc_p) { + while (*pvc_p) { if ((*pvc_p)->dlci == dlci) return *pvc_p; if ((*pvc_p)->dlci > dlci) - break; /* the listed is sorted */ + break; /* the list is sorted */ pvc_p = &(*pvc_p)->next; } @@ -78,17 +171,37 @@ __inline__ pvc_device* add_pvc(hdlc_device *hdlc, u16 dlci) } -__inline__ int pvc_is_used(pvc_device *pvc) +static inline int pvc_is_used(pvc_device *pvc) { return pvc->main != NULL || pvc->ether != NULL; } -__inline__ void delete_unused_pvcs(hdlc_device *hdlc) +static inline void pvc_carrier(int on, pvc_device *pvc) +{ + if (on) { + if (pvc->main) + if (!netif_carrier_ok(pvc->main)) + netif_carrier_on(pvc->main); + if (pvc->ether) + if (!netif_carrier_ok(pvc->ether)) + netif_carrier_on(pvc->ether); + } else { + if (pvc->main) + if (netif_carrier_ok(pvc->main)) + netif_carrier_off(pvc->main); + if (pvc->ether) + if (netif_carrier_ok(pvc->ether)) + netif_carrier_off(pvc->ether); + } +} + + +static inline void delete_unused_pvcs(hdlc_device *hdlc) { pvc_device **pvc_p = &hdlc->state.fr.first_pvc; - while(*pvc_p) { + while (*pvc_p) { if (!pvc_is_used(*pvc_p)) { pvc_device *pvc = *pvc_p; *pvc_p = pvc->next; @@ -100,7 +213,7 @@ __inline__ void delete_unused_pvcs(hdlc_device *hdlc) } -__inline__ struct net_device** get_dev_p(pvc_device *pvc, int type) +static inline struct net_device** get_dev_p(pvc_device *pvc, int type) { if (type == ARPHRD_ETHER) return &pvc->ether; @@ -109,20 +222,19 @@ __inline__ struct net_device** get_dev_p(pvc_device *pvc, int type) } -__inline__ u16 status_to_dlci(u8 *status, int *active, int *new) +static inline u16 status_to_dlci(u8 *status, int *active, int *new) { *new = (status[2] & 0x08) ? 1 : 0; *active = (status[2] & 0x02) ? 1 : 0; - return ((status[0] & 0x3F)<<4) | ((status[1] & 0x78)>>3); + return ((status[0] & 0x3F) << 4) | ((status[1] & 0x78) >> 3); } -__inline__ void dlci_to_status(u16 dlci, u8 *status, - int active, int new) +static inline void dlci_to_status(u16 dlci, u8 *status, int active, int new) { - status[0] = (dlci>>4) & 0x3F; - status[1] = ((dlci<<3) & 0x78) | 0x80; + status[0] = (dlci >> 4) & 0x3F; + status[1] = ((dlci << 3) & 0x78) | 0x80; status[2] = 0x80; if (new) @@ -138,7 +250,7 @@ static int fr_hard_header(struct sk_buff **skb_p, u16 dlci) u16 head_len; struct sk_buff *skb = *skb_p; - switch(skb->protocol) { + switch (skb->protocol) { case __constant_ntohs(ETH_P_IP): head_len = 4; skb_push(skb, head_len); @@ -204,8 +316,9 @@ static int pvc_open(struct net_device *dev) if (pvc->open_count++ == 0) { if (pvc->master->state.fr.settings.lmi == LMI_NONE) - pvc->state.active = 1; + pvc->state.active = pvc->master->carrier; + pvc_carrier(pvc->state.active, pvc); pvc->master->state.fr.dce_changed = 1; } return 0; @@ -260,7 +373,7 @@ int pvc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) } -__inline__ struct net_device_stats *pvc_get_stats(struct net_device *dev) +static inline struct net_device_stats *pvc_get_stats(struct net_device *dev) { return (struct net_device_stats *) ((char *)dev + sizeof(struct net_device)); @@ -402,6 +515,7 @@ static void fr_lmi_send(hdlc_device *hdlc, int fullrep) /* ifconfig PVC up */ if (pvc->open_count && !pvc->state.active && pvc->state.exist && !pvc->state.new) { + pvc_carrier(1, pvc); pvc->state.active = 1; fr_log_dlci_active(pvc); } @@ -423,6 +537,41 @@ static void fr_lmi_send(hdlc_device *hdlc, int fullrep) +static void fr_set_link_state(int reliable, hdlc_device *hdlc) +{ + pvc_device *pvc = hdlc->state.fr.first_pvc; + + hdlc->state.fr.reliable = reliable; + if (reliable) { + if (!netif_carrier_ok(&hdlc->netdev)) + netif_carrier_on(&hdlc->netdev); + + hdlc->state.fr.n391cnt = 0; /* Request full status */ + hdlc->state.fr.dce_changed = 1; + + if (hdlc->state.fr.settings.lmi == LMI_NONE) { + while (pvc) { /* Activate all PVCs */ + pvc_carrier(1, pvc); + pvc->state.exist = pvc->state.active = 1; + pvc->state.new = 0; + pvc = pvc->next; + } + } + } else { + if (netif_carrier_ok(&hdlc->netdev)) + netif_carrier_off(&hdlc->netdev); + + while (pvc) { /* Deactivate all PVCs */ + pvc_carrier(0, pvc); + pvc->state.exist = pvc->state.active = 0; + pvc->state.new = 0; + pvc = pvc->next; + } + } +} + + + static void fr_timer(unsigned long arg) { hdlc_device *hdlc = (hdlc_device*)arg; @@ -449,22 +598,9 @@ static void fr_timer(unsigned long arg) } if (hdlc->state.fr.reliable != reliable) { - pvc_device *pvc = hdlc->state.fr.first_pvc; - - hdlc->state.fr.reliable = reliable; printk(KERN_INFO "%s: Link %sreliable\n", hdlc_to_name(hdlc), reliable ? "" : "un"); - - if (reliable) { - hdlc->state.fr.n391cnt = 0; /* Request full status */ - hdlc->state.fr.dce_changed = 1; - } else { - while (pvc) { /* Deactivate all PVCs */ - pvc->state.exist = 0; - pvc->state.active = pvc->state.new = 0; - pvc = pvc->next; - } - } + fr_set_link_state(reliable, hdlc); } if (hdlc->state.fr.settings.dce) @@ -636,6 +772,7 @@ static int fr_lmi_recv(hdlc_device *hdlc, struct sk_buff *skb) !pvc->state.exist) { pvc->state.new = new; pvc->state.active = active; + pvc_carrier(active, pvc); fr_log_dlci_active(pvc); } } @@ -647,6 +784,7 @@ static int fr_lmi_recv(hdlc_device *hdlc, struct sk_buff *skb) while (pvc) { if (pvc->state.deleted && pvc->state.exist) { + pvc_carrier(0, pvc); pvc->state.active = pvc->state.new = 0; pvc->state.exist = 0; fr_log_dlci_active(pvc); @@ -699,7 +837,7 @@ static void fr_rx(struct sk_buff *skb) pvc = find_pvc(hdlc, dlci); if (!pvc) { -#ifdef CONFIG_HDLC_DEBUG_PKT +#ifdef DEBUG_PKT printk(KERN_INFO "%s: No PVC for received frame's DLCI %d\n", hdlc_to_name(hdlc), dlci); #endif @@ -708,7 +846,7 @@ static void fr_rx(struct sk_buff *skb) } if (pvc->state.fecn != fh->fecn) { -#ifdef CONFIG_HDLC_DEBUG_ECN +#ifdef DEBUG_ECN printk(KERN_DEBUG "%s: DLCI %d FECN O%s\n", hdlc_to_name(pvc), dlci, fh->fecn ? "N" : "FF"); #endif @@ -716,7 +854,7 @@ static void fr_rx(struct sk_buff *skb) } if (pvc->state.becn != fh->becn) { -#ifdef CONFIG_HDLC_DEBUG_ECN +#ifdef DEBUG_ECN printk(KERN_DEBUG "%s: DLCI %d BECN O%s\n", hdlc_to_name(pvc), dlci, fh->becn ? "N" : "FF"); #endif @@ -787,9 +925,14 @@ static void fr_rx(struct sk_buff *skb) -static int fr_open(hdlc_device *hdlc) +static void fr_start(hdlc_device *hdlc) { +#ifdef DEBUG_LINK + printk(KERN_DEBUG "fr_start\n"); +#endif if (hdlc->state.fr.settings.lmi != LMI_NONE) { + if (netif_carrier_ok(&hdlc->netdev)) + netif_carrier_off(&hdlc->netdev); hdlc->state.fr.last_poll = 0; hdlc->state.fr.reliable = 0; hdlc->state.fr.dce_changed = 1; @@ -806,9 +949,19 @@ static int fr_open(hdlc_device *hdlc) hdlc->state.fr.timer.data = (unsigned long)hdlc; add_timer(&hdlc->state.fr.timer); } else - hdlc->state.fr.reliable = 1; + fr_set_link_state(1, hdlc); +} - return 0; + + +static void fr_stop(hdlc_device *hdlc) +{ +#ifdef DEBUG_LINK + printk(KERN_DEBUG "fr_stop\n"); +#endif + if (hdlc->state.fr.settings.lmi != LMI_NONE) + del_timer_sync(&hdlc->state.fr.timer); + fr_set_link_state(0, hdlc); } @@ -817,22 +970,17 @@ static void fr_close(hdlc_device *hdlc) { pvc_device *pvc = hdlc->state.fr.first_pvc; - if (hdlc->state.fr.settings.lmi != LMI_NONE) - del_timer_sync(&hdlc->state.fr.timer); - - while(pvc) { /* Shutdown all PVCs for this FRAD */ + while (pvc) { /* Shutdown all PVCs for this FRAD */ if (pvc->main) dev_close(pvc->main); if (pvc->ether) dev_close(pvc->ether); - pvc->state.active = pvc->state.new = pvc->state.fecn = - pvc->state.becn = 0; - pvc->state.exist = 0; pvc = pvc->next; } } + static int fr_add_pvc(hdlc_device *hdlc, unsigned int dlci, int type) { pvc_device *pvc = NULL; @@ -900,6 +1048,7 @@ static int fr_add_pvc(hdlc_device *hdlc, unsigned int dlci, int type) return -EIO; } + dev->destructor = (void (*)(struct net_device *)) kfree; *get_dev_p(pvc, type) = dev; if (!used) { hdlc->state.fr.dce_changed = 1; @@ -924,8 +1073,7 @@ static int fr_del_pvc(hdlc_device *hdlc, unsigned int dlci, int type) if (dev->flags & IFF_UP) return -EBUSY; /* PVC in use */ - unregister_netdevice(dev); - kfree(dev); + unregister_netdevice(dev); /* the destructor will kfree(dev) */ *get_dev_p(pvc, type) = NULL; if (!pvc_is_used(pvc)) { @@ -940,24 +1088,24 @@ static int fr_del_pvc(hdlc_device *hdlc, unsigned int dlci, int type) static void fr_destroy(hdlc_device *hdlc) { - pvc_device *pvc = hdlc->state.fr.first_pvc; - while(pvc) { + pvc_device *pvc; + + pvc = hdlc->state.fr.first_pvc; + hdlc->state.fr.first_pvc = NULL; /* All PVCs destroyed */ + hdlc->state.fr.dce_pvc_count = 0; + hdlc->state.fr.dce_changed = 1; + + while (pvc) { pvc_device *next = pvc->next; - if (pvc->main) { + if (pvc->main) /* the destructor will kfree(main + ether) */ unregister_netdevice(pvc->main); - kfree(pvc->main); - } - if (pvc->ether) { + + if (pvc->ether) unregister_netdevice(pvc->ether); - kfree(pvc->ether); - } + kfree(pvc); pvc = next; } - - hdlc->state.fr.first_pvc = NULL; /* All PVCs destroyed */ - hdlc->state.fr.dce_pvc_count = 0; - hdlc->state.fr.dce_changed = 1; } @@ -1012,19 +1160,20 @@ int hdlc_fr_ioctl(hdlc_device *hdlc, struct ifreq *ifr) if (result) return result; - if (hdlc->proto != IF_PROTO_FR) { + if (hdlc->proto.id != IF_PROTO_FR) { hdlc_proto_detach(hdlc); hdlc->state.fr.first_pvc = NULL; hdlc->state.fr.dce_pvc_count = 0; } memcpy(&hdlc->state.fr.settings, &new_settings, size); - - hdlc->open = fr_open; - hdlc->stop = fr_close; - hdlc->netif_rx = fr_rx; - hdlc->type_trans = NULL; - hdlc->proto_detach = fr_destroy; - hdlc->proto = IF_PROTO_FR; + memset(&hdlc->proto, 0, sizeof(hdlc->proto)); + + hdlc->proto.close = fr_close; + hdlc->proto.start = fr_start; + hdlc->proto.stop = fr_stop; + hdlc->proto.detach = fr_destroy; + hdlc->proto.netif_rx = fr_rx; + hdlc->proto.id = IF_PROTO_FR; dev->hard_start_xmit = hdlc->xmit; dev->hard_header = NULL; dev->type = ARPHRD_FRAD; diff --git a/drivers/net/wan/hdlc_generic.c b/drivers/net/wan/hdlc_generic.c index fd0b3dfeeb19..4d150428ec89 100644 --- a/drivers/net/wan/hdlc_generic.c +++ b/drivers/net/wan/hdlc_generic.c @@ -33,7 +33,9 @@ #include -static const char* version = "HDLC support module revision 1.14"; +static const char* version = "HDLC support module revision 1.15"; + +#undef DEBUG_LINK static int hdlc_change_mtu(struct net_device *dev, int new_mtu) @@ -57,8 +59,8 @@ static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *p) { hdlc_device *hdlc = dev_to_hdlc(dev); - if (hdlc->netif_rx) - hdlc->netif_rx(skb); + if (hdlc->proto.netif_rx) + hdlc->proto.netif_rx(skb); else { hdlc->stats.rx_dropped++; /* Shouldn't happen */ dev_kfree_skb(skb); @@ -67,6 +69,103 @@ static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev, } + +void hdlc_set_carrier(int on, hdlc_device *hdlc) +{ + on = on ? 1 : 0; + +#ifdef DEBUG_LINK + printk(KERN_DEBUG "hdlc_set_carrier %i\n", on); +#endif + + spin_lock_irq(&hdlc->state_lock); + + if (hdlc->carrier == on) + goto carrier_exit; /* no change in DCD line level */ + + printk(KERN_INFO "%s: carrier %s\n", hdlc_to_name(hdlc), + on ? "ON" : "off"); + hdlc->carrier = on; + + if (!hdlc->open) + goto carrier_exit; + + if (hdlc->carrier) { + if (hdlc->proto.start) + hdlc->proto.start(hdlc); + else if (!netif_carrier_ok(&hdlc->netdev)) + netif_carrier_on(&hdlc->netdev); + + } else { /* no carrier */ + if (hdlc->proto.stop) + hdlc->proto.stop(hdlc); + else if (netif_carrier_ok(&hdlc->netdev)) + netif_carrier_off(&hdlc->netdev); + } + + carrier_exit: + spin_unlock_irq(&hdlc->state_lock); +} + + +/* Must be called by hardware driver when HDLC device is being opened */ +int hdlc_open(hdlc_device *hdlc) +{ +#ifdef DEBUG_LINK + printk(KERN_DEBUG "hdlc_open carrier %i open %i\n", + hdlc->carrier, hdlc->open); +#endif + + if (hdlc->proto.id == -1) + return -ENOSYS; /* no protocol attached */ + + if (hdlc->proto.open) { + int result = hdlc->proto.open(hdlc); + if (result) + return result; + } + + spin_lock_irq(&hdlc->state_lock); + + if (hdlc->carrier) { + if (hdlc->proto.start) + hdlc->proto.start(hdlc); + else if (!netif_carrier_ok(&hdlc->netdev)) + netif_carrier_on(&hdlc->netdev); + + } else if (netif_carrier_ok(&hdlc->netdev)) + netif_carrier_off(&hdlc->netdev); + + hdlc->open = 1; + + spin_unlock_irq(&hdlc->state_lock); + return 0; +} + + + +/* Must be called by hardware driver when HDLC device is being closed */ +void hdlc_close(hdlc_device *hdlc) +{ +#ifdef DEBUG_LINK + printk(KERN_DEBUG "hdlc_close carrier %i open %i\n", + hdlc->carrier, hdlc->open); +#endif + + spin_lock_irq(&hdlc->state_lock); + + hdlc->open = 0; + if (hdlc->carrier && hdlc->proto.stop) + hdlc->proto.stop(hdlc); + + spin_unlock_irq(&hdlc->state_lock); + + if (hdlc->proto.close) + hdlc->proto.close(hdlc); +} + + + #ifndef CONFIG_HDLC_RAW #define hdlc_raw_ioctl(hdlc, ifr) -ENOSYS #endif @@ -111,7 +210,7 @@ int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) break; default: - proto = hdlc->proto; + proto = hdlc->proto.id; } switch(proto) { @@ -141,11 +240,14 @@ int register_hdlc_device(hdlc_device *hdlc) dev->flags = IFF_POINTOPOINT | IFF_NOARP; - hdlc->proto = -1; - hdlc->proto_detach = NULL; + hdlc->proto.id = -1; + hdlc->proto.detach = NULL; + hdlc->carrier = 1; + hdlc->open = 0; + spin_lock_init(&hdlc->state_lock); result = dev_alloc_name(dev, "hdlc%d"); - if (result<0) + if (result < 0) return result; result = register_netdev(dev); @@ -171,6 +273,9 @@ MODULE_AUTHOR("Krzysztof Halasa "); MODULE_DESCRIPTION("HDLC support module"); MODULE_LICENSE("GPL v2"); +EXPORT_SYMBOL(hdlc_open); +EXPORT_SYMBOL(hdlc_close); +EXPORT_SYMBOL(hdlc_set_carrier); EXPORT_SYMBOL(hdlc_ioctl); EXPORT_SYMBOL(register_hdlc_device); EXPORT_SYMBOL(unregister_hdlc_device); diff --git a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c index 1d93f3ac14ed..7eeec068d5a2 100644 --- a/drivers/net/wan/hdlc_ppp.c +++ b/drivers/net/wan/hdlc_ppp.c @@ -9,7 +9,6 @@ * as published by the Free Software Foundation. */ -#include #include #include #include @@ -99,12 +98,12 @@ int hdlc_ppp_ioctl(hdlc_device *hdlc, struct ifreq *ifr) return result; hdlc_proto_detach(hdlc); + memset(&hdlc->proto, 0, sizeof(hdlc->proto)); - hdlc->open = ppp_open; - hdlc->stop = ppp_close; - hdlc->netif_rx = NULL; - hdlc->type_trans = ppp_type_trans; - hdlc->proto = IF_PROTO_PPP; + hdlc->proto.open = ppp_open; + hdlc->proto.close = ppp_close; + hdlc->proto.type_trans = ppp_type_trans; + hdlc->proto.id = IF_PROTO_PPP; dev->hard_start_xmit = hdlc->xmit; dev->hard_header = NULL; dev->type = ARPHRD_PPP; diff --git a/drivers/net/wan/hdlc_raw.c b/drivers/net/wan/hdlc_raw.c index 7bc89d695ecd..6c0aecc442fa 100644 --- a/drivers/net/wan/hdlc_raw.c +++ b/drivers/net/wan/hdlc_raw.c @@ -9,7 +9,6 @@ * as published by the Free Software Foundation. */ -#include #include #include #include @@ -75,12 +74,10 @@ int hdlc_raw_ioctl(hdlc_device *hdlc, struct ifreq *ifr) hdlc_proto_detach(hdlc); memcpy(&hdlc->state.raw_hdlc.settings, &new_settings, size); + memset(&hdlc->proto, 0, sizeof(hdlc->proto)); - hdlc->open = NULL; - hdlc->stop = NULL; - hdlc->netif_rx = NULL; - hdlc->type_trans = raw_type_trans; - hdlc->proto = IF_PROTO_HDLC; + hdlc->proto.type_trans = raw_type_trans; + hdlc->proto.id = IF_PROTO_HDLC; dev->hard_start_xmit = hdlc->xmit; dev->hard_header = NULL; dev->type = ARPHRD_RAWHDLC; diff --git a/drivers/net/wan/hdlc_raw_eth.c b/drivers/net/wan/hdlc_raw_eth.c index 90c69addb6d5..d91a4fc87730 100644 --- a/drivers/net/wan/hdlc_raw_eth.c +++ b/drivers/net/wan/hdlc_raw_eth.c @@ -9,7 +9,6 @@ * as published by the Free Software Foundation. */ -#include #include #include #include @@ -89,12 +88,10 @@ int hdlc_raw_eth_ioctl(hdlc_device *hdlc, struct ifreq *ifr) hdlc_proto_detach(hdlc); memcpy(&hdlc->state.raw_hdlc.settings, &new_settings, size); + memset(&hdlc->proto, 0, sizeof(hdlc->proto)); - hdlc->open = NULL; - hdlc->stop = NULL; - hdlc->netif_rx = NULL; - hdlc->type_trans = eth_type_trans; - hdlc->proto = IF_PROTO_HDLC_ETH; + hdlc->proto.type_trans = eth_type_trans; + hdlc->proto.id = IF_PROTO_HDLC_ETH; dev->hard_start_xmit = eth_tx; old_ch_mtu = dev->change_mtu; old_qlen = dev->tx_queue_len; diff --git a/drivers/net/wan/hdlc_x25.c b/drivers/net/wan/hdlc_x25.c index 53b118c5f8d5..7433c966028e 100644 --- a/drivers/net/wan/hdlc_x25.c +++ b/drivers/net/wan/hdlc_x25.c @@ -9,7 +9,6 @@ * as published by the Free Software Foundation. */ -#include #include #include #include @@ -199,12 +198,13 @@ int hdlc_x25_ioctl(hdlc_device *hdlc, struct ifreq *ifr) return result; hdlc_proto_detach(hdlc); + memset(&hdlc->proto, 0, sizeof(hdlc->proto)); - hdlc->open = x25_open; - hdlc->stop = x25_close; - hdlc->netif_rx = x25_rx; - hdlc->type_trans = NULL; - hdlc->proto = IF_PROTO_X25; + hdlc->proto.open = x25_open; + hdlc->proto.close = x25_close; + hdlc->proto.netif_rx = x25_rx; + hdlc->proto.type_trans = NULL; + hdlc->proto.id = IF_PROTO_X25; dev->hard_start_xmit = x25_xmit; dev->hard_header = NULL; dev->type = ARPHRD_X25; diff --git a/drivers/net/wan/n2.c b/drivers/net/wan/n2.c index 53e0701da0ff..7e50bc51f021 100644 --- a/drivers/net/wan/n2.c +++ b/drivers/net/wan/n2.c @@ -16,7 +16,6 @@ * SDL Inc. PPP/HDLC/CISCO driver */ -#include #include #include #include @@ -34,9 +33,12 @@ #include "hd64570.h" -static const char* version = "SDL RISCom/N2 driver version: 1.14"; +static const char* version = "SDL RISCom/N2 driver version: 1.15"; static const char* devname = "RISCom/N2"; +#undef DEBUG_PKT +#define DEBUG_RINGS + #define USE_WINDOWSIZE 16384 #define USE_BUS16BITS 1 #define CLOCK_BASE 9830400 /* 9.8304 MHz */ @@ -48,6 +50,7 @@ static const char* devname = "RISCom/N2"; #endif #define N2_IOPORTS 0x10 #define NEED_DETECT_RAM +#define NEED_SCA_MSCI_INTR #define MAX_TX_BUFFERS 10 static char *hw = NULL; /* pointer to hw=xxx command line string */ @@ -257,7 +260,7 @@ static int n2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) hdlc_device *hdlc = dev_to_hdlc(dev); port_t *port = hdlc_to_port(hdlc); -#ifdef CONFIG_HDLC_DEBUG_RINGS +#ifdef DEBUG_RINGS if (cmd == SIOCDEVPRIVATE) { sca_dump_rings(hdlc); return 0; @@ -415,7 +418,7 @@ static int __init n2_run(unsigned long io, unsigned long irq, card->buff_offset = (valid0 + valid1) * sizeof(pkt_desc) * (card->tx_ring_buffers + card->rx_ring_buffers); - printk(KERN_DEBUG "n2: RISCom/N2 %u KB RAM, IRQ%u, " + printk(KERN_INFO "n2: RISCom/N2 %u KB RAM, IRQ%u, " "using %u TX + %u RX packets rings\n", card->ram_size / 1024, card->irq, card->tx_ring_buffers, card->rx_ring_buffers); @@ -447,7 +450,7 @@ static int __init n2_run(unsigned long io, unsigned long irq, SET_MODULE_OWNER(dev); dev->irq = irq; dev->mem_start = winbase; - dev->mem_end = winbase + USE_WINDOWSIZE-1; + dev->mem_end = winbase + USE_WINDOWSIZE - 1; dev->tx_queue_len = 50; dev->do_ioctl = n2_ioctl; dev->open = n2_open; diff --git a/include/linux/hdlc.h b/include/linux/hdlc.h index 6b89e9c85f9b..94c967d945e7 100644 --- a/include/linux/hdlc.h +++ b/include/linux/hdlc.h @@ -42,6 +42,9 @@ #define LMI_ANSI 2 /* ANSI Annex D */ #define LMI_CCITT 3 /* ITU-T Annex A */ +#define HDLC_MAX_MTU 1500 /* Ethernet 1500 bytes */ +#define HDLC_MAX_MRU (HDLC_MAX_MTU + 10 + 14 + 4) /* for ETH+VLAN over FR */ + #ifdef __KERNEL__ @@ -50,78 +53,6 @@ #include #include -#define HDLC_MAX_MTU 1500 /* Ethernet 1500 bytes */ -#define HDLC_MAX_MRU (HDLC_MAX_MTU + 10 + 14 + 4) /* for ETH+VLAN over FR */ - -#define MAXLEN_LMISTAT 20 /* max size of status enquiry frame */ - -#define PVC_STATE_NEW 0x01 -#define PVC_STATE_ACTIVE 0x02 -#define PVC_STATE_FECN 0x08 /* FECN condition */ -#define PVC_STATE_BECN 0x10 /* BECN condition */ - - -#define FR_UI 0x03 -#define FR_PAD 0x00 - -#define NLPID_IP 0xCC -#define NLPID_IPV6 0x8E -#define NLPID_SNAP 0x80 -#define NLPID_PAD 0x00 -#define NLPID_Q933 0x08 - - -#define LMI_DLCI 0 /* LMI DLCI */ -#define LMI_PROTO 0x08 -#define LMI_CALLREF 0x00 /* Call Reference */ -#define LMI_ANSI_LOCKSHIFT 0x95 /* ANSI lockshift */ -#define LMI_REPTYPE 1 /* report type */ -#define LMI_CCITT_REPTYPE 0x51 -#define LMI_ALIVE 3 /* keep alive */ -#define LMI_CCITT_ALIVE 0x53 -#define LMI_PVCSTAT 7 /* pvc status */ -#define LMI_CCITT_PVCSTAT 0x57 -#define LMI_FULLREP 0 /* full report */ -#define LMI_INTEGRITY 1 /* link integrity report */ -#define LMI_SINGLE 2 /* single pvc report */ -#define LMI_STATUS_ENQUIRY 0x75 -#define LMI_STATUS 0x7D /* reply */ - -#define LMI_REPT_LEN 1 /* report type element length */ -#define LMI_INTEG_LEN 2 /* link integrity element length */ - -#define LMI_LENGTH 13 /* standard LMI frame length */ -#define LMI_ANSI_LENGTH 14 - - - -typedef struct { -#if defined(__LITTLE_ENDIAN_BITFIELD) - unsigned ea1 : 1; - unsigned cr : 1; - unsigned dlcih: 6; - - unsigned ea2 : 1; - unsigned de : 1; - unsigned becn : 1; - unsigned fecn : 1; - unsigned dlcil: 4; -#elif defined (__BIG_ENDIAN_BITFIELD) - unsigned dlcih: 6; - unsigned cr : 1; - unsigned ea1 : 1; - - unsigned dlcil: 4; - unsigned fecn : 1; - unsigned becn : 1; - unsigned de : 1; - unsigned ea2 : 1; -#else -#error "Please fix " -#endif -}__attribute__ ((packed)) fr_hdr; - - typedef struct { /* Used in Cisco and PPP mode */ u8 address; @@ -177,14 +108,25 @@ typedef struct hdlc_device_struct { /* Things below are for HDLC layer internal use only */ - int (*ioctl)(struct net_device *dev, struct ifreq *ifr, int cmd); - int (*open)(struct hdlc_device_struct *hdlc); - void (*stop)(struct hdlc_device_struct *hdlc); - void (*proto_detach)(struct hdlc_device_struct *hdlc); - void (*netif_rx)(struct sk_buff *skb); - unsigned short (*type_trans)(struct sk_buff *skb, - struct net_device *dev); - int proto; /* IF_PROTO_HDLC/CISCO/FR/etc. */ + struct { + int (*open)(struct hdlc_device_struct *hdlc); + void (*close)(struct hdlc_device_struct *hdlc); + + /* if open & DCD */ + void (*start)(struct hdlc_device_struct *hdlc); + /* if open & !DCD */ + void (*stop)(struct hdlc_device_struct *hdlc); + + void (*detach)(struct hdlc_device_struct *hdlc); + void (*netif_rx)(struct sk_buff *skb); + unsigned short (*type_trans)(struct sk_buff *skb, + struct net_device *dev); + int id; /* IF_PROTO_HDLC/CISCO/FR/etc. */ + }proto; + + int carrier; + int open; + spinlock_t state_lock; union { struct { @@ -271,26 +213,11 @@ static __inline__ const char *hdlc_to_name(hdlc_device *hdlc) } -static __inline__ u16 q922_to_dlci(u8 *hdr) -{ - return ((hdr[0] & 0xFC) << 2) | ((hdr[1] & 0xF0) >> 4); -} - - - -static __inline__ void dlci_to_q922(u8 *hdr, u16 dlci) -{ - hdr[0] = (dlci >> 2) & 0xFC; - hdr[1] = ((dlci << 4) & 0xF0) | 0x01; -} - - - static __inline__ void debug_frame(const struct sk_buff *skb) { int i; - for (i=0; ilen; i++) { + for (i=0; i < skb->len; i++) { if (i == 100) { printk("...\n"); return; @@ -301,33 +228,19 @@ static __inline__ void debug_frame(const struct sk_buff *skb) } - /* Must be called by hardware driver when HDLC device is being opened */ -static __inline__ int hdlc_open(hdlc_device *hdlc) -{ - if (hdlc->proto == -1) - return -ENOSYS; /* no protocol attached */ - - if (hdlc->open) - return hdlc->open(hdlc); - return 0; -} - - +int hdlc_open(hdlc_device *hdlc); /* Must be called by hardware driver when HDLC device is being closed */ -static __inline__ void hdlc_close(hdlc_device *hdlc) -{ - if (hdlc->stop) - hdlc->stop(hdlc); -} - +void hdlc_close(hdlc_device *hdlc); +/* Called by hardware driver when DCD line level changes */ +void hdlc_set_carrier(int on, hdlc_device *hdlc); /* May be used by hardware driver to gain control over HDLC device */ static __inline__ void hdlc_proto_detach(hdlc_device *hdlc) { - if (hdlc->proto_detach) - hdlc->proto_detach(hdlc); - hdlc->proto_detach = NULL; + if (hdlc->proto.detach) + hdlc->proto.detach(hdlc); + hdlc->proto.detach = NULL; } @@ -335,8 +248,8 @@ static __inline__ unsigned short hdlc_type_trans(struct sk_buff *skb, struct net_device *dev) { hdlc_device *hdlc = dev_to_hdlc(skb->dev); - if (hdlc->type_trans) - return hdlc->type_trans(skb, dev); + if (hdlc->proto.type_trans) + return hdlc->proto.type_trans(skb, dev); else return __constant_htons(ETH_P_HDLC); } -- cgit v1.2.3