From b7080c483f6be4463390f18a331ff36c96030d46 Mon Sep 17 00:00:00 2001 From: Jon Grimm Date: Fri, 27 Sep 2002 05:42:26 -0500 Subject: sctp: mark functions needed by testsuite as SCTP_STATIC The lksctp project implemenents a regressions suite which needs certain functions exported. SCTP_STATIC is used to compile the function as 'static' when not in the testsuite. --- include/net/sctp/sctp.h | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'include') diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index d45cdd15f939..56de3338ade2 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -103,6 +103,14 @@ #define SCTP_PROTOSW_FLAG INET_PROTOSW_PERMANENT #endif + +/* Certain internal static functions need to be exported when + * compiled into the test frame. + */ +#ifndef SCTP_STATIC +#define SCTP_STATIC static +#endif + /* * Function declarations. */ -- cgit v1.2.3 From a4cae070b155d9738ca207330b579bfec840720a Mon Sep 17 00:00:00 2001 From: Daisy Chang Date: Tue, 1 Oct 2002 09:05:12 -0500 Subject: sctp: Added the 'Unrecognized Parameter' handling. --- include/linux/sctp.h | 3 +- include/net/sctp/sm.h | 11 +- include/net/sctp/structs.h | 14 ++ net/sctp/debug.c | 2 +- net/sctp/sm_make_chunk.c | 227 +++++++++++++++++++++--- net/sctp/sm_sideeffect.c | 18 +- net/sctp/sm_statefuns.c | 427 +++++++++++++++++++++++++++++++++++---------- 7 files changed, 578 insertions(+), 124 deletions(-) (limited to 'include') diff --git a/include/linux/sctp.h b/include/linux/sctp.h index 77502f62b660..ba784913fb09 100644 --- a/include/linux/sctp.h +++ b/include/linux/sctp.h @@ -155,7 +155,7 @@ typedef struct sctp_paramhdr { typedef enum { /* RFC 2960 Section 3.3.5 */ - SCTP_PARAM_HEATBEAT_INFO = __constant_htons(1), + SCTP_PARAM_HEARTBEAT_INFO = __constant_htons(1), /* RFC 2960 Section 3.3.2.1 */ SCTP_PARAM_IPV4_ADDRESS = __constant_htons(5), SCTP_PARAM_IPV6_ADDRESS = __constant_htons(6), @@ -190,6 +190,7 @@ typedef enum { SCTP_PARAM_ACTION_SKIP_ERR = __constant_htons(0xc000), } sctp_param_action_t; +enum { SCTP_PARAM_ACTION_MASK = __constant_htons(0xc000), }; /* RFC 2960 Section 3.3.1 Payload Data (DATA) (0) */ diff --git a/include/net/sctp/sm.h b/include/net/sctp/sm.h index 5cb4858fac34..9459322a411b 100644 --- a/include/net/sctp/sm.h +++ b/include/net/sctp/sm.h @@ -215,7 +215,8 @@ sctp_chunk_t *sctp_make_init(const sctp_association_t *, int priority); sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *, const sctp_chunk_t *, - const int priority); + const int priority, + const int unkparam_len); sctp_chunk_t *sctp_make_cookie_echo(const sctp_association_t *, const sctp_chunk_t *); sctp_chunk_t *sctp_make_cookie_ack(const sctp_association_t *, @@ -304,6 +305,14 @@ void sctp_generate_t3_rtx_event(unsigned long peer); void sctp_generate_heartbeat_event(unsigned long peer); sctp_sackhdr_t *sctp_sm_pull_sack(sctp_chunk_t *); +sctp_packet_t *sctp_abort_pkt_new(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + sctp_chunk_t *chunk, + const void *payload, + size_t paylen); +sctp_packet_t *sctp_ootb_pkt_new(const sctp_association_t *asoc, + const sctp_chunk_t *chunk); +void sctp_ootb_pkt_free(sctp_packet_t *packet); sctp_cookie_param_t * sctp_pack_cookie(const sctp_endpoint_t *, const sctp_association_t *, diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 69f99bba1d9b..89898ddb0db7 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -1044,6 +1044,20 @@ sctp_association_t *sctp_endpoint_lookup_assoc(const sctp_endpoint_t *ep, sctp_endpoint_t *sctp_endpoint_is_match(sctp_endpoint_t *, const sockaddr_storage_t *); +int sctp_verify_init(const sctp_association_t *asoc, + sctp_cid_t cid, + sctp_init_chunk_t *peer_init, + sctp_chunk_t *chunk, + sctp_chunk_t **err_chunk); +int sctp_verify_param(const sctp_association_t *asoc, + sctpParam_t param, + sctp_cid_t cid, + sctp_chunk_t *chunk, + sctp_chunk_t **err_chunk); +int sctp_process_unk_param(const sctp_association_t *asoc, + sctpParam_t param, + sctp_chunk_t *chunk, + sctp_chunk_t **err_chunk); void sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid, const sockaddr_storage_t *peer_addr, sctp_init_chunk_t *peer_init, int priority); diff --git a/net/sctp/debug.c b/net/sctp/debug.c index 18f68d7b1dc5..bca2c110aa7e 100644 --- a/net/sctp/debug.c +++ b/net/sctp/debug.c @@ -97,7 +97,7 @@ const char *sctp_cname(const sctp_subtype_t cid) /* These are printable form of variable-length parameters. */ const char *sctp_param_tbl[SCTP_PARAM_ECN_CAPABLE + 1] = { "", - "PARAM_HEATBEAT_INFO", + "PARAM_HEARTBEAT_INFO", "", "", "", diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index d798822e9730..7a4f8834af61 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -223,7 +223,7 @@ nodata: sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *asoc, const sctp_chunk_t *chunk, - int priority) + int priority, int unkparam_len) { sctp_inithdr_t initack; sctp_chunk_t *retval; @@ -278,7 +278,10 @@ sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *asoc, if (!cookie) goto nomem_cookie; - chunksize = sizeof(initack) + addrs_len + cookie_len; + /* Calculate the total size of allocation, include the reserved + * space for reporting unknown parameters if it is specified. + */ + chunksize = sizeof(initack) + addrs_len + cookie_len + unkparam_len; /* Tell peer that we'll do ECN only if peer advertised such cap. */ if (asoc->peer.ecn_capable) @@ -883,28 +886,48 @@ nodata: return retval; } +/* Create an Operation Error chunk with the specified space reserved. + * This routine can be used for containing multiple causes in the chunk. + */ +sctp_chunk_t *sctp_make_op_error_space(const sctp_association_t *asoc, + const sctp_chunk_t *chunk, + size_t size) +{ + sctp_chunk_t *retval; + + retval = sctp_make_chunk(asoc, SCTP_CID_ERROR, 0, + sizeof(sctp_errhdr_t) + size); + if (!retval) + goto nodata; + + /* RFC 2960 6.4 Multi-homed SCTP Endpoints + * + * An endpoint SHOULD transmit reply chunks (e.g., SACK, + * HEARTBEAT ACK, etc.) to the same destination transport + * address from which it received the DATA or control chunk + * to which it is replying. + * + */ + if (chunk) + retval->transport = chunk->transport; + + nodata: + return retval; + +} + /* Create an Operation Error chunk. */ sctp_chunk_t *sctp_make_op_error(const sctp_association_t *asoc, const sctp_chunk_t *chunk, __u16 cause_code, const void *payload, size_t paylen) { - sctp_chunk_t *retval = sctp_make_chunk(asoc, SCTP_CID_ERROR, 0, - sizeof(sctp_errhdr_t) + paylen); + sctp_chunk_t *retval = sctp_make_op_error_space(asoc, chunk, paylen); if (!retval) goto nodata; - sctp_init_cause(retval, cause_code, payload, paylen); - /* RFC 2960 6.4 Multi-homed SCTP Endpoints - * - * An endpoint SHOULD transmit reply chunks (e.g., SACK, - * HEARTBEAT ACK, * etc.) to the same destination transport - * address from which it * received the DATA or control chunk - * to which it is replying. - */ - if (chunk) - retval->transport = chunk->transport; + sctp_init_cause(retval, cause_code, payload, paylen); nodata: return retval; @@ -1405,6 +1428,167 @@ malformed: * 3rd Level Abstractions ********************************************************************/ +/* Verify the INIT packet before we process it. */ +int sctp_verify_init(const sctp_association_t *asoc, + sctp_cid_t cid, + sctp_init_chunk_t *peer_init, + sctp_chunk_t *chunk, + sctp_chunk_t **err_chk_p) +{ + sctpParam_t param; + uint8_t *end; + + + /* FIXME - Verify the fixed fields of the INIT chunk. Also, verify + * the mandatory parameters somewhere here and generate either the + * "Missing mandatory parameter" error or the "Invalid mandatory + * parameter" error. */ + + /* Find unrecognized parameters. */ + + end = ((uint8_t *)peer_init + ntohs(peer_init->chunk_hdr.length)); + + for (param.v = peer_init->init_hdr.params; + param.v < end; + param.v += WORD_ROUND(ntohs(param.p->length))) { + + if (!sctp_verify_param(asoc, param, cid, chunk, err_chk_p)) + return 0; + + } /* for (loop through all parameters) */ + + return 1; + + +} + + +/* Find unrecognized parameters in the chunk. + * Return values: + * 0 - discard the chunk + * 1 - continue with the chunk + */ +int sctp_verify_param(const sctp_association_t *asoc, + sctpParam_t param, + sctp_cid_t cid, + sctp_chunk_t *chunk, + sctp_chunk_t **err_chk_p) +{ + int retval = 1; + + /* FIXME - This routine is not looking at each parameter per the + * chunk type, i.e., unrecognized parameters should be further + * identified based on the chunk id. + */ + + switch (param.p->type) { + case SCTP_PARAM_IPV4_ADDRESS: + case SCTP_PARAM_IPV6_ADDRESS: + case SCTP_PARAM_COOKIE_PRESERVATIVE: + /* FIXME - If we don't support the host name parameter, we should + * generate an error for this - Unresolvable address. + */ + case SCTP_PARAM_HOST_NAME_ADDRESS: + case SCTP_PARAM_SUPPORTED_ADDRESS_TYPES: + case SCTP_PARAM_STATE_COOKIE: + case SCTP_PARAM_HEARTBEAT_INFO: + case SCTP_PARAM_UNRECOGNIZED_PARAMETERS: + case SCTP_PARAM_ECN_CAPABLE: + break; + default: + SCTP_DEBUG_PRINTK("Unrecognized param: %d for chunk %d.\n", + ntohs(param.p->type), cid); + return sctp_process_unk_param(asoc, param, chunk, err_chk_p); + + break; + } + return retval; + +} + +/* RFC 3.2.1 & the Implementers Guide 2.2. + * + * The Parameter Types are encoded such that the + * highest-order two bits specify the action that must be + * taken if the processing endpoint does not recognize the + * Parameter Type. + * + * 00 - Stop processing this SCTP chunk and discard it, + * do not process any further chunks within it. + * + * 01 - Stop processing this SCTP chunk and discard it, + * do not process any further chunks within it, and report + * the unrecognized parameter in an 'Unrecognized + * Parameter Type' (in either an ERROR or in the INIT ACK). + * + * 10 - Skip this parameter and continue processing. + * + * 11 - Skip this parameter and continue processing but + * report the unrecognized parameter in an + * 'Unrecognized Parameter Type' (in either an ERROR or in + * the INIT ACK). + * + * Return value: + * 0 - discard the chunk + * 1 - continue with the chunk + */ +int sctp_process_unk_param(const sctp_association_t *asoc, + sctpParam_t param, + sctp_chunk_t *chunk, + sctp_chunk_t **err_chk_p) +{ + int retval = 1; + + switch (param.p->type & SCTP_PARAM_ACTION_MASK) { + case SCTP_PARAM_ACTION_DISCARD: + retval = 0; + break; + case SCTP_PARAM_ACTION_DISCARD_ERR: + retval = 0; + /* Make an ERROR chunk, preparing enough room for + * returning multiple unknown parameters. + */ + if (NULL == *err_chk_p) + *err_chk_p = sctp_make_op_error_space(asoc, chunk, + ntohs(chunk->chunk_hdr->length)); + + if (*err_chk_p) + sctp_init_cause(*err_chk_p, SCTP_ERROR_UNKNOWN_PARAM, + (const void *)param.p, + WORD_ROUND(ntohs(param.p->length))); + + break; + case SCTP_PARAM_ACTION_SKIP: + break; + case SCTP_PARAM_ACTION_SKIP_ERR: + /* Make an ERROR chunk, preparing enough room for + * returning multiple unknown parameters. + */ + if (NULL == *err_chk_p) + *err_chk_p = sctp_make_op_error_space(asoc, chunk, + ntohs(chunk->chunk_hdr->length)); + + if (*err_chk_p) { + sctp_init_cause(*err_chk_p, SCTP_ERROR_UNKNOWN_PARAM, + (const void *)param.p, + WORD_ROUND(ntohs(param.p->length))); + } else { + /* If there is no memory for generating the ERROR + * report as specified, an ABORT will be triggered + * to the peer and the association won't be established. + */ + retval = 0; + } + + break; + default: + break; + } + + return retval; + +} + /* Unpack the parameters in an INIT packet. * FIXME: There is no return status to allow callers to do * error handling. @@ -1609,9 +1793,9 @@ int sctp_process_param(sctp_association_t *asoc, sctpParam_t param, asoc->peer.cookie = param.cookie->body; break; - case SCTP_PARAM_HEATBEAT_INFO: + case SCTP_PARAM_HEARTBEAT_INFO: SCTP_DEBUG_PRINTK("unimplemented " - "SCTP_PARAM_HEATBEAT_INFO\n"); + "SCTP_PARAM_HEARTBEAT_INFO\n"); break; case SCTP_PARAM_UNRECOGNIZED_PARAMETERS: @@ -1624,14 +1808,13 @@ int sctp_process_param(sctp_association_t *asoc, sctpParam_t param, break; default: + /* Any unrecognized parameters should have been caught + * and handled by sctp_verify_param() which should be + * called prior to this routine. Simply log the error + * here. + */ SCTP_DEBUG_PRINTK("Ignoring param: %d for association %p.\n", ntohs(param.p->type), asoc); - /* FIXME: The entire parameter processing really needs - * redesigned. For now, always return success as doing - * otherwise craters the system. - */ - retval = 1; - break; }; diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index 457e669aa17b..f6c217fb68a6 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -327,7 +327,8 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, case SCTP_CMD_GEN_INIT_ACK: /* Generate an INIT ACK chunk. */ - new_obj = sctp_make_init_ack(asoc, chunk, GFP_ATOMIC); + new_obj = sctp_make_init_ack(asoc, chunk, GFP_ATOMIC, + 0); if (!new_obj) goto nomem; @@ -344,10 +345,20 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, case SCTP_CMD_GEN_COOKIE_ECHO: /* Generate a COOKIE ECHO chunk. */ new_obj = sctp_make_cookie_echo(asoc, chunk); - if (!new_obj) + if (!new_obj) { + if (command->obj.ptr) + sctp_free_chunk(command->obj.ptr); goto nomem; + } sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(new_obj)); + + /* If there is an ERROR chunk to be sent along with + * the COOKIE_ECHO, send it, too. + */ + if (command->obj.ptr) + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, + SCTP_CHUNK(command->obj.ptr)); break; case SCTP_CMD_GEN_SHUTDOWN: @@ -397,8 +408,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, /* Send a full packet to our peer. */ packet = command->obj.ptr; sctp_packet_transmit(packet); - sctp_transport_free(packet->transport); - sctp_packet_free(packet); + sctp_ootb_pkt_free(packet); break; case SCTP_CMD_RETRAN: diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 6226b68336e9..b62f15cbff44 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -194,6 +194,10 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep, sctp_chunk_t *chunk = arg; sctp_chunk_t *repl; sctp_association_t *new_asoc; + sctp_chunk_t *err_chunk; + sctp_packet_t *packet; + sctp_unrecognized_param_t *unk_param; + int len; /* If the packet is an OOTB packet which is temporarily on the * control endpoint, responding with an ABORT. @@ -208,6 +212,37 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep, if (!chunk->singleton) return SCTP_DISPOSITION_VIOLATION; + /* Verify the INIT chunk before processing it. */ + err_chunk = NULL; + if (!sctp_verify_init(asoc, chunk->chunk_hdr->type, + (sctp_init_chunk_t *)chunk->chunk_hdr, chunk, + &err_chunk)) { + /* This chunk contains fatal error. It is to be discarded. + * Send an ABORT, with causes if there is any. + */ + if (err_chunk) { + packet = sctp_abort_pkt_new(ep, asoc, arg, + (__u8 *)(err_chunk->chunk_hdr) + + sizeof(sctp_chunkhdr_t), + ntohs(err_chunk->chunk_hdr->length) - + sizeof(sctp_chunkhdr_t)); + + sctp_free_chunk(err_chunk); + + if (packet) { + sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT, + SCTP_PACKET(packet)); + return SCTP_DISPOSITION_CONSUME; + } else { + return SCTP_DISPOSITION_NOMEM; + } + } else { + return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, + commands); + } + + } + /* Grab the INIT header. */ chunk->subh.init_hdr = (sctp_inithdr_t *)chunk->skb->data; @@ -230,10 +265,41 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep, sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc)); /* B) "Z" shall respond immediately with an INIT ACK chunk. */ - repl = sctp_make_init_ack(new_asoc, chunk, GFP_ATOMIC); + + /* If there are errors need to be reported for unknown parameters, + * make sure to reserve enough room in the INIT ACK for them. + */ + len = 0; + if (err_chunk) + len = ntohs(err_chunk->chunk_hdr->length) - + sizeof(sctp_chunkhdr_t); + + repl = sctp_make_init_ack(new_asoc, chunk, GFP_ATOMIC, len); if (!repl) goto nomem_ack; + /* If there are errors need to be reported for unknown parameters, + * include them in the outgoing INIT ACK as "Unrecognized parameter" + * parameter. + */ + if (err_chunk) { + /* Get the "Unrecognized parameter" parameter(s) out of the + * ERROR chunk generated by sctp_verify_init(). Since the + * error cause code for "unknown parameter" and the + * "Unrecognized parameter" type is the same, we can + * construct the parameters in INIT ACK by copying the + * ERROR causes over. + */ + unk_param = (sctp_unrecognized_param_t *) + ((__u8 *)(err_chunk->chunk_hdr) + + sizeof(sctp_chunkhdr_t)); + /* Replace the cause code with the "Unrecognized parameter" + * parameter type. + */ + sctp_addto_chunk(repl, len, unk_param); + sctp_free_chunk(err_chunk); + } + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); /* @@ -248,6 +314,9 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep, nomem_ack: sctp_association_free(new_asoc); + if (err_chunk) + sctp_free_chunk(err_chunk); + nomem: return SCTP_DISPOSITION_NOMEM; } @@ -289,6 +358,10 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const sctp_endpoint_t *ep, sctp_chunk_t *chunk = arg; sctp_init_chunk_t *initchunk; __u32 init_tag; + sctp_chunk_t *err_chunk; + sctp_packet_t *packet; + sctp_disposition_t ret; + /* 6.10 Bundling * An endpoint MUST NOT bundle INIT, INIT ACK or @@ -319,6 +392,49 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const sctp_endpoint_t *ep, return SCTP_DISPOSITION_DELETE_TCB; } + /* Verify the INIT chunk before processing it. */ + err_chunk = NULL; + if (!sctp_verify_init(asoc, chunk->chunk_hdr->type, + (sctp_init_chunk_t *)chunk->chunk_hdr, chunk, + &err_chunk)) { + /* This chunk contains fatal error. It is to be discarded. + * Send an ABORT, with causes if there is any. + */ + if (err_chunk) { + packet = sctp_abort_pkt_new(ep, asoc, arg, + (__u8 *)(err_chunk->chunk_hdr) + + sizeof(sctp_chunkhdr_t), + ntohs(err_chunk->chunk_hdr->length) - + sizeof(sctp_chunkhdr_t)); + + sctp_free_chunk(err_chunk); + + if (packet) { + sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT, + SCTP_PACKET(packet)); + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, + SCTP_STATE(SCTP_STATE_CLOSED)); + sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, + SCTP_NULL()); + return SCTP_DISPOSITION_CONSUME; + } else { + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, + SCTP_STATE(SCTP_STATE_CLOSED)); + sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, + SCTP_NULL()); + return SCTP_DISPOSITION_NOMEM; + } + } else { + ret = sctp_sf_tabort_8_4_8(ep, asoc, type, arg, + commands); + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, + SCTP_STATE(SCTP_STATE_CLOSED)); + sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, + SCTP_NULL()); + return ret; + } + } + /* Tag the variable length paramters. Note that we never * convert the parameters in an INIT chunk. */ @@ -345,7 +461,12 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const sctp_endpoint_t *ep, /* 5.1 C) "A" shall then send the State Cookie received in the * INIT ACK chunk in a COOKIE ECHO chunk, ... */ - sctp_add_cmd_sf(commands, SCTP_CMD_GEN_COOKIE_ECHO, SCTP_NULL()); + /* If there is any errors to report, send the ERROR chunk generated + * for unknown parameters as well. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_GEN_COOKIE_ECHO, + SCTP_CHUNK(err_chunk)); + return SCTP_DISPOSITION_CONSUME; nomem: @@ -579,7 +700,7 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const sctp_endpoint_t *ep, * HEARTBEAT is sent (see Section 8.3). */ - hbinfo.param_hdr.type = SCTP_PARAM_HEATBEAT_INFO; + hbinfo.param_hdr.type = SCTP_PARAM_HEARTBEAT_INFO; hbinfo.param_hdr.length = htons(sizeof(sctp_sender_hb_info_t)); hbinfo.daddr = transport->ipaddr; hbinfo.sent_at = jiffies; @@ -852,6 +973,11 @@ static sctp_disposition_t sctp_sf_do_unexpected_init( sctp_chunk_t *chunk = arg; sctp_chunk_t *repl; sctp_association_t *new_asoc; + sctp_chunk_t *err_chunk; + sctp_packet_t *packet; + sctp_unrecognized_param_t *unk_param; + int len; + /* 6.10 Bundling * An endpoint MUST NOT bundle INIT, INIT ACK or @@ -866,6 +992,36 @@ static sctp_disposition_t sctp_sf_do_unexpected_init( /* Tag the variable length parameters. */ chunk->param_hdr.v = skb_pull(chunk->skb, sizeof(sctp_inithdr_t)); + /* Verify the INIT chunk before processing it. */ + err_chunk = NULL; + if (!sctp_verify_init(asoc, chunk->chunk_hdr->type, + (sctp_init_chunk_t *)chunk->chunk_hdr, chunk, + &err_chunk)) { + /* This chunk contains fatal error. It is to be discarded. + * Send an ABORT, with causes if there is any. + */ + if (err_chunk) { + packet = sctp_abort_pkt_new(ep, asoc, arg, + (__u8 *)(err_chunk->chunk_hdr) + + sizeof(sctp_chunkhdr_t), + ntohs(err_chunk->chunk_hdr->length) - + sizeof(sctp_chunkhdr_t)); + + sctp_free_chunk(err_chunk); + + if (packet) { + sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT, + SCTP_PACKET(packet)); + return SCTP_DISPOSITION_CONSUME; + } else { + return SCTP_DISPOSITION_NOMEM; + } + } else { + return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, + commands); + } + } + /* * Other parameters for the endpoint SHOULD be copied from the * existing parameters of the association (e.g. number of @@ -887,10 +1043,41 @@ static sctp_disposition_t sctp_sf_do_unexpected_init( sctp_tietags_populate(new_asoc, asoc); /* B) "Z" shall respond immediately with an INIT ACK chunk. */ - repl = sctp_make_init_ack(new_asoc, chunk, GFP_ATOMIC); + + /* If there are errors need to be reported for unknown parameters, + * make sure to reserve enough room in the INIT ACK for them. + */ + len = 0; + if (err_chunk) { + len = ntohs(err_chunk->chunk_hdr->length) - + sizeof(sctp_chunkhdr_t); + } + repl = sctp_make_init_ack(new_asoc, chunk, GFP_ATOMIC, len); if (!repl) goto nomem; + /* If there are errors need to be reported for unknown parameters, + * include them in the outgoing INIT ACK as "Unrecognized parameter" + * parameter. + */ + if (err_chunk) { + /* Get the "Unrecognized parameter" parameter(s) out of the + * ERROR chunk generated by sctp_verify_init(). Since the + * error cause code for "unknown parameter" and the + * "Unrecognized parameter" type is the same, we can + * construct the parameters in INIT ACK by copying the + * ERROR causes over. + */ + unk_param = (sctp_unrecognized_param_t *) + ((__u8 *)(err_chunk->chunk_hdr) + + sizeof(sctp_chunkhdr_t)); + /* Replace the cause code with the "Unrecognized parameter" + * parameter type. + */ + sctp_addto_chunk(repl, len, unk_param); + sctp_free_chunk(err_chunk); + } + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc)); sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); @@ -903,6 +1090,9 @@ static sctp_disposition_t sctp_sf_do_unexpected_init( return SCTP_DISPOSITION_CONSUME; nomem: + if (err_chunk) + sctp_free_chunk(err_chunk); + return SCTP_DISPOSITION_NOMEM; } @@ -2330,60 +2520,35 @@ sctp_disposition_t sctp_sf_tabort_8_4_8(const sctp_endpoint_t *ep, sctp_cmd_seq_t *commands) { sctp_packet_t *packet = NULL; - sctp_transport_t *transport = NULL; sctp_chunk_t *chunk = arg; sctp_chunk_t *abort; - __u16 sport; - __u16 dport; - __u32 vtag; - /* Grub in chunk and endpoint for kewl bitz. */ - sport = ntohs(chunk->sctp_hdr->dest); - dport = ntohs(chunk->sctp_hdr->source); - /* -- Make sure the ABORT packet's V-tag is the same as the - * inbound packet if no association exists, otherwise use - * the peer's vtag. - */ - if (asoc) - vtag = asoc->peer.i.init_tag; - else - vtag = ntohl(chunk->sctp_hdr->vtag); - - /* Make a transport for the bucket, Eliza... */ - transport = sctp_transport_new(sctp_source(chunk), GFP_ATOMIC); - if (!transport) - goto nomem; - - /* Make a packet for the ABORT to go into. */ - packet = t_new(sctp_packet_t, GFP_ATOMIC); - if (!packet) - goto nomem_packet; - - packet = sctp_packet_init(packet, transport, sport, dport); - packet = sctp_packet_config(packet, vtag, 0, NULL); - - /* Make an ABORT. - * This will set the T bit since we have no association. - */ - abort = sctp_make_abort(NULL, chunk, 0); - if (!abort) - goto nomem_chunk; - - /* Set the skb to the belonging sock for accounting. */ - abort->skb->sk = ep->base.sk; + + packet = sctp_ootb_pkt_new(asoc, chunk); + + if (packet) { + /* Make an ABORT. The T bit will be set if the asoc + * is NULL. + */ + abort = sctp_make_abort(asoc, chunk, 0); + if (!abort) { + sctp_ootb_pkt_free(packet); + return SCTP_DISPOSITION_NOMEM; + } - sctp_packet_append_chunk(packet, abort); - sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT, SCTP_PACKET(packet)); - return SCTP_DISPOSITION_DISCARD; + /* Set the skb to the belonging sock for accounting. */ + abort->skb->sk = ep->base.sk; -nomem_chunk: - sctp_packet_free(packet); + sctp_packet_append_chunk(packet, abort); + + sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT, + SCTP_PACKET(packet)); -nomem_packet: - sctp_transport_free(transport); + return SCTP_DISPOSITION_CONSUME; + } -nomem: return SCTP_DISPOSITION_NOMEM; + } /* @@ -2560,59 +2725,35 @@ sctp_disposition_t sctp_sf_shut_8_4_5(const sctp_endpoint_t *ep, sctp_cmd_seq_t *commands) { sctp_packet_t *packet = NULL; - sctp_transport_t *transport = NULL; sctp_chunk_t *chunk = arg; sctp_chunk_t *shut; - __u16 sport; - __u16 dport; - __u32 vtag; - - /* Grub in chunk and endpoint for kewl bitz. */ - sport = ntohs(chunk->sctp_hdr->dest); - dport = ntohs(chunk->sctp_hdr->source); - - /* Make sure the ABORT packet's V-tag is the same as the - * inbound packet if no association exists, otherwise use - * the peer's vtag. - */ - vtag = ntohl(chunk->sctp_hdr->vtag); - - /* Make a transport for the bucket, Eliza... */ - transport = sctp_transport_new(sctp_source(chunk), GFP_ATOMIC); - if (!transport) - goto nomem; - - /* Make a packet for the ABORT to go into. */ - packet = t_new(sctp_packet_t, GFP_ATOMIC); - if (!packet) - goto nomem_packet; - - packet = sctp_packet_init(packet, transport, sport, dport); - packet = sctp_packet_config(packet, vtag, 0, NULL); - - /* Make an ABORT. - * This will set the T bit since we have no association. - */ - shut = sctp_make_shutdown_complete(NULL, chunk); - if (!shut) - goto nomem_chunk; - /* Set the skb to the belonging sock for accounting. */ - shut->skb->sk = ep->base.sk; - - sctp_packet_append_chunk(packet, shut); - sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT, SCTP_PACKET(packet)); + + packet = sctp_ootb_pkt_new(asoc, chunk); + + if (packet) { + /* Make an SHUTDOWN_COMPLETE. + * The T bit will be set if the asoc is NULL. + */ + shut = sctp_make_shutdown_complete(asoc, chunk); + if (!shut) { + sctp_ootb_pkt_free(packet); + return SCTP_DISPOSITION_NOMEM; + } - return SCTP_DISPOSITION_CONSUME; + /* Set the skb to the belonging sock for accounting. */ + shut->skb->sk = ep->base.sk; -nomem_chunk: - sctp_packet_free(packet); + sctp_packet_append_chunk(packet, shut); + + sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT, + SCTP_PACKET(packet)); -nomem_packet: - sctp_transport_free(transport); + return SCTP_DISPOSITION_CONSUME; + } -nomem: return SCTP_DISPOSITION_NOMEM; + } /* * Process an unknown chunk. @@ -3949,3 +4090,99 @@ sctp_sackhdr_t *sctp_sm_pull_sack(sctp_chunk_t *chunk) skb_pull(chunk->skb, (num_blocks + num_dup_tsns) * sizeof(__u32)); return sack; } + +/* Create an ABORT packet to be sent as a response, with the specified + * error causes. + */ +sctp_packet_t *sctp_abort_pkt_new(const sctp_endpoint_t *ep, + const sctp_association_t *asoc, + sctp_chunk_t *chunk, + const void *payload, + size_t paylen) +{ + sctp_packet_t *packet; + sctp_chunk_t *abort; + + + packet = sctp_ootb_pkt_new(asoc, chunk); + + if (packet) { + /* Make an ABORT. + * The T bit will be set if the asoc is NULL. + */ + abort = sctp_make_abort(asoc, chunk, paylen); + if (!abort) { + sctp_ootb_pkt_free(packet); + return NULL; + } + /* Add specified error causes, i.e., payload, to the + * end of the chunk. + */ + sctp_addto_chunk(abort, paylen, payload); + + /* Set the skb to the belonging sock for accounting. */ + abort->skb->sk = ep->base.sk; + + sctp_packet_append_chunk(packet, abort); + + } + + return packet; + +} + +/* Allocate a packet for responding in the OOTB conditions. */ +sctp_packet_t *sctp_ootb_pkt_new(const sctp_association_t *asoc, + const sctp_chunk_t *chunk) +{ + sctp_packet_t *packet; + sctp_transport_t *transport; + __u16 sport; + __u16 dport; + __u32 vtag; + + + /* Get the source and destination port from the inbound packet. */ + sport = ntohs(chunk->sctp_hdr->dest); + dport = ntohs(chunk->sctp_hdr->source); + + /* The V-tag is going to be the same as the inbound packet if no + * association exists, otherwise, use the peer's vtag. + */ + if (asoc) { + vtag = asoc->peer.i.init_tag; + } else { + vtag = ntohl(chunk->sctp_hdr->vtag); + } + + /* Make a transport for the bucket, Eliza... */ + transport = sctp_transport_new(sctp_source(chunk), GFP_ATOMIC); + + if (!transport) + goto nomem; + + /* Allocate a new packet for sending the response. */ + packet = t_new(sctp_packet_t, GFP_ATOMIC); + if (!packet) + goto nomem_packet; + + packet = sctp_packet_init(packet, transport, sport, dport); + packet = sctp_packet_config(packet, vtag, 0, NULL); + + return packet; + +nomem_packet: + sctp_transport_free(transport); +nomem: + return NULL; + +} + +/* Free the packet allocated earlier for responding in the OOTB condition. */ +void sctp_ootb_pkt_free(sctp_packet_t *packet) +{ + + sctp_transport_free(packet->transport); + sctp_packet_free(packet); + +} -- cgit v1.2.3 From d5804f1bcba6d5d90b4a1e19bc617fed8d9e0324 Mon Sep 17 00:00:00 2001 From: Daisy Chang Date: Wed, 2 Oct 2002 05:13:14 -0500 Subject: Remove more excessive spaces. --- include/linux/sctp.h | 16 ++++++++-------- include/net/sctp/structs.h | 16 ++++++++-------- net/sctp/sm_make_chunk.c | 6 +++--- net/sctp/sm_statefuns.c | 2 +- 4 files changed, 20 insertions(+), 20 deletions(-) (limited to 'include') diff --git a/include/linux/sctp.h b/include/linux/sctp.h index ba784913fb09..1d54c9488601 100644 --- a/include/linux/sctp.h +++ b/include/linux/sctp.h @@ -155,15 +155,15 @@ typedef struct sctp_paramhdr { typedef enum { /* RFC 2960 Section 3.3.5 */ - SCTP_PARAM_HEARTBEAT_INFO = __constant_htons(1), + SCTP_PARAM_HEARTBEAT_INFO = __constant_htons(1), /* RFC 2960 Section 3.3.2.1 */ - SCTP_PARAM_IPV4_ADDRESS = __constant_htons(5), - SCTP_PARAM_IPV6_ADDRESS = __constant_htons(6), - SCTP_PARAM_STATE_COOKIE = __constant_htons(7), - SCTP_PARAM_UNRECOGNIZED_PARAMETERS = __constant_htons(8), - SCTP_PARAM_COOKIE_PRESERVATIVE = __constant_htons(9), - SCTP_PARAM_HOST_NAME_ADDRESS = __constant_htons(11), - SCTP_PARAM_SUPPORTED_ADDRESS_TYPES = __constant_htons(12), + SCTP_PARAM_IPV4_ADDRESS = __constant_htons(5), + SCTP_PARAM_IPV6_ADDRESS = __constant_htons(6), + SCTP_PARAM_STATE_COOKIE = __constant_htons(7), + SCTP_PARAM_UNRECOGNIZED_PARAMETERS = __constant_htons(8), + SCTP_PARAM_COOKIE_PRESERVATIVE = __constant_htons(9), + SCTP_PARAM_HOST_NAME_ADDRESS = __constant_htons(11), + SCTP_PARAM_SUPPORTED_ADDRESS_TYPES = __constant_htons(12), SCTP_PARAM_ECN_CAPABLE = __constant_htons(0x8000), /* Add-IP Extension. Section 3.2 */ diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 89898ddb0db7..c3f11bdf3aeb 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -1044,15 +1044,15 @@ sctp_association_t *sctp_endpoint_lookup_assoc(const sctp_endpoint_t *ep, sctp_endpoint_t *sctp_endpoint_is_match(sctp_endpoint_t *, const sockaddr_storage_t *); -int sctp_verify_init(const sctp_association_t *asoc, - sctp_cid_t cid, - sctp_init_chunk_t *peer_init, - sctp_chunk_t *chunk, +int sctp_verify_init(const sctp_association_t *asoc, + sctp_cid_t cid, + sctp_init_chunk_t *peer_init, + sctp_chunk_t *chunk, sctp_chunk_t **err_chunk); -int sctp_verify_param(const sctp_association_t *asoc, - sctpParam_t param, - sctp_cid_t cid, - sctp_chunk_t *chunk, +int sctp_verify_param(const sctp_association_t *asoc, + sctpParam_t param, + sctp_cid_t cid, + sctp_chunk_t *chunk, sctp_chunk_t **err_chunk); int sctp_process_unk_param(const sctp_association_t *asoc, sctpParam_t param, diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index b3333a8fa182..74c795b964f5 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -886,7 +886,7 @@ nodata: return retval; } -/* Create an Operation Error chunk with the specified space reserved. +/* Create an Operation Error chunk with the specified space reserved. * This routine can be used for containing multiple causes in the chunk. */ sctp_chunk_t *sctp_make_op_error_space(const sctp_association_t *asoc, @@ -1511,7 +1511,7 @@ int sctp_verify_param(const sctp_association_t *asoc, * 00 - Stop processing this SCTP chunk and discard it, * do not process any further chunks within it. * - * 01 - Stop processing this SCTP chunk and discard it, + * 01 - Stop processing this SCTP chunk and discard it, * do not process any further chunks within it, and report * the unrecognized parameter in an 'Unrecognized * Parameter Type' (in either an ERROR or in the INIT ACK). @@ -1549,7 +1549,7 @@ int sctp_process_unk_param(const sctp_association_t *asoc, if (*err_chk_p) sctp_init_cause(*err_chk_p, SCTP_ERROR_UNKNOWN_PARAM, - (const void *)param.p, + (const void *)param.p, WORD_ROUND(ntohs(param.p->length))); break; diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index ed1bc0c0d535..9b6138f8f8dc 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -2741,7 +2741,7 @@ sctp_disposition_t sctp_sf_shut_8_4_5(const sctp_endpoint_t *ep, shut->skb->sk = ep->base.sk; sctp_packet_append_chunk(packet, shut); - + sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT, SCTP_PACKET(packet)); -- cgit v1.2.3 From 25587b0087ba4c0c29279a068c6433d9a4368006 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Fri, 4 Oct 2002 05:17:53 -0700 Subject: [NET]: Remove net_call_rx_atomic. --- include/linux/netdevice.h | 1 - net/bridge/br.c | 12 ++++++------ net/core/dev.c | 14 -------------- net/netsyms.c | 1 - 4 files changed, 6 insertions(+), 22 deletions(-) (limited to 'include') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 93b4d5f1e64d..f2c8daf526aa 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -587,7 +587,6 @@ static inline void dev_kfree_skb_any(struct sk_buff *skb) dev_kfree_skb(skb); } -extern void net_call_rx_atomic(void (*fn)(void)); #define HAVE_NETIF_RX 1 extern int netif_rx(struct sk_buff *skb); #define HAVE_NETIF_RECEIVE_SKB 1 diff --git a/net/bridge/br.c b/net/bridge/br.c index c4a03bd392b0..2af745df791f 100644 --- a/net/bridge/br.c +++ b/net/bridge/br.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "br_private.h" @@ -55,11 +56,6 @@ static int __init br_init(void) return 0; } -static void __br_clear_frame_hook(void) -{ - br_handle_frame_hook = NULL; -} - static void __br_clear_ioctl_hook(void) { br_ioctl_hook = NULL; @@ -69,7 +65,11 @@ static void __exit br_deinit(void) { unregister_netdevice_notifier(&br_device_notifier); br_call_ioctl_atomic(__br_clear_ioctl_hook); - net_call_rx_atomic(__br_clear_frame_hook); + + br_write_lock_bh(BR_NETPROTO_LOCK); + br_handle_frame_hook = NULL; + br_write_unlock_bh(BR_NETPROTO_LOCK); + #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) br_fdb_get_hook = NULL; br_fdb_put_hook = NULL; diff --git a/net/core/dev.c b/net/core/dev.c index 8ed6cb8b6457..a1f8b13b0898 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1374,20 +1374,6 @@ static void net_tx_action(struct softirq_action *h) } } -/** - * net_call_rx_atomic - * @fn: function to call - * - * Make a function call that is atomic with respect to the protocol - * layers. - */ -void net_call_rx_atomic(void (*fn)(void)) -{ - br_write_lock_bh(BR_NETPROTO_LOCK); - fn(); - br_write_unlock_bh(BR_NETPROTO_LOCK); -} - #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) int (*br_handle_frame_hook)(struct sk_buff *skb) = NULL; #endif diff --git a/net/netsyms.c b/net/netsyms.c index 463f6749b027..1a77dc66baa6 100644 --- a/net/netsyms.c +++ b/net/netsyms.c @@ -587,7 +587,6 @@ EXPORT_SYMBOL(ip_route_me_harder); EXPORT_SYMBOL(register_gifconf); -EXPORT_SYMBOL(net_call_rx_atomic); EXPORT_SYMBOL(softnet_data); #if defined(CONFIG_NET_RADIO) || defined(CONFIG_NET_PCMCIA_RADIO) -- cgit v1.2.3 From 2bcff6c19fb53083e0cc0a9d85204bdf268b7b0f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sat, 5 Oct 2002 13:13:46 -0300 Subject: o LLC: start using seq_file for proc stuff --- include/net/llc_main.h | 3 +- include/net/llc_proc.h | 18 ++++ net/llc/Makefile | 2 +- net/llc/af_llc.c | 100 ++-------------------- net/llc/llc_if.c | 2 +- net/llc/llc_mac.c | 3 +- net/llc/llc_main.c | 12 +-- net/llc/llc_proc.c | 227 +++++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 260 insertions(+), 107 deletions(-) create mode 100644 include/net/llc_proc.h create mode 100644 net/llc/llc_proc.c (limited to 'include') diff --git a/include/net/llc_main.h b/include/net/llc_main.h index 434e86044dec..0e0d39742a2e 100644 --- a/include/net/llc_main.h +++ b/include/net/llc_main.h @@ -57,10 +57,11 @@ extern struct llc_sap *llc_sap_alloc(void); extern void llc_sap_save(struct llc_sap *sap); extern void llc_free_sap(struct llc_sap *sap); extern struct llc_sap *llc_sap_find(u8 lsap); -extern struct llc_station *llc_station_get(void); extern void llc_station_state_process(struct llc_station *station, struct sk_buff *skb); extern void llc_station_send_pdu(struct llc_station *station, struct sk_buff *skb); extern struct sk_buff *llc_alloc_frame(void); + +extern struct llc_station llc_main_station; #endif /* LLC_MAIN_H */ diff --git a/include/net/llc_proc.h b/include/net/llc_proc.h new file mode 100644 index 000000000000..c6e7306aa8c3 --- /dev/null +++ b/include/net/llc_proc.h @@ -0,0 +1,18 @@ +#ifndef LLC_PROC_H +#define LLC_PROC_H +/* + * Copyright (c) 1997 by Procom Technology, Inc. + * 2002 by Arnaldo Carvalho de Melo + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ + +extern int llc_proc_init(void); +extern void llc_proc_exit(void); + +#endif /* LLC_PROC_H */ diff --git a/net/llc/Makefile b/net/llc/Makefile index 05ae5f67518d..5c9a53fe6988 100644 --- a/net/llc/Makefile +++ b/net/llc/Makefile @@ -16,7 +16,7 @@ obj-$(CONFIG_LLC) += llc.o llc-y := llc_if.o llc_c_ev.o llc_c_ac.o llc_mac.o llc_sap.o llc_s_st.o \ llc_main.o llc_s_ac.o llc_conn.o llc_c_st.o llc_stat.o llc_actn.o \ - llc_s_ev.o llc_evnt.o llc_pdu.o + llc_s_ev.o llc_evnt.o llc_pdu.o llc_proc.o llc-$(CONFIG_LLC_UI) += af_llc.o llc-objs := $(llc-y) diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index 2144915eee5b..0c99a4e6c01f 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -1027,94 +1028,6 @@ out: return rc; } -#ifdef CONFIG_PROC_FS -#define MAC_FORMATTED_SIZE 17 -static void llc_ui_format_mac(char *bf, unsigned char *mac) -{ - sprintf(bf, "%02X:%02X:%02X:%02X:%02X:%02X", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); -} - -/** - * llc_ui_get_info - return info to procfs - * @buffer: where to put the formatted output - * @start: starting from - * @offset: offset into buffer. - * @length: size of the buffer - * - * Get the output of the local llc ui socket list to the caller. - * Returns the length of data wrote to buffer. - */ -static int llc_ui_get_info(char *buffer, char **start, off_t offset, int length) -{ - off_t pos = 0; - off_t begin = 0; - struct llc_sap *sap; - struct sock *sk; - struct list_head *sap_entry; - struct llc_station *station = llc_station_get(); - int len = sprintf(buffer, "SKt Mc local_mac_sap " - "remote_mac_sap tx_queue rx_queue st uid " - "link\n"); - - /* Output the LLC socket data for the /proc filesystem */ - read_lock_bh(&station->sap_list.lock); - list_for_each(sap_entry, &station->sap_list.list) { - sap = list_entry(sap_entry, struct llc_sap, node); - - read_lock_bh(&sap->sk_list.lock); - for (sk = sap->sk_list.list; sk; sk = sk->next) { - struct llc_opt *llc = llc_sk(sk); - - len += sprintf(buffer + len, "%2X %2X ", sk->type, - !llc_mac_null(llc->addr.sllc_mmac)); - if (llc->dev && llc_mac_null(llc->addr.sllc_mmac)) - llc_ui_format_mac(buffer + len, - llc->dev->dev_addr); - else { - if (!llc_mac_null(llc->addr.sllc_mmac)) - llc_ui_format_mac(buffer + len, - llc->addr.sllc_mmac); - else - sprintf(buffer + len, - "00:00:00:00:00:00"); - } - len += MAC_FORMATTED_SIZE; - len += sprintf(buffer + len, "@%02X ", sap->laddr.lsap); - llc_ui_format_mac(buffer + len, llc->addr.sllc_dmac); - len += MAC_FORMATTED_SIZE; - len += sprintf(buffer + len, - "@%02X %8d %8d %2d %3d ", - llc->addr.sllc_dsap, - atomic_read(&sk->wmem_alloc), - atomic_read(&sk->rmem_alloc), - sk->state, - sk->socket ? - SOCK_INODE(sk->socket)->i_uid : -1); - len += sprintf(buffer + len, "%4d\n", llc->link); - /* Are we still dumping unwanted data then discard the record */ - pos = begin + len; - - if (pos < offset) { - len = 0; /* Keep dumping into the buffer start */ - begin = pos; - } - if (pos > offset + length) /* We have dumped enough */ - break; - } - read_unlock_bh(&sap->sk_list.lock); - } - read_unlock_bh(&station->sap_list.lock); - - /* The data in question runs from begin to begin + len */ - *start = buffer + offset - begin; /* Start of wanted data */ - len -= offset - begin; /* Remove unwanted header data from length */ - if (len > length) - len = length; /* Remove unwanted tail data from length */ - return len; -} -#endif /* CONFIG_PROC_FS */ - static struct net_proto_family llc_ui_family_ops = { .family = PF_LLC, .create = llc_ui_create, @@ -1145,15 +1058,20 @@ static char llc_ui_banner[] __initdata = int __init llc_ui_init(void) { + int rc = llc_proc_init(); + + if (rc) + goto out; llc_ui_sap_last_autoport = LLC_SAP_DYN_START; sock_register(&llc_ui_family_ops); - proc_net_create("llc", 0, llc_ui_get_info); printk(llc_ui_banner); - return 0; + rc = 0; +out: + return rc; } void __exit llc_ui_exit(void) { - proc_net_remove("llc"); sock_unregister(PF_LLC); + llc_proc_exit(); } diff --git a/net/llc/llc_if.c b/net/llc/llc_if.c index 1f1d241732a6..ffc0771f69e4 100644 --- a/net/llc/llc_if.c +++ b/net/llc/llc_if.c @@ -56,7 +56,7 @@ struct llc_sap *llc_sap_open(u8 lsap, int (*func)(struct sk_buff *skb, /* allocated a SAP; initialize it and clear out its memory pool */ sap->laddr.lsap = lsap; sap->rcv_func = func; - sap->station = llc_station_get(); + sap->station = &llc_main_station; /* initialized SAP; add it to list of SAPs this station manages */ llc_sap_save(sap); out: diff --git a/net/llc/llc_mac.c b/net/llc/llc_mac.c index ae97f73a607b..3f53410df740 100644 --- a/net/llc/llc_mac.c +++ b/net/llc/llc_mac.c @@ -197,12 +197,11 @@ static void fix_up_incoming_skb(struct sk_buff *skb) */ static void llc_station_rcv(struct sk_buff *skb) { - struct llc_station *station = llc_station_get(); struct llc_station_state_ev *ev = llc_station_ev(skb); ev->type = LLC_STATION_EV_TYPE_PDU; ev->reason = 0; - llc_station_state_process(station, skb); + llc_station_state_process(&llc_main_station, skb); } diff --git a/net/llc/llc_main.c b/net/llc/llc_main.c index f7b54e15882d..a8167171dc6b 100644 --- a/net/llc/llc_main.c +++ b/net/llc/llc_main.c @@ -50,7 +50,7 @@ static struct llc_station_state_trans * struct sk_buff *skb); static int llc_rtn_all_conns(struct llc_sap *sap); -static struct llc_station llc_main_station; /* only one of its kind */ +struct llc_station llc_main_station; /* only one of its kind */ #undef LLC_REFCNT_DEBUG #ifdef LLC_REFCNT_DEBUG @@ -339,16 +339,6 @@ static int llc_rtn_all_conns(struct llc_sap *sap) return rc; } -/** - * llc_station_get - get addr of global station. - * - * Returns address of a place to copy the global station to it. - */ -struct llc_station *llc_station_get(void) -{ - return &llc_main_station; -} - /** * llc_station_state_process: queue event and try to process queue. * @station: Address of the station diff --git a/net/llc/llc_proc.c b/net/llc/llc_proc.c new file mode 100644 index 000000000000..e9f08b48dc68 --- /dev/null +++ b/net/llc/llc_proc.c @@ -0,0 +1,227 @@ +/* + * proc_llc.c - proc interface for LLC + * + * Copyright (c) 2001 by Jay Schulist + * 2002 by Arnaldo Carvalho de Melo + * + * This program can be redistributed or modified under the terms of the + * GNU General Public License as published by the Free Software Foundation. + * This program is distributed without any warranty or implied warranty + * of merchantability or fitness for a particular purpose. + * + * See the GNU General Public License for more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_PROC_FS +static void llc_ui_format_mac(struct seq_file *seq, unsigned char *mac) +{ + seq_printf(seq, "%02X:%02X:%02X:%02X:%02X:%02X", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); +} + +static __inline__ struct sock *llc_get_sk_idx(loff_t pos) +{ + struct list_head *sap_entry; + struct llc_sap *sap; + struct sock *sk = NULL; + + list_for_each(sap_entry, &llc_main_station.sap_list.list) { + sap = list_entry(sap_entry, struct llc_sap, node); + + read_lock_bh(&sap->sk_list.lock); + for (sk = sap->sk_list.list; pos && sk; sk = sk->next) + --pos; + if (!pos) { + if (!sk) + read_unlock_bh(&sap->sk_list.lock); + break; + } + read_unlock_bh(&sap->sk_list.lock); + } + return sk; +} + +static void *llc_seq_start(struct seq_file *seq, loff_t *pos) +{ + loff_t l = *pos; + + read_lock_bh(&llc_main_station.sap_list.lock); + if (!l) + return (void *)1; + return llc_get_sk_idx(--l); +} + +static void *llc_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct sock* sk; + struct llc_opt *llc; + struct llc_sap *sap; + + ++*pos; + if (v == (void *)1) { + if (list_empty(&llc_main_station.sap_list.list)) { + sk = NULL; + goto out; + } + sap = list_entry(llc_main_station.sap_list.list.next, + struct llc_sap, node); + + read_lock_bh(&sap->sk_list.lock); + sk = sap->sk_list.list; + goto out; + } + sk = v; + if (sk->next) { + sk = sk->next; + goto out; + } + llc = llc_sk(sk); + sap = llc->sap; + read_unlock_bh(&sap->sk_list.lock); + sk = NULL; + for (;;) { + if (sap->node.next == &llc_main_station.sap_list.list) + break; + sap = list_entry(sap->node.next, struct llc_sap, node); + read_lock_bh(&sap->sk_list.lock); + if (sap->sk_list.list) { + sk = sap->sk_list.list; + break; + } + read_unlock_bh(&sap->sk_list.lock); + } +out: + return sk; +} + +static void llc_seq_stop(struct seq_file *seq, void *v) +{ + read_unlock_bh(&llc_main_station.sap_list.lock); +} + +static int llc_seq_show(struct seq_file *seq, void *v) +{ + struct sock* sk; + struct llc_opt *llc; + + if (v == (void *)1) { + seq_puts(seq, "SKt Mc local_mac_sap remote_mac_sap " + " tx_queue rx_queue st uid link\n"); + goto out; + } + sk = v; + llc = llc_sk(sk); + + seq_printf(seq, "%2X %2X ", sk->type, + !llc_mac_null(llc->addr.sllc_mmac)); + + if (llc->dev && llc_mac_null(llc->addr.sllc_mmac)) + llc_ui_format_mac(seq, llc->dev->dev_addr); + else if (!llc_mac_null(llc->addr.sllc_mmac)) + llc_ui_format_mac(seq, llc->addr.sllc_mmac); + else + seq_printf(seq, "00:00:00:00:00:00"); + seq_printf(seq, "@%02X ", llc->sap->laddr.lsap); + llc_ui_format_mac(seq, llc->addr.sllc_dmac); + seq_printf(seq, "@%02X %8d %8d %2d %3d %4d\n", llc->addr.sllc_dsap, + atomic_read(&sk->wmem_alloc), atomic_read(&sk->rmem_alloc), + sk->state, sk->socket ? SOCK_INODE(sk->socket)->i_uid : -1, + llc->link); +out: + return 0; +} + +struct seq_operations llc_seq_ops = { + .start = llc_seq_start, + .next = llc_seq_next, + .stop = llc_seq_stop, + .show = llc_seq_show, +}; + +static int llc_seq_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &llc_seq_ops); +} + +static int llc_proc_perms(struct inode* inode, int op) +{ + return 0; +} + +static struct file_operations llc_seq_fops = { + .open = llc_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static struct inode_operations llc_seq_inode = { + .permission = llc_proc_perms, +}; + +static struct proc_dir_entry *llc_proc_dir; + +int __init llc_proc_init(void) +{ + int rc = -ENOMEM; + struct proc_dir_entry *p; + + llc_proc_dir = proc_mkdir("llc", proc_net); + if (!llc_proc_dir) + goto out; + + p = create_proc_entry("socket", 0, llc_proc_dir); + if (!p) + goto out_socket; + + p->proc_fops = &llc_seq_fops; + p->proc_iops = &llc_seq_inode; + rc = 0; +out: + return rc; +out_socket: + remove_proc_entry("llc", proc_net); + goto out; +} + +void __exit llc_proc_exit(void) +{ + remove_proc_entry("socket", llc_proc_dir); + remove_proc_entry("llc", proc_net); +} +#else /* CONFIG_PROC_FS */ +int __init llc_proc_init(void) +{ + return 0; +} + +void __exit llc_proc_exit(void) +{ +} +#endif /* CONFIG_PROC_FS */ -- cgit v1.2.3 From b1e16e5e6790c28cdd37381216114a8cfcf6e09c Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sat, 5 Oct 2002 18:04:50 -0300 Subject: o IPX: use seq_file for proc stuff Also move the lenghty ChangeLog to a separate file. It also tidies a tiny bit of LLC. --- include/net/ipx.h | 21 ++- net/ipx/ChangeLog | 101 ++++++++++++++ net/ipx/Makefile | 2 +- net/ipx/af_ipx.c | 294 ++++------------------------------------ net/ipx/ipx_proc.c | 388 +++++++++++++++++++++++++++++++++++++++++++++++++++++ net/llc/llc_proc.c | 4 +- 6 files changed, 530 insertions(+), 280 deletions(-) create mode 100644 net/ipx/ChangeLog create mode 100644 net/ipx/ipx_proc.c (limited to 'include') diff --git a/include/net/ipx.h b/include/net/ipx.h index 1f59db84c1a1..c3b1e4698438 100644 --- a/include/net/ipx.h +++ b/include/net/ipx.h @@ -1,3 +1,5 @@ +#ifndef _NET_INET_IPX_H_ +#define _NET_INET_IPX_H_ /* * The following information is in its entirety obtained from: * @@ -7,9 +9,6 @@ * Which is available from ftp.novell.com */ -#ifndef _NET_INET_IPX_H_ -#define _NET_INET_IPX_H_ - #include #include #include @@ -25,8 +24,7 @@ struct ipx_address { #define IPX_MAX_PPROP_HOPS 8 -struct ipxhdr -{ +struct ipxhdr { __u16 ipx_checksum __attribute__ ((packed)); #define IPX_NO_CHECKSUM 0xFFFF __u16 ipx_pktsize __attribute__ ((packed)); @@ -110,4 +108,17 @@ struct ipx_opt { #define IPX_MIN_EPHEMERAL_SOCKET 0x4000 #define IPX_MAX_EPHEMERAL_SOCKET 0x7fff +extern struct ipx_route *ipx_routes; +extern rwlock_t ipx_routes_lock; + +extern struct ipx_interface *ipx_interfaces; +extern spinlock_t ipx_interfaces_lock; + +extern struct ipx_interface *ipx_primary_net; + +extern int ipx_proc_init(void); +extern void ipx_proc_exit(void); + +extern const char *ipx_frame_name(unsigned short); +extern const char *ipx_device_name(struct ipx_interface *intrfc); #endif /* def _NET_INET_IPX_H_ */ diff --git a/net/ipx/ChangeLog b/net/ipx/ChangeLog new file mode 100644 index 000000000000..3b29763751a3 --- /dev/null +++ b/net/ipx/ChangeLog @@ -0,0 +1,101 @@ + Revision 0.21: Uses the new generic socket option code. + + Revision 0.22: Gcc clean ups and drop out device registration. Use the + new multi-protocol edition of hard_header + + Revision 0.23: IPX /proc by Mark Evans. Adding a route will + will overwrite any existing route to the same network. + + Revision 0.24: Supports new /proc with no 4K limit + + Revision 0.25: Add ephemeral sockets, passive local network + identification, support for local net 0 and + multiple datalinks + + Revision 0.26: Device drop kills IPX routes via it. (needed for module) + + Revision 0.27: Autobind + + Revision 0.28: Small fix for multiple local networks + + Revision 0.29: Assorted major errors removed + Small correction to promisc mode error fix + Asynchronous I/O support. Changed to use notifiers + and the newer packet_type stuff. Assorted major + fixes + + Revision 0.30: Moved to net/ipx/... + Don't set address length on recvfrom that errors. + Incorrect verify_area. + + Revision 0.31: New sk_buffs. This still needs a lot of + testing. + + Revision 0.32: Using sock_alloc_send_skb, firewall hooks. + Supports sendmsg/recvmsg + + Revision 0.33: Internal network support, routing changes, uses a + protocol private area for ipx data. + + Revision 0.34: Module support. + + Revision 0.35: Checksum support. , hooked in by + Handles WIN95 discovery packets + + Revision 0.36: Internal bump up for 2.1 + + Revision 0.37: Began adding POSIXisms. + + Revision 0.38: Asynchronous socket stuff made current. + + Revision 0.39: SPX interfaces + + Revision 0.40: Tiny SIOCGSTAMP fix (chris@cybernet.co.nz) + + Revision 0.41: 802.2TR removed (p.norton@computer.org) + Fixed connecting to primary net, + Automatic binding on send & receive, + Martijn van Oosterhout + + Revision 042: Multithreading - use spinlocks and refcounting to + protect some structures: ipx_interface sock list, list + of ipx interfaces, etc. + Bugfixes - do refcounting on net_devices, check function + results, etc. Thanks to davem and freitag for + suggestions and guidance. + Arnaldo Carvalho de Melo , + November, 2000 + + Revision 043: Shared SKBs, don't mangle packets, some cleanups + Arnaldo Carvalho de Melo , + December, 2000 + + Revision 044: Call ipxitf_hold on NETDEV_UP - acme + + Revision 045: fix PPROP routing bug - acme + + Revision 046: Further fixes to PPROP, ipxitf_create_internal was + doing an unneeded MOD_INC_USE_COUNT, implement + sysctl for ipx_pprop_broacasting, fix the ipx sysctl + handling, making it dynamic, some cleanups, thanks to + Petr Vandrovec for review and good suggestions. (acme) + + Revision 047: Cleanups, CodingStyle changes, move the ncp connection + hack out of line - acme + + Revision 048: Use sk->protinfo to store the pointer to IPX private + area, remove af_ipx from sk->protinfo and move ipx_opt + to include/net/ipx.h, use IPX_SK like DecNET, etc - acme + + Revision 049: SPX support dropped, see comment in ipx_create - acme + + Revision 050: Use seq_file for proc stuff, moving it to ipx_proc.c - acme + +Other fixes: + + Protect the module by a MOD_INC_USE_COUNT/MOD_DEC_USE_COUNT pair. Also, now + usage count is managed this way: + -Count one if the auto_interface mode is on + -Count one per configured interface + + Jacques Gelinas (jacques@solucorp.qc.ca) diff --git a/net/ipx/Makefile b/net/ipx/Makefile index 0c40039074f3..e17fffc815d8 100644 --- a/net/ipx/Makefile +++ b/net/ipx/Makefile @@ -4,7 +4,7 @@ obj-$(CONFIG_IPX) += ipx.o -ipx-y := af_ipx.o +ipx-y := af_ipx.o ipx_proc.o ipx-$(CONFIG_SYSCTL) += sysctl_net_ipx.o ipx-objs := $(ipx-y) diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c index a0dedb215d95..0951077705e9 100644 --- a/net/ipx/af_ipx.c +++ b/net/ipx/af_ipx.c @@ -15,81 +15,17 @@ * liability nor provide warranty for any of this software. This material * is provided as is and at no charge. * - * Revision 0.21: Uses the new generic socket option code. - * Revision 0.22: Gcc clean ups and drop out device registration. Use the - * new multi-protocol edition of hard_header - * Revision 0.23: IPX /proc by Mark Evans. Adding a route will - * will overwrite any existing route to the same network. - * Revision 0.24: Supports new /proc with no 4K limit - * Revision 0.25: Add ephemeral sockets, passive local network - * identification, support for local net 0 and - * multiple datalinks - * Revision 0.26: Device drop kills IPX routes via it. (needed for module) - * Revision 0.27: Autobind - * Revision 0.28: Small fix for multiple local networks - * Revision 0.29: Assorted major errors removed - * Small correction to promisc mode error fix - * Asynchronous I/O support. Changed to use notifiers - * and the newer packet_type stuff. Assorted major - * fixes - * Revision 0.30: Moved to net/ipx/... - * Don't set address length on recvfrom that errors. - * Incorrect verify_area. - * Revision 0.31: New sk_buffs. This still needs a lot of - * testing. - * Revision 0.32: Using sock_alloc_send_skb, firewall hooks. - * Supports sendmsg/recvmsg - * Revision 0.33: Internal network support, routing changes, uses a - * protocol private area for ipx data. - * Revision 0.34: Module support. - * Revision 0.35: Checksum support. , hooked in by - * Handles WIN95 discovery packets - * Revision 0.36: Internal bump up for 2.1 - * Revision 0.37: Began adding POSIXisms. - * Revision 0.38: Asynchronous socket stuff made current. - * Revision 0.39: SPX interfaces - * Revision 0.40: Tiny SIOCGSTAMP fix (chris@cybernet.co.nz) - * Revision 0.41: 802.2TR removed (p.norton@computer.org) - * Fixed connecting to primary net, - * Automatic binding on send & receive, - * Martijn van Oosterhout - * Revision 042: Multithreading - use spinlocks and refcounting to - * protect some structures: ipx_interface sock list, list - * of ipx interfaces, etc. - * Bugfixes - do refcounting on net_devices, check function - * results, etc. Thanks to davem and freitag for - * suggestions and guidance. - * Arnaldo Carvalho de Melo , - * November, 2000 - * Revision 043: Shared SKBs, don't mangle packets, some cleanups - * Arnaldo Carvalho de Melo , - * December, 2000 - * Revision 044: Call ipxitf_hold on NETDEV_UP (acme) - * Revision 045: fix PPROP routing bug (acme) - * Revision 046: Further fixes to PPROP, ipxitf_create_internal was - * doing an unneeded MOD_INC_USE_COUNT, implement - * sysctl for ipx_pprop_broacasting, fix the ipx sysctl - * handling, making it dynamic, some cleanups, thanks to - * Petr Vandrovec for review and good suggestions. (acme) - * Revision 047: Cleanups, CodingStyle changes, move the ncp connection - * hack out of line (acme) - * Revision 048: Use sk->protinfo to store the pointer to IPX private - * area, remove af_ipx from sk->protinfo and move ipx_opt - * to include/net/ipx.h, use IPX_SK like DecNET, etc - * Revision 049: SPX support dropped, see comment in ipx_create - * - * Protect the module by a MOD_INC_USE_COUNT/MOD_DEC_USE_COUNT - * pair. Also, now usage count is managed this way - * -Count one if the auto_interface mode is on - * -Count one per configured interface - * - * Jacques Gelinas (jacques@solucorp.qc.ca) - * + * Portions Copyright (c) 2000-2002 Conectiva, Inc. + * Neither Arnaldo Carvalho de Melo nor Conectiva, Inc. admit liability nor + * provide warranty for any of this software. This material is provided + * "AS-IS" and at no charge. * * Portions Copyright (c) 1995 Caldera, Inc. * Neither Greg Page nor Caldera, Inc. admit liability nor provide * warranty for any of this software. This material is provided * "AS-IS" and at no charge. + * + * See net/ipx/ChangeLog. */ #include @@ -145,13 +81,13 @@ static struct datalink_proto *pSNAP_datalink; static struct proto_ops ipx_dgram_ops; -static struct ipx_route *ipx_routes; -static rwlock_t ipx_routes_lock = RW_LOCK_UNLOCKED; +struct ipx_route *ipx_routes; +rwlock_t ipx_routes_lock = RW_LOCK_UNLOCKED; -static struct ipx_interface *ipx_interfaces; -static spinlock_t ipx_interfaces_lock = SPIN_LOCK_UNLOCKED; +struct ipx_interface *ipx_interfaces; +spinlock_t ipx_interfaces_lock = SPIN_LOCK_UNLOCKED; -static struct ipx_interface *ipx_primary_net; +struct ipx_interface *ipx_primary_net; static struct ipx_interface *ipx_internal_net; #undef IPX_REFCNT_DEBUG @@ -791,8 +727,6 @@ static int ipxitf_add_local_route(struct ipx_interface *intrfc) return ipxrtr_add_route(intrfc->if_netnum, intrfc, NULL); } -static const char *ipx_frame_name(unsigned short); -static const char *ipx_device_name(struct ipx_interface *); static void ipxitf_discover_netnum(struct ipx_interface *intrfc, struct sk_buff *skb); static int ipxitf_pprop(struct ipx_interface *intrfc, struct sk_buff *skb); @@ -1656,7 +1590,7 @@ static int ipxrtr_ioctl(unsigned int cmd, void *arg) out: return ret; } -static const char *ipx_frame_name(unsigned short frame) +const char *ipx_frame_name(unsigned short frame) { char* ret = "None"; @@ -1671,189 +1605,12 @@ static const char *ipx_frame_name(unsigned short frame) return ret; } -static const char *ipx_device_name(struct ipx_interface *intrfc) +const char *ipx_device_name(struct ipx_interface *intrfc) { return intrfc->if_internal ? "Internal" : intrfc->if_dev ? intrfc->if_dev->name : "Unknown"; } -/* Called from proc fs */ -static int ipx_interface_get_info(char *buffer, char **start, off_t offset, - int length) -{ - struct ipx_interface *i; - off_t begin = 0, pos = 0; - int len = 0; - - /* Theory.. Keep printing in the same place until we pass offset */ - - len += sprintf(buffer, "%-11s%-15s%-9s%-11s%s", "Network", - "Node_Address", "Primary", "Device", "Frame_Type"); -#ifdef IPX_REFCNT_DEBUG - len += sprintf(buffer + len, " refcnt"); -#endif - strcat(buffer + len++, "\n"); - spin_lock_bh(&ipx_interfaces_lock); - for (i = ipx_interfaces; i; i = i->if_next) { - len += sprintf(buffer + len, "%08lX ", - (long unsigned int) ntohl(i->if_netnum)); - len += sprintf(buffer + len, "%02X%02X%02X%02X%02X%02X ", - i->if_node[0], i->if_node[1], i->if_node[2], - i->if_node[3], i->if_node[4], i->if_node[5]); - len += sprintf(buffer + len, "%-9s", i == ipx_primary_net ? - "Yes" : "No"); - len += sprintf(buffer + len, "%-11s", ipx_device_name(i)); - len += sprintf(buffer + len, "%-9s", - ipx_frame_name(i->if_dlink_type)); -#ifdef IPX_REFCNT_DEBUG - len += sprintf(buffer + len, "%6d", atomic_read(&i->refcnt)); -#endif - strcat(buffer + len++, "\n"); - /* Are we still dumping unwanted data then discard the record */ - pos = begin + len; - - if (pos < offset) { - len = 0; /* Keep dumping into the buffer start */ - begin = pos; - } - if (pos > offset + length) /* We have dumped enough */ - break; - } - spin_unlock_bh(&ipx_interfaces_lock); - - /* The data in question runs from begin to begin+len */ - *start = buffer + (offset - begin); /* Start of wanted data */ - len -= (offset - begin); /* Remove unwanted header data from length */ - if (len > length) - len = length; /* Remove unwanted tail data from length */ - - return len; -} - -static int ipx_get_info(char *buffer, char **start, off_t offset, int length) -{ - struct sock *s; - struct ipx_interface *i; - off_t begin = 0, pos = 0; - int len = 0; - - /* Theory.. Keep printing in the same place until we pass offset */ - -#ifdef CONFIG_IPX_INTERN - len += sprintf(buffer, "%-28s%-28s%-10s%-10s%-7s%s\n", "Local_Address", -#else - len += sprintf(buffer, "%-15s%-28s%-10s%-10s%-7s%s\n", "Local_Address", -#endif /* CONFIG_IPX_INTERN */ - "Remote_Address", "Tx_Queue", "Rx_Queue", - "State", "Uid"); - - spin_lock_bh(&ipx_interfaces_lock); - for (i = ipx_interfaces; i; i = i->if_next) { - ipxitf_hold(i); - spin_lock_bh(&i->if_sklist_lock); - for (s = i->if_sklist; s; s = s->next) { - struct ipx_opt *ipxs = ipx_sk(s); -#ifdef CONFIG_IPX_INTERN - len += sprintf(buffer + len, - "%08lX:%02X%02X%02X%02X%02X%02X:%04X ", - (unsigned long)htonl(ipxs->intrfc->if_netnum), - ipxs->node[0], ipxs->node[1], - ipxs->node[2], ipxs->node[3], - ipxs->node[4], ipxs->node[5], - htons(ipxs->port)); -#else - len += sprintf(buffer + len, "%08lX:%04X ", - (unsigned long) htonl(i->if_netnum), - htons(ipxs->port)); -#endif /* CONFIG_IPX_INTERN */ - if (s->state != TCP_ESTABLISHED) - len += sprintf(buffer + len, "%-28s", - "Not_Connected"); - else { - len += sprintf(buffer + len, - "%08lX:%02X%02X%02X%02X%02X%02X:%04X ", - (unsigned long)htonl(ipxs->dest_addr.net), - ipxs->dest_addr.node[0], - ipxs->dest_addr.node[1], - ipxs->dest_addr.node[2], - ipxs->dest_addr.node[3], - ipxs->dest_addr.node[4], - ipxs->dest_addr.node[5], - htons(ipxs->dest_addr.sock)); - } - - len += sprintf(buffer + len, "%08X %08X ", - atomic_read(&s->wmem_alloc), - atomic_read(&s->rmem_alloc)); - len += sprintf(buffer + len, "%02X %03d\n", - s->state, SOCK_INODE(s->socket)->i_uid); - - pos = begin + len; - if (pos < offset) { - len = 0; - begin = pos; - } - - if (pos > offset + length) /* We have dumped enough */ - break; - } - spin_unlock_bh(&i->if_sklist_lock); - ipxitf_put(i); - } - spin_unlock_bh(&ipx_interfaces_lock); - - /* The data in question runs from begin to begin+len */ - *start = buffer + offset - begin; - len -= (offset - begin); - if (len > length) - len = length; - - return len; -} - -static int ipx_rt_get_info(char *buffer, char **start, off_t offset, int length) -{ - struct ipx_route *rt; - off_t begin = 0, pos = 0; - int len = 0; - - len += sprintf(buffer, "%-11s%-13s%s\n", - "Network", "Router_Net", "Router_Node"); - read_lock_bh(&ipx_routes_lock); - for (rt = ipx_routes; rt; rt = rt->ir_next) { - len += sprintf(buffer + len, "%08lX ", - (long unsigned int) ntohl(rt->ir_net)); - if (rt->ir_routed) { - len += sprintf(buffer + len, - "%08lX %02X%02X%02X%02X%02X%02X\n", - (long unsigned int) ntohl(rt->ir_intrfc->if_netnum), - rt->ir_router_node[0], rt->ir_router_node[1], - rt->ir_router_node[2], rt->ir_router_node[3], - rt->ir_router_node[4], rt->ir_router_node[5]); - } else { - len += sprintf(buffer + len, "%-13s%s\n", - "Directly", "Connected"); - } - - pos = begin + len; - if (pos < offset) { - len = 0; - begin = pos; - } - - if (pos > offset + length) - break; - } - read_unlock_bh(&ipx_routes_lock); - - *start = buffer + (offset - begin); - len -= (offset - begin); - if (len > length) - len = length; - - return len; -} - /* Handling for system calls applied via the various interfaces to an IPX * socket object. */ @@ -2516,9 +2273,9 @@ extern void destroy_8023_client(struct datalink_proto *); static unsigned char ipx_8022_type = 0xE0; static unsigned char ipx_snap_id[5] = { 0x0, 0x0, 0x0, 0x81, 0x37 }; static char ipx_banner[] __initdata = - KERN_INFO "NET4: Linux IPX 0.49 for NET4.0\n" + KERN_INFO "NET4: Linux IPX 0.50 for NET4.0\n" KERN_INFO "IPX Portions Copyright (c) 1995 Caldera, Inc.\n" \ - KERN_INFO "IPX Portions Copyright (c) 2000, 2001 Conectiva, Inc.\n"; + KERN_INFO "IPX Portions Copyright (c) 2000-2002 Conectiva, Inc.\n"; static char ipx_EII_err_msg[] __initdata = KERN_CRIT "IPX: Unable to register with Ethernet II\n"; static char ipx_8023_err_msg[] __initdata = @@ -2554,11 +2311,7 @@ static int __init ipx_init(void) register_netdevice_notifier(&ipx_dev_notifier); ipx_register_sysctl(); -#ifdef CONFIG_PROC_FS - proc_net_create("ipx", 0, ipx_get_info); - proc_net_create("ipx_interface", 0, ipx_interface_get_info); - proc_net_create("ipx_route", 0, ipx_rt_get_info); -#endif + ipx_proc_init(); printk(ipx_banner); return 0; } @@ -2580,14 +2333,13 @@ module_init(ipx_init); static void __exit ipx_proto_finito(void) { - /* no need to worry about having anything on the ipx_interfaces - * list, when a interface is created we increment the module - * usage count, so the module will only be unloaded when there - * are no more interfaces */ - - proc_net_remove("ipx_route"); - proc_net_remove("ipx_interface"); - proc_net_remove("ipx"); + /* + * No need to worry about having anything on the ipx_interfaces list, + * when a interface is created we increment the module usage count, so + * the module will only be unloaded when there are no more interfaces + */ + + ipx_proc_exit(); ipx_unregister_sysctl(); unregister_netdevice_notifier(&ipx_dev_notifier); diff --git a/net/ipx/ipx_proc.c b/net/ipx/ipx_proc.c new file mode 100644 index 000000000000..c96b7b382d0e --- /dev/null +++ b/net/ipx/ipx_proc.c @@ -0,0 +1,388 @@ +/* + * IPX proc routines + * + * Copyright(C) Arnaldo Carvalho de Melo , 2002 + */ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_PROC_FS +static __inline__ struct ipx_interface *ipx_get_interface_idx(loff_t pos) +{ + struct ipx_interface *i; + + for (i = ipx_interfaces; pos && i; i = i->if_next) + --pos; + + return i; +} + +static void *ipx_seq_interface_start(struct seq_file *seq, loff_t *pos) +{ + loff_t l = *pos; + + spin_lock_bh(&ipx_interfaces_lock); + return l ? ipx_get_interface_idx(--l) : (void *)1; +} + +static void *ipx_seq_interface_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct ipx_interface *i; + + ++*pos; + if (v == (void *)1) { + i = NULL; + if (ipx_interfaces) + i = ipx_interfaces; + goto out; + } + i = v; + i = i->if_next; +out: + return i; +} + +static void ipx_seq_interface_stop(struct seq_file *seq, void *v) +{ + spin_unlock_bh(&ipx_interfaces_lock); +} + +static int ipx_seq_interface_show(struct seq_file *seq, void *v) +{ + struct ipx_interface *i; + + if (v == (void *)1) { + seq_puts(seq, "Network Node_Address Primary Device " + "Frame_Type"); +#ifdef IPX_REFCNT_DEBUG + seq_puts(seq, " refcnt"); +#endif + seq_puts(seq, "\n"); + goto out; + } + + i = v; + seq_printf(seq, "%08lX ", (unsigned long int)ntohl(i->if_netnum)); + seq_printf(seq, "%02X%02X%02X%02X%02X%02X ", + i->if_node[0], i->if_node[1], i->if_node[2], + i->if_node[3], i->if_node[4], i->if_node[5]); + seq_printf(seq, "%-9s", i == ipx_primary_net ? "Yes" : "No"); + seq_printf(seq, "%-11s", ipx_device_name(i)); + seq_printf(seq, "%-9s", ipx_frame_name(i->if_dlink_type)); +#ifdef IPX_REFCNT_DEBUG + seq_printf(seq, "%6d", atomic_read(&i->refcnt)); +#endif + seq_puts(seq, "\n"); +out: + return 0; +} + +static __inline__ struct ipx_route *ipx_get_route_idx(loff_t pos) +{ + struct ipx_route *r; + + for (r = ipx_routes; pos && r; r = r->ir_next) + --pos; + + return r; +} + +static void *ipx_seq_route_start(struct seq_file *seq, loff_t *pos) +{ + loff_t l = *pos; + read_lock_bh(&ipx_routes_lock); + return l ? ipx_get_route_idx(--l) : (void *)1; +} + +static void *ipx_seq_route_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct ipx_route *r; + + ++*pos; + if (v == (void *)1) { + r = NULL; + if (ipx_routes) + r = ipx_routes; + goto out; + } + r = v; + r = r->ir_next; +out: + return r; +} + +static void ipx_seq_route_stop(struct seq_file *seq, void *v) +{ + read_unlock_bh(&ipx_routes_lock); +} + +static int ipx_seq_route_show(struct seq_file *seq, void *v) +{ + struct ipx_route *rt; + + if (v == (void *)1) { + seq_puts(seq, "Network Router_Net Router_Node\n"); + goto out; + } + rt = v; + seq_printf(seq, "%08lX ", (unsigned long int)ntohl(rt->ir_net)); + if (rt->ir_routed) + seq_printf(seq, "%08lX %02X%02X%02X%02X%02X%02X\n", + (long unsigned int)ntohl(rt->ir_intrfc->if_netnum), + rt->ir_router_node[0], rt->ir_router_node[1], + rt->ir_router_node[2], rt->ir_router_node[3], + rt->ir_router_node[4], rt->ir_router_node[5]); + else + seq_puts(seq, "Directly Connected\n"); +out: + return 0; +} + +static __inline__ struct sock *ipx_get_socket_idx(loff_t pos) +{ + struct sock *s = NULL; + struct ipx_interface *i; + + for (i = ipx_interfaces; pos && i; i = i->if_next) { + spin_lock_bh(&i->if_sklist_lock); + for (s = i->if_sklist; pos && s; s = s->next) + --pos; + if (!pos) { + if (!s) + spin_unlock_bh(&i->if_sklist_lock); + break; + } + spin_unlock_bh(&i->if_sklist_lock); + } + + return s; +} + +static void *ipx_seq_socket_start(struct seq_file *seq, loff_t *pos) +{ + loff_t l = *pos; + + spin_lock_bh(&ipx_interfaces_lock); + return l ? ipx_get_socket_idx(--l) : (void *)1; +} + +static void *ipx_seq_socket_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct sock* sk; + struct ipx_interface *i; + struct ipx_opt *ipxs; + + ++*pos; + if (v == (void *)1) { + sk = NULL; + if (!ipx_interfaces) + goto out; + sk = ipx_interfaces->if_sklist; + if (sk) + spin_lock_bh(&ipx_interfaces->if_sklist_lock); + goto out; + } + sk = v; + if (sk->next) { + sk = sk->next; + goto out; + } + ipxs = ipx_sk(sk); + i = ipxs->intrfc; + spin_unlock_bh(&i->if_sklist_lock); + sk = NULL; + for (;;) { + if (!i->if_next) + break; + i = i->if_next; + spin_lock_bh(&i->if_sklist_lock); + if (i->if_sklist) { + sk = i->if_sklist; + break; + } + spin_unlock_bh(&i->if_sklist_lock); + } +out: + return sk; +} + +static int ipx_seq_socket_show(struct seq_file *seq, void *v) +{ + struct sock *s; + struct ipx_opt *ipxs; + + if (v == (void *)1) { +#ifdef CONFIG_IPX_INTERN + seq_puts(seq, "Local_Address " + "Remote_Address Tx_Queue " + "Rx_Queue State Uid\n"); +#else + seq_puts(seq, "Local_Address Remote_Address " + "Tx_Queue Rx_Queue State Uid\n"); +#endif + goto out; + } + + s = v; + ipxs = ipx_sk(s); +#ifdef CONFIG_IPX_INTERN + seq_printf(seq, "%08lX:%02X%02X%02X%02X%02X%02X:%04X ", + (unsigned long)htonl(ipxs->intrfc->if_netnum), + ipxs->node[0], ipxs->node[1], ipxs->node[2], ipxs->node[3], + ipxs->node[4], ipxs->node[5], htons(ipxs->port)); +#else + seq_printf(seq, "%08lX:%04X ", (unsigned long) htonl(ipxs->intrfc->if_netnum), + htons(ipxs->port)); +#endif /* CONFIG_IPX_INTERN */ + if (s->state != TCP_ESTABLISHED) + seq_printf(seq, "%-28s", "Not_Connected"); + else { + seq_printf(seq, "%08lX:%02X%02X%02X%02X%02X%02X:%04X ", + (unsigned long)htonl(ipxs->dest_addr.net), + ipxs->dest_addr.node[0], ipxs->dest_addr.node[1], + ipxs->dest_addr.node[2], ipxs->dest_addr.node[3], + ipxs->dest_addr.node[4], ipxs->dest_addr.node[5], + htons(ipxs->dest_addr.sock)); + } + + seq_printf(seq, "%08X %08X %02X %03d\n", + atomic_read(&s->wmem_alloc), atomic_read(&s->rmem_alloc), + s->state, SOCK_INODE(s->socket)->i_uid); +out: + return 0; +} + +struct seq_operations ipx_seq_interface_ops = { + .start = ipx_seq_interface_start, + .next = ipx_seq_interface_next, + .stop = ipx_seq_interface_stop, + .show = ipx_seq_interface_show, +}; + +struct seq_operations ipx_seq_route_ops = { + .start = ipx_seq_route_start, + .next = ipx_seq_route_next, + .stop = ipx_seq_route_stop, + .show = ipx_seq_route_show, +}; + +struct seq_operations ipx_seq_socket_ops = { + .start = ipx_seq_socket_start, + .next = ipx_seq_socket_next, + .stop = ipx_seq_interface_stop, + .show = ipx_seq_socket_show, +}; + +static int ipx_seq_route_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &ipx_seq_route_ops); +} + +static int ipx_seq_interface_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &ipx_seq_interface_ops); +} + +static int ipx_seq_socket_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &ipx_seq_socket_ops); +} + +static struct file_operations ipx_seq_interface_fops = { + .open = ipx_seq_interface_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static struct file_operations ipx_seq_route_fops = { + .open = ipx_seq_route_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static struct file_operations ipx_seq_socket_fops = { + .open = ipx_seq_socket_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int ipx_proc_perms(struct inode* inode, int op) +{ + return 0; +} + +static struct inode_operations ipx_seq_inode = { + .permission = ipx_proc_perms, +}; + +static struct proc_dir_entry *ipx_proc_dir; + +int __init ipx_proc_init(void) +{ + struct proc_dir_entry *p; + int rc = -ENOMEM; + + ipx_proc_dir = proc_mkdir("ipx", proc_net); + + if (!ipx_proc_dir) + goto out; + p = create_proc_entry("interface", 0, ipx_proc_dir); + if (!p) + goto out_interface; + + p->proc_fops = &ipx_seq_interface_fops; + p->proc_iops = &ipx_seq_inode; + p = create_proc_entry("route", 0, ipx_proc_dir); + if (!p) + goto out_route; + + p->proc_fops = &ipx_seq_route_fops; + p->proc_iops = &ipx_seq_inode; + p = create_proc_entry("socket", 0, ipx_proc_dir); + if (!p) + goto out_socket; + + p->proc_fops = &ipx_seq_socket_fops; + p->proc_iops = &ipx_seq_inode; + + rc = 0; +out: + return rc; +out_socket: + remove_proc_entry("route", ipx_proc_dir); +out_route: + remove_proc_entry("interface", ipx_proc_dir); +out_interface: + remove_proc_entry("ipx", proc_net); + goto out; +} + +void __exit ipx_proc_exit(void) +{ + remove_proc_entry("interface", ipx_proc_dir); + remove_proc_entry("route", ipx_proc_dir); + remove_proc_entry("socket", ipx_proc_dir); + remove_proc_entry("ipx", proc_net); +} + +#else /* CONFIG_PROC_FS */ + +int __init ipx_proc_init(void) +{ + return 0; +} + +void __exit ipx_proc_exit(void) +{ +} + +#endif /* CONFIG_PROC_FS */ diff --git a/net/llc/llc_proc.c b/net/llc/llc_proc.c index 1b917697fcea..d4f1f73f2245 100644 --- a/net/llc/llc_proc.c +++ b/net/llc/llc_proc.c @@ -61,9 +61,7 @@ static void *llc_seq_start(struct seq_file *seq, loff_t *pos) loff_t l = *pos; read_lock_bh(&llc_main_station.sap_list.lock); - if (!l) - return (void *)1; - return llc_get_sk_idx(--l); + return l ? llc_get_sk_idx(--l) : (void *)1; } static void *llc_seq_next(struct seq_file *seq, void *v, loff_t *pos) -- cgit v1.2.3 From 45f0e972148c30bc84edf7d7c228bd6d3db0ba8a Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 6 Oct 2002 18:18:10 -0300 Subject: o X25: use seq_file for proc stuff Also some CodingStyle cleanups. --- include/net/x25.h | 11 ++- net/x25/Makefile | 2 +- net/x25/af_x25.c | 146 +++++++++-------------------- net/x25/x25_proc.c | 263 ++++++++++++++++++++++++++++++++++++++++++++++++++++ net/x25/x25_route.c | 65 +------------ 5 files changed, 320 insertions(+), 167 deletions(-) create mode 100644 net/x25/x25_proc.c (limited to 'include') diff --git a/include/net/x25.h b/include/net/x25.h index a043f5e093c8..98fb713f3121 100644 --- a/include/net/x25.h +++ b/include/net/x25.h @@ -220,9 +220,8 @@ extern void x25_enquiry_response(struct sock *); /* x25_route.c */ extern struct x25_route *x25_get_route(struct x25_address *addr); extern struct net_device *x25_dev_get(char *); -extern void x25_route_device_down(struct net_device *); +extern void x25_route_device_down(struct net_device *dev); extern int x25_route_ioctl(unsigned int, void *); -extern int x25_routes_get_info(char *, char **, off_t, int); extern void x25_route_free(void); static __inline__ void x25_route_hold(struct x25_route *rt) @@ -263,4 +262,12 @@ struct x25_skb_cb { unsigned flags; }; #define X25_SKB_CB(s) ((struct x25_skb_cb *) ((s)->cb)) + +extern struct sock *x25_list; +extern rwlock_t x25_list_lock; +extern struct list_head x25_route_list; +extern rwlock_t x25_route_list_lock; + +extern int x25_proc_init(void); +extern void x25_proc_exit(void); #endif diff --git a/net/x25/Makefile b/net/x25/Makefile index 7656831c6c69..eb24260baafc 100644 --- a/net/x25/Makefile +++ b/net/x25/Makefile @@ -6,7 +6,7 @@ obj-$(CONFIG_X25) += x25.o x25-y := af_x25.o x25_dev.o x25_facilities.o x25_in.o \ x25_link.o x25_out.o x25_route.o x25_subr.o \ - x25_timer.o + x25_timer.o x25_proc.o x25-$(CONFIG_SYSCTL) += sysctl_net_x25.o x25-objs := $(x25-y) diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index 97ac8aa10235..89c6026256c9 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -27,6 +27,8 @@ * 2000-10-02 Henner Eisen Made x25_kick() single threaded per socket. * 2000-10-27 Henner Eisen MSG_DONTWAIT for fragment allocation. * 2000-11-14 Henner Eisen Closing datalink from NETDEV_GOING_DOWN + * 2002-10-06 Arnaldo C. Melo Get rid of cli/sti, move proc stuff to + * x25_proc.c, using seq_file */ #include @@ -55,7 +57,6 @@ #include #include #include -#include #include #include @@ -65,8 +66,8 @@ int sysctl_x25_reset_request_timeout = X25_DEFAULT_T22; int sysctl_x25_clear_request_timeout = X25_DEFAULT_T23; int sysctl_x25_ack_holdback_timeout = X25_DEFAULT_T2; -static struct sock *x25_list; -static rwlock_t x25_list_lock = RW_LOCK_UNLOCKED; +struct sock *x25_list; +rwlock_t x25_list_lock = RW_LOCK_UNLOCKED; static struct proto_ops x25_proto_ops; @@ -246,8 +247,10 @@ static struct sock *x25_find_listener(struct x25_address *addr) read_lock_bh(&x25_list_lock); for (s = x25_list; s; s = s->next) - if ((!strcmp(addr->x25_addr, x25_sk(s)->source_addr.x25_addr) || - !strcmp(addr->x25_addr, null_x25_address.x25_addr)) && + if ((!strcmp(addr->x25_addr, + x25_sk(s)->source_addr.x25_addr) || + !strcmp(addr->x25_addr, + null_x25_address.x25_addr)) && s->state == TCP_LISTEN) break; @@ -318,12 +321,13 @@ static void x25_destroy_timer(unsigned long data) } /* - * This is called from user mode and the timers. Thus it protects itself against - * interrupt users but doesn't worry about being called during work. - * Once it is removed from the queue no interrupt or bottom half will - * touch it and we are (fairly 8-) ) safe. + * This is called from user mode and the timers. Thus it protects itself + * against interrupt users but doesn't worry about being called during + * work. Once it is removed from the queue no interrupt or bottom half + * will touch it and we are (fairly 8-) ) safe. + * Not static as it's used by the timer */ -void x25_destroy_socket(struct sock *sk) /* Not static as it's used by the timer */ +void x25_destroy_socket(struct sock *sk) { struct sk_buff *skb; @@ -337,7 +341,10 @@ void x25_destroy_socket(struct sock *sk) /* Not static as it's used by the timer while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) { if (skb->sk != sk) { /* A pending connection */ - skb->sk->dead = 1; /* Queue the unaccepted socket for death */ + /* + * Queue the unaccepted socket for death + */ + skb->sk->dead = 1; x25_start_heartbeat(skb->sk); x25_sk(skb->sk)->state = X25_STATE_0; } @@ -631,7 +638,8 @@ static int x25_wait_for_connection_establishment(struct sock *sk) return rc; } -static int x25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags) +static int x25_connect(struct socket *sock, struct sockaddr *uaddr, + int addr_len, int flags) { struct sock *sk = sock->sk; struct x25_opt *x25 = x25_sk(sk); @@ -642,7 +650,7 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len lock_sock(sk); if (sk->state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) { sock->state = SS_CONNECTED; - goto out; /* Connect completed during a ERESTARTSYS event */ + goto out; /* Connect completed during a ERESTARTSYS event */ } rc = -ECONNREFUSED; @@ -679,7 +687,7 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len goto out_put_neigh; rc = -EINVAL; - if (sk->zapped) /* Must bind first - autobinding does not work */ + if (sk->zapped) /* Must bind first - autobinding does not work */ goto out_put_neigh; if (!strcmp(x25->source_addr.x25_addr, null_x25_address.x25_addr)) @@ -785,7 +793,8 @@ out: return rc; } -static int x25_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer) +static int x25_getname(struct socket *sock, struct sockaddr *uaddr, + int *uaddr_len, int peer) { struct sockaddr_x25 *sx25 = (struct sockaddr_x25 *)uaddr; struct sock *sk = sock->sk; @@ -804,7 +813,8 @@ static int x25_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_l return 0; } -int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb, unsigned int lci) +int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb, + unsigned int lci) { struct sock *sk; struct sock *make; @@ -906,7 +916,8 @@ out_clear_request: goto out; } -static int x25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm) +static int x25_sendmsg(struct socket *sock, struct msghdr *msg, int len, + struct scm_cookie *scm) { struct sock *sk = sock->sk; struct x25_opt *x25 = x25_sk(sk); @@ -1118,7 +1129,8 @@ static int x25_recvmsg(struct socket *sock, struct msghdr *msg, int size, msg->msg_flags |= MSG_OOB; } else { /* Now we can treat all alike */ - skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &rc); + skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, + flags & MSG_DONTWAIT, &rc); if (!skb) goto out; @@ -1236,14 +1248,16 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) break; case SIOCX25GFACILITIES: { struct x25_facilities fac = x25->facilities; - rc = copy_to_user((void *)arg, &fac, sizeof(fac)) ? -EFAULT : 0; + rc = copy_to_user((void *)arg, &fac, + sizeof(fac)) ? -EFAULT : 0; break; } case SIOCX25SFACILITIES: { struct x25_facilities facilities; rc = -EFAULT; - if (copy_from_user(&facilities, (void *)arg, sizeof(facilities))) + if (copy_from_user(&facilities, (void *)arg, + sizeof(facilities))) break; rc = -EINVAL; if (sk->state != TCP_LISTEN && sk->state != TCP_CLOSE) @@ -1269,7 +1283,8 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) case SIOCX25GCALLUSERDATA: { struct x25_calluserdata cud = x25->calluserdata; - rc = copy_to_user((void *)arg, &cud, sizeof(cud)) ? -EFAULT : 0; + rc = copy_to_user((void *)arg, &cud, + sizeof(cud)) ? -EFAULT : 0; break; } @@ -1277,7 +1292,8 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) struct x25_calluserdata calluserdata; rc = -EFAULT; - if (copy_from_user(&calluserdata, (void *)arg, sizeof(calluserdata))) + if (copy_from_user(&calluserdata, (void *)arg, + sizeof(calluserdata))) break; rc = -EINVAL; if (calluserdata.cudlength > X25_MAX_CUD_LEN) @@ -1290,7 +1306,8 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) case SIOCX25GCAUSEDIAG: { struct x25_causediag causediag; causediag = x25->causediag; - rc = copy_to_user((void *)arg, &causediag, sizeof(causediag)) ? -EFAULT : 0; + rc = copy_to_user((void *)arg, &causediag, + sizeof(causediag)) ? -EFAULT : 0; break; } @@ -1302,70 +1319,6 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) return rc; } -static int x25_get_info(char *buffer, char **start, off_t offset, int length) -{ - struct sock *s; - struct net_device *dev; - const char *devname; - off_t pos = 0; - off_t begin = 0; - int len = sprintf(buffer, "dest_addr src_addr dev lci st vs vr " - "va t t2 t21 t22 t23 Snd-Q Rcv-Q inode\n"); - - read_lock_bh(&x25_list_lock); - - for (s = x25_list; s; s = s->next) { - struct x25_opt *x25 = x25_sk(s); - - if (!x25->neighbour || (dev = x25->neighbour->dev) == NULL) - devname = "???"; - else - devname = x25->neighbour->dev->name; - - len += sprintf(buffer + len, "%-10s %-10s %-5s %3.3X %d %d " - "%d %d %3lu %3lu %3lu %3lu %3lu " - "%5d %5d %ld\n", - !x25->dest_addr.x25_addr[0] ? "*" : - x25->dest_addr.x25_addr, - !x25->source_addr.x25_addr[0] ? "*" : - x25->source_addr.x25_addr, - devname, - x25->lci & 0x0FFF, - x25->state, - x25->vs, - x25->vr, - x25->va, - x25_display_timer(s) / HZ, - x25->t2 / HZ, - x25->t21 / HZ, - x25->t22 / HZ, - x25->t23 / HZ, - atomic_read(&s->wmem_alloc), - atomic_read(&s->rmem_alloc), - s->socket ? SOCK_INODE(s->socket)->i_ino : 0L); - - pos = begin + len; - - if (pos < offset) { - len = 0; - begin = pos; - } - - if (pos > offset + length) - break; - } - - read_unlock_bh(&x25_list_lock); - - *start = buffer + (offset - begin); - len -= (offset - begin); - - if (len > length) - len = length; - - return len; -} - struct net_proto_family x25_family_ops = { .family = AF_X25, .create = x25_create, @@ -1395,7 +1348,6 @@ static struct proto_ops SOCKOPS_WRAPPED(x25_proto_ops) = { #include SOCKOPS_WRAP(x25_proto, AF_X25); - static struct packet_type x25_packet_type = { .type = __constant_htons(ETH_P_X25), .func = x25_lapb_receive_frame, @@ -1435,9 +1387,7 @@ static int __init x25_init(void) x25_register_sysctl(); #endif - proc_net_create("x25", 0, x25_get_info); - proc_net_create("x25_routes", 0, x25_routes_get_info); - + x25_proc_init(); #ifdef MODULE /* * Register any pre existing devices. @@ -1457,18 +1407,9 @@ static int __init x25_init(void) } module_init(x25_init); - - -MODULE_AUTHOR("Jonathan Naylor "); -MODULE_DESCRIPTION("The X.25 Packet Layer network layer protocol"); -MODULE_LICENSE("GPL"); - static void __exit x25_exit(void) { - - proc_net_remove("x25"); - proc_net_remove("x25_routes"); - + x25_proc_exit(); x25_link_free(); x25_route_free(); @@ -1484,3 +1425,6 @@ static void __exit x25_exit(void) } module_exit(x25_exit); +MODULE_AUTHOR("Jonathan Naylor "); +MODULE_DESCRIPTION("The X.25 Packet Layer network layer protocol"); +MODULE_LICENSE("GPL"); diff --git a/net/x25/x25_proc.c b/net/x25/x25_proc.c new file mode 100644 index 000000000000..23aa74e273d4 --- /dev/null +++ b/net/x25/x25_proc.c @@ -0,0 +1,263 @@ +/* + * X.25 Packet Layer release 002 + * + * This is ALPHA test software. This code may break your machine, + * randomly fail to work with new releases, misbehave and/or generally + * screw up. It might even work. + * + * This code REQUIRES 2.4 with seq_file support + * + * This module: + * This module 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 of the License, or (at your option) any later version. + * + * History + * 2002/10/06 Arnaldo Carvalho de Melo seq_file support + */ + +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_PROC_FS +static __inline__ struct x25_route *x25_get_route_idx(loff_t pos) +{ + struct list_head *route_entry; + struct x25_route *rt = NULL; + + list_for_each(route_entry, &x25_route_list) { + rt = list_entry(route_entry, struct x25_route, node); + if (--pos) + break; + } + + return rt; +} + +static void *x25_seq_route_start(struct seq_file *seq, loff_t *pos) +{ + loff_t l = *pos; + + read_lock_bh(&x25_route_list_lock); + return l ? x25_get_route_idx(--l) : (void *)1; +} + +static void *x25_seq_route_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct x25_route *rt; + + ++*pos; + if (v == (void *)1) { + rt = NULL; + if (!list_empty(&x25_route_list)) + rt = list_entry(x25_route_list.next, + struct x25_route, node); + goto out; + } + rt = v; + if (rt->node.next != &x25_route_list) + rt = list_entry(rt->node.next, struct x25_route, node); + else + rt = NULL; +out: + return rt; +} + +static void x25_seq_route_stop(struct seq_file *seq, void *v) +{ + read_unlock_bh(&x25_route_list_lock); +} + +static int x25_seq_route_show(struct seq_file *seq, void *v) +{ + struct x25_route *rt; + + if (v == (void *)1) { + seq_puts(seq, "Address Digits Device\n"); + goto out; + } + + rt = v; + seq_printf(seq, "%-15s %-6d %-5s\n", + rt->address.x25_addr, rt->sigdigits, + rt->dev ? rt->dev->name : "???"); +out: + return 0; +} + +static __inline__ struct sock *x25_get_socket_idx(loff_t pos) +{ + struct sock *s; + + for (s = x25_list; pos && s; s = s->next) + --pos; + + return s; +} + +static void *x25_seq_socket_start(struct seq_file *seq, loff_t *pos) +{ + loff_t l = *pos; + + read_lock_bh(&x25_list_lock); + return l ? x25_get_socket_idx(--l) : (void *)1; +} + +static void *x25_seq_socket_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct sock *s; + + ++*pos; + if (v == (void *)1) { + s = NULL; + if (x25_list) + s = x25_list; + goto out; + } + s = v; + s = s->next; +out: + return s; +} + +static void x25_seq_socket_stop(struct seq_file *seq, void *v) +{ + read_unlock_bh(&x25_list_lock); +} + +static int x25_seq_socket_show(struct seq_file *seq, void *v) +{ + struct sock *s; + struct x25_opt *x25; + struct net_device *dev; + const char *devname; + + if (v == (void *)1) { + seq_printf(seq, "dest_addr src_addr dev lci st vs vr " + "va t t2 t21 t22 t23 Snd-Q Rcv-Q inode\n"); + goto out; + } + + s = v; + x25 = x25_sk(s); + + if (!x25->neighbour || (dev = x25->neighbour->dev) == NULL) + devname = "???"; + else + devname = x25->neighbour->dev->name; + + seq_printf(seq, "%-10s %-10s %-5s %3.3X %d %d %d %d %3lu %3lu " + "%3lu %3lu %3lu %5d %5d %ld\n", + !x25->dest_addr.x25_addr[0] ? "*" : x25->dest_addr.x25_addr, + !x25->source_addr.x25_addr[0] ? "*" : x25->source_addr.x25_addr, + devname, x25->lci & 0x0FFF, x25->state, x25->vs, x25->vr, + x25->va, x25_display_timer(s) / HZ, x25->t2 / HZ, + x25->t21 / HZ, x25->t22 / HZ, x25->t23 / HZ, + atomic_read(&s->wmem_alloc), atomic_read(&s->rmem_alloc), + s->socket ? SOCK_INODE(s->socket)->i_ino : 0L); +out: + return 0; +} + +struct seq_operations x25_seq_route_ops = { + .start = x25_seq_route_start, + .next = x25_seq_route_next, + .stop = x25_seq_route_stop, + .show = x25_seq_route_show, +}; + +struct seq_operations x25_seq_socket_ops = { + .start = x25_seq_socket_start, + .next = x25_seq_socket_next, + .stop = x25_seq_socket_stop, + .show = x25_seq_socket_show, +}; + +static int x25_seq_socket_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &x25_seq_socket_ops); +} + +static int x25_seq_route_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &x25_seq_route_ops); +} + +static struct file_operations x25_seq_socket_fops = { + .open = x25_seq_socket_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static struct file_operations x25_seq_route_fops = { + .open = x25_seq_route_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int x25_proc_perms(struct inode* inode, int op) +{ + return 0; +} + +static struct inode_operations x25_seq_inode = { + .permission = x25_proc_perms, +}; + +static struct proc_dir_entry *x25_proc_dir; + +int __init x25_proc_init(void) +{ + struct proc_dir_entry *p; + int rc = -ENOMEM; + + x25_proc_dir = proc_mkdir("x25", proc_net); + if (!x25_proc_dir) + goto out; + + p = create_proc_entry("route", 0, x25_proc_dir); + if (!p) + goto out_route; + p->proc_fops = &x25_seq_route_fops; + p->proc_iops = &x25_seq_inode; + + p = create_proc_entry("socket", 0, x25_proc_dir); + if (!p) + goto out_socket; + p->proc_fops = &x25_seq_socket_fops; + p->proc_iops = &x25_seq_inode; + rc = 0; +out: + return rc; +out_socket: + remove_proc_entry("route", x25_proc_dir); +out_route: + remove_proc_entry("x25", proc_net); + goto out; +} + +void __exit x25_proc_exit(void) +{ + remove_proc_entry("route", x25_proc_dir); + remove_proc_entry("socket", x25_proc_dir); + remove_proc_entry("x25", proc_net); +} + +#else /* CONFIG_PROC_FS */ + +int __init x25_proc_init(void) +{ + return 0; +} + +void __exit x25_proc_exit(void) +{ +} +#endif /* CONFIG_PROC_FS */ diff --git a/net/x25/x25_route.c b/net/x25/x25_route.c index 0513197a7f8b..07ae9d9e204a 100644 --- a/net/x25/x25_route.c +++ b/net/x25/x25_route.c @@ -18,34 +18,12 @@ */ #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include /* For TIOCINQ/OUTQ */ -#include -#include -#include #include #include -static struct list_head x25_route_list = LIST_HEAD_INIT(x25_route_list); -static rwlock_t x25_route_list_lock = RW_LOCK_UNLOCKED; +struct list_head x25_route_list = LIST_HEAD_INIT(x25_route_list); +rwlock_t x25_route_list_lock = RW_LOCK_UNLOCKED; /* * Add a new route. @@ -226,45 +204,6 @@ out: return rc; } -int x25_routes_get_info(char *buffer, char **start, off_t offset, int length) -{ - struct x25_route *rt; - struct list_head *entry; - off_t pos = 0; - off_t begin = 0; - int len = sprintf(buffer, "address digits device\n"); - - read_lock_bh(&x25_route_list_lock); - - list_for_each(entry, &x25_route_list) { - rt = list_entry(entry, struct x25_route, node); - len += sprintf(buffer + len, "%-15s %-6d %-5s\n", - rt->address.x25_addr, - rt->sigdigits, - rt->dev ? rt->dev->name : "???"); - - pos = begin + len; - - if (pos < offset) { - len = 0; - begin = pos; - } - - if (pos > offset + length) - break; - } - - read_unlock_bh(&x25_route_list_lock); - - *start = buffer + (offset - begin); - len -= (offset - begin); - - if (len > length) - len = length; - - return len; -} - /* * Release all memory associated with X.25 routing structures. */ -- cgit v1.2.3 From 102f07337e683bfbe50532e8864c609c98419f24 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 6 Oct 2002 21:27:57 -0300 Subject: o Appletalk: use seq_file for proc stuff And also move MODULE_LICENSE from aarp.c to ddp.c, as its there that the module_init/exit is. Also added MODULE_AUTHOR and MODULE_DESCRIPTION. --- include/linux/atalk.h | 14 ++ net/appletalk/Makefile | 2 +- net/appletalk/aarp.c | 22 --- net/appletalk/atalk_proc.c | 319 +++++++++++++++++++++++++++++++++++++++ net/appletalk/ddp.c | 244 ++++++------------------------ net/appletalk/sysctl_net_atalk.c | 7 +- 6 files changed, 385 insertions(+), 223 deletions(-) create mode 100644 net/appletalk/atalk_proc.c (limited to 'include') diff --git a/include/linux/atalk.h b/include/linux/atalk.h index e26dc1db8a41..477169eb5b28 100644 --- a/include/linux/atalk.h +++ b/include/linux/atalk.h @@ -198,5 +198,19 @@ extern void aarp_cleanup_module(void); #define at_sk(__sk) ((struct atalk_sock *)(__sk)->protinfo) +extern struct sock *atalk_sockets; +extern spinlock_t atalk_sockets_lock; + +extern struct atalk_route *atalk_routes; +extern rwlock_t atalk_routes_lock; + +extern struct atalk_iface *atalk_interfaces; +extern spinlock_t atalk_interfaces_lock; + +extern struct atalk_route atrtr_default; + +extern int atalk_proc_init(void); +extern void atalk_proc_exit(void); + #endif /* __KERNEL__ */ #endif /* __LINUX_ATALK_H__ */ diff --git a/net/appletalk/Makefile b/net/appletalk/Makefile index 14c4e7c55e0a..0f8309f9d5a6 100644 --- a/net/appletalk/Makefile +++ b/net/appletalk/Makefile @@ -6,7 +6,7 @@ export-objs = ddp.o obj-$(CONFIG_ATALK) += appletalk.o -appletalk-y := aarp.o ddp.o +appletalk-y := aarp.o ddp.o atalk_proc.o appletalk-$(CONFIG_SYSCTL) += sysctl_net_atalk.o appletalk-objs := $(appletalk-y) diff --git a/net/appletalk/aarp.c b/net/appletalk/aarp.c index c86f71734d9c..ee2303344c7a 100644 --- a/net/appletalk/aarp.c +++ b/net/appletalk/aarp.c @@ -30,34 +30,13 @@ */ #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include #include #include #include #include #include #include -#include int sysctl_aarp_expiry_time = AARP_EXPIRY_TIME; int sysctl_aarp_tick_time = AARP_TICK_TIME; @@ -995,4 +974,3 @@ void aarp_unregister_proc_fs(void) proc_net_remove("aarp"); } #endif -MODULE_LICENSE("GPL"); diff --git a/net/appletalk/atalk_proc.c b/net/appletalk/atalk_proc.c new file mode 100644 index 000000000000..7a990eff3066 --- /dev/null +++ b/net/appletalk/atalk_proc.c @@ -0,0 +1,319 @@ +/* + * atalk_proc.c - proc support for Appletalk + * + * Copyright(c) Arnaldo Carvalho de Melo + * + * This program 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, version 2. + */ + +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_PROC_FS +static __inline__ struct atalk_iface *atalk_get_interface_idx(loff_t pos) +{ + struct atalk_iface *i; + + for (i = atalk_interfaces; pos && i; i = i->next) + --pos; + + return i; +} + +static void *atalk_seq_interface_start(struct seq_file *seq, loff_t *pos) +{ + loff_t l = *pos; + + spin_lock_bh(&atalk_interfaces_lock); + return l ? atalk_get_interface_idx(--l) : (void *)1; +} + +static void *atalk_seq_interface_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct atalk_iface *i; + + ++*pos; + if (v == (void *)1) { + i = NULL; + if (atalk_interfaces) + i = atalk_interfaces; + goto out; + } + i = v; + i = i->next; +out: + return i; +} + +static void atalk_seq_interface_stop(struct seq_file *seq, void *v) +{ + spin_unlock_bh(&atalk_interfaces_lock); +} + +static int atalk_seq_interface_show(struct seq_file *seq, void *v) +{ + struct atalk_iface *iface; + + if (v == (void *)1) { + seq_puts(seq, "Interface Address Networks " + "Status\n"); + goto out; + } + + iface = v; + seq_printf(seq, "%-16s %04X:%02X %04X-%04X %d\n", + iface->dev->name, ntohs(iface->address.s_net), + iface->address.s_node, ntohs(iface->nets.nr_firstnet), + ntohs(iface->nets.nr_lastnet), iface->status); +out: + return 0; +} + +static __inline__ struct atalk_route *atalk_get_route_idx(loff_t pos) +{ + struct atalk_route *r; + + for (r = atalk_routes; pos && r; r = r->next) + --pos; + + return r; +} + +static void *atalk_seq_route_start(struct seq_file *seq, loff_t *pos) +{ + loff_t l = *pos; + + read_lock_bh(&atalk_routes_lock); + return l ? atalk_get_route_idx(--l) : (void *)1; +} + +static void *atalk_seq_route_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct atalk_route *r; + + ++*pos; + if (v == (void *)1) { + r = NULL; + if (atalk_routes) + r = atalk_routes; + goto out; + } + r = v; + r = r->next; +out: + return r; +} + +static void atalk_seq_route_stop(struct seq_file *seq, void *v) +{ + read_unlock_bh(&atalk_routes_lock); +} + +static int atalk_seq_route_show(struct seq_file *seq, void *v) +{ + struct atalk_route *rt; + + if (v == (void *)1) { + seq_puts(seq, "Target Router Flags Dev\n"); + goto out; + } + + if (atrtr_default.dev) { + rt = &atrtr_default; + seq_printf(seq, "Default %04X:%02X %-4d %s\n", + ntohs(rt->gateway.s_net), rt->gateway.s_node, + rt->flags, rt->dev->name); + } + + rt = v; + seq_printf(seq, "%04X:%02X %04X:%02X %-4d %s\n", + ntohs(rt->target.s_net), rt->target.s_node, + ntohs(rt->gateway.s_net), rt->gateway.s_node, + rt->flags, rt->dev->name); +out: + return 0; +} + +static __inline__ struct sock *atalk_get_socket_idx(loff_t pos) +{ + struct sock *s; + + for (s = atalk_sockets; pos && s; s = s->next) + --pos; + + return s; +} + +static void *atalk_seq_socket_start(struct seq_file *seq, loff_t *pos) +{ + loff_t l = *pos; + + spin_lock_bh(&atalk_sockets_lock); + return l ? atalk_get_socket_idx(--l) : (void *)1; +} + +static void *atalk_seq_socket_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct sock *i; + + ++*pos; + if (v == (void *)1) { + i = NULL; + if (atalk_sockets) + i = atalk_sockets; + goto out; + } + i = v; + i = i->next; +out: + return i; +} + +static void atalk_seq_socket_stop(struct seq_file *seq, void *v) +{ + spin_unlock_bh(&atalk_sockets_lock); +} + +static int atalk_seq_socket_show(struct seq_file *seq, void *v) +{ + struct sock *s; + struct atalk_sock *at; + + if (v == (void *)1) { + seq_printf(seq, "Type Local_addr Remote_addr Tx_queue " + "Rx_queue St UID\n"); + goto out; + } + + s = v; + at = at_sk(s); + + seq_printf(seq, "%02X %04X:%02X:%02X %04X:%02X:%02X %08X:%08X " + "%02X %d\n", + s->type, ntohs(at->src_net), at->src_node, at->src_port, + ntohs(at->dest_net), at->dest_node, at->dest_port, + atomic_read(&s->wmem_alloc), atomic_read(&s->rmem_alloc), + s->state, SOCK_INODE(s->socket)->i_uid); +out: + return 0; +} + +struct seq_operations atalk_seq_interface_ops = { + .start = atalk_seq_interface_start, + .next = atalk_seq_interface_next, + .stop = atalk_seq_interface_stop, + .show = atalk_seq_interface_show, +}; + +struct seq_operations atalk_seq_route_ops = { + .start = atalk_seq_route_start, + .next = atalk_seq_route_next, + .stop = atalk_seq_route_stop, + .show = atalk_seq_route_show, +}; + +struct seq_operations atalk_seq_socket_ops = { + .start = atalk_seq_socket_start, + .next = atalk_seq_socket_next, + .stop = atalk_seq_socket_stop, + .show = atalk_seq_socket_show, +}; + +static int atalk_seq_interface_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &atalk_seq_interface_ops); +} + +static int atalk_seq_route_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &atalk_seq_route_ops); +} + +static int atalk_seq_socket_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &atalk_seq_socket_ops); +} + +static struct file_operations atalk_seq_interface_fops = { + .open = atalk_seq_interface_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static struct file_operations atalk_seq_route_fops = { + .open = atalk_seq_route_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static struct file_operations atalk_seq_socket_fops = { + .open = atalk_seq_socket_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static struct proc_dir_entry *atalk_proc_dir; + +int __init atalk_proc_init(void) +{ + struct proc_dir_entry *p; + int rc = -ENOMEM; + + atalk_proc_dir = proc_mkdir("atalk", proc_net); + if (!atalk_proc_dir) + goto out; + + p = create_proc_entry("interface", S_IRUGO, atalk_proc_dir); + if (!p) + goto out_interface; + p->proc_fops = &atalk_seq_interface_fops; + + p = create_proc_entry("route", S_IRUGO, atalk_proc_dir); + if (!p) + goto out_route; + p->proc_fops = &atalk_seq_route_fops; + + p = create_proc_entry("socket", S_IRUGO, atalk_proc_dir); + if (!p) + goto out_socket; + p->proc_fops = &atalk_seq_socket_fops; + + rc = 0; +out: + return rc; +out_socket: + remove_proc_entry("route", atalk_proc_dir); +out_route: + remove_proc_entry("interface", atalk_proc_dir); +out_interface: + remove_proc_entry("atalk", proc_net); + goto out; +} + +void __exit atalk_proc_exit(void) +{ + remove_proc_entry("interface", atalk_proc_dir); + remove_proc_entry("route", atalk_proc_dir); + remove_proc_entry("socket", atalk_proc_dir); + remove_proc_entry("atalk", proc_net); +} + +#else /* CONFIG_PROC_FS */ +int __init atalk_proc_init(void) +{ + return 0; +} + +void __exit atalk_proc_exit(void) +{ +} +#endif /* CONFIG_PROC_FS */ diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index 3a3eae32fa43..5b1dc1368548 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -40,6 +40,8 @@ * result. * Arnaldo C. de Melo : Cleanup, in preparation for * shared skb support 8) + * Arnaldo C. de Melo : Move proc stuff to atalk_proc.c, + * use seq_file * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -50,41 +52,14 @@ #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include #include /* For TIOCOUTQ/INQ */ #include -#include #include #include -#include #include #include -#include -#include -#include #ifdef CONFIG_PROC_FS extern void aarp_register_proc_fs(void); @@ -112,8 +87,8 @@ static struct proto_ops atalk_dgram_ops; * * \**************************************************************************/ -static struct sock *atalk_sockets; -static spinlock_t atalk_sockets_lock = SPIN_LOCK_UNLOCKED; +struct sock *atalk_sockets; +spinlock_t atalk_sockets_lock = SPIN_LOCK_UNLOCKED; extern inline void atalk_insert_socket(struct sock *sk) { @@ -244,53 +219,6 @@ extern inline void atalk_destroy_socket(struct sock *sk) } } -/* Called from proc fs */ -static int atalk_get_info(char *buffer, char **start, off_t offset, int length) -{ - off_t pos = 0; - off_t begin = 0; - int len = sprintf(buffer, "Type local_addr remote_addr tx_queue " - "rx_queue st uid\n"); - struct sock *s; - /* Output the AppleTalk data for the /proc filesystem */ - - spin_lock_bh(&atalk_sockets_lock); - for (s = atalk_sockets; s; s = s->next) { - struct atalk_sock *at = at_sk(s); - - len += sprintf(buffer + len, "%02X ", s->type); - len += sprintf(buffer + len, "%04X:%02X:%02X ", - ntohs(at->src_net), at->src_node, at->src_port); - len += sprintf(buffer + len, "%04X:%02X:%02X ", - ntohs(at->dest_net), at->dest_node, - at->dest_port); - len += sprintf(buffer + len, "%08X:%08X ", - atomic_read(&s->wmem_alloc), - atomic_read(&s->rmem_alloc)); - len += sprintf(buffer + len, "%02X %d\n", s->state, - SOCK_INODE(s->socket)->i_uid); - - /* Are we still dumping unwanted data then discard the record */ - pos = begin + len; - - if (pos < offset) { - len = 0; /* Keep dumping into the buffer start */ - begin = pos; - } - if (pos > offset + length) /* We have dumped enough */ - break; - } - spin_unlock_bh(&atalk_sockets_lock); - - /* The data in question runs from begin to begin + len */ - *start = buffer + offset - begin; /* Start of wanted data */ - len -= offset - begin; /* Remove unwanted header data from length */ - if (len > length) - len = length; /* Remove unwanted tail data from length */ - - return len; -} - /**************************************************************************\ * * * Routing tables for the AppleTalk socket layer. * @@ -298,14 +226,14 @@ static int atalk_get_info(char *buffer, char **start, off_t offset, int length) \**************************************************************************/ /* Anti-deadlock ordering is router_lock --> iface_lock -DaveM */ -static struct atalk_route *atalk_router_list; -static rwlock_t atalk_router_lock = RW_LOCK_UNLOCKED; +struct atalk_route *atalk_routes; +rwlock_t atalk_routes_lock = RW_LOCK_UNLOCKED; -static struct atalk_iface *atalk_iface_list; -static spinlock_t atalk_iface_lock = SPIN_LOCK_UNLOCKED; +struct atalk_iface *atalk_interfaces; +spinlock_t atalk_interfaces_lock = SPIN_LOCK_UNLOCKED; /* For probing devices or in a routerless network */ -static struct atalk_route atrtr_default; +struct atalk_route atrtr_default; /* AppleTalk interface control */ /* @@ -314,10 +242,10 @@ static struct atalk_route atrtr_default; */ static void atif_drop_device(struct net_device *dev) { - struct atalk_iface **iface = &atalk_iface_list; + struct atalk_iface **iface = &atalk_interfaces; struct atalk_iface *tmp; - spin_lock_bh(&atalk_iface_lock); + spin_lock_bh(&atalk_interfaces_lock); while ((tmp = *iface) != NULL) { if (tmp->dev == dev) { *iface = tmp->next; @@ -327,7 +255,7 @@ static void atif_drop_device(struct net_device *dev) } else iface = &tmp->next; } - spin_unlock_bh(&atalk_iface_lock); + spin_unlock_bh(&atalk_interfaces_lock); } static struct atalk_iface *atif_add_device(struct net_device *dev, @@ -346,10 +274,10 @@ static struct atalk_iface *atif_add_device(struct net_device *dev, iface->address = *sa; iface->status = 0; - spin_lock_bh(&atalk_iface_lock); - iface->next = atalk_iface_list; - atalk_iface_list = iface; - spin_unlock_bh(&atalk_iface_lock); + spin_lock_bh(&atalk_interfaces_lock); + iface->next = atalk_interfaces; + atalk_interfaces = iface; + spin_unlock_bh(&atalk_interfaces_lock); out: return iface; out_mem: @@ -466,8 +394,8 @@ static struct atalk_addr *atalk_find_primary(void) * Return a point-to-point interface only if * there is no non-ptp interface available. */ - spin_lock_bh(&atalk_iface_lock); - for (iface = atalk_iface_list; iface; iface = iface->next) { + spin_lock_bh(&atalk_interfaces_lock); + for (iface = atalk_interfaces; iface; iface = iface->next) { if (!fiface && !(iface->dev->flags & IFF_LOOPBACK)) fiface = iface; if (!(iface->dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT))) { @@ -478,12 +406,12 @@ static struct atalk_addr *atalk_find_primary(void) if (fiface) retval = &fiface->address; - else if (atalk_iface_list) - retval = &atalk_iface_list->address; + else if (atalk_interfaces) + retval = &atalk_interfaces->address; else retval = NULL; out: - spin_unlock_bh(&atalk_iface_lock); + spin_unlock_bh(&atalk_interfaces_lock); return retval; } @@ -514,8 +442,8 @@ static struct atalk_iface *atalk_find_interface(int net, int node) { struct atalk_iface *iface; - spin_lock_bh(&atalk_iface_lock); - for (iface = atalk_iface_list; iface; iface = iface->next) { + spin_lock_bh(&atalk_interfaces_lock); + for (iface = atalk_interfaces; iface; iface = iface->next) { if ((node == ATADDR_BCAST || node == ATADDR_ANYNODE || iface->address.s_node == node) && @@ -529,7 +457,7 @@ static struct atalk_iface *atalk_find_interface(int net, int node) ntohs(net) <= ntohs(iface->nets.nr_lastnet)) break; } - spin_unlock_bh(&atalk_iface_lock); + spin_unlock_bh(&atalk_interfaces_lock); return iface; } @@ -549,8 +477,8 @@ static struct atalk_route *atrtr_find(struct atalk_addr *target) struct atalk_route *net_route = NULL; struct atalk_route *r; - read_lock_bh(&atalk_router_lock); - for (r = atalk_router_list; r; r = r->next) { + read_lock_bh(&atalk_routes_lock); + for (r = atalk_routes; r; r = r->next) { if (!(r->flags & RTF_UP)) continue; @@ -582,7 +510,7 @@ static struct atalk_route *atrtr_find(struct atalk_addr *target) else /* No route can be found */ r = NULL; out: - read_unlock_bh(&atalk_router_lock); + read_unlock_bh(&atalk_routes_lock); return r; } @@ -630,8 +558,8 @@ static int atrtr_create(struct rtentry *r, struct net_device *devhint) goto out; /* Now walk the routing table and make our decisions */ - write_lock_bh(&atalk_router_lock); - for (rt = atalk_router_list; rt; rt = rt->next) { + write_lock_bh(&atalk_routes_lock); + for (rt = atalk_routes; rt; rt = rt->next) { if (r->rt_flags != rt->flags) continue; @@ -646,8 +574,8 @@ static int atrtr_create(struct rtentry *r, struct net_device *devhint) if (!devhint) { riface = NULL; - spin_lock_bh(&atalk_iface_lock); - for (iface = atalk_iface_list; iface; iface = iface->next) { + spin_lock_bh(&atalk_interfaces_lock); + for (iface = atalk_interfaces; iface; iface = iface->next) { if (!riface && ntohs(ga->sat_addr.s_net) >= ntohs(iface->nets.nr_firstnet) && @@ -659,7 +587,7 @@ static int atrtr_create(struct rtentry *r, struct net_device *devhint) ga->sat_addr.s_node == iface->address.s_node) riface = iface; } - spin_unlock_bh(&atalk_iface_lock); + spin_unlock_bh(&atalk_interfaces_lock); retval = -ENETUNREACH; if (!riface) @@ -675,8 +603,8 @@ static int atrtr_create(struct rtentry *r, struct net_device *devhint) if (!rt) goto out; - rt->next = atalk_router_list; - atalk_router_list = rt; + rt->next = atalk_routes; + atalk_routes = rt; } /* Fill in the routing entry */ @@ -687,7 +615,7 @@ static int atrtr_create(struct rtentry *r, struct net_device *devhint) retval = 0; out_unlock: - write_unlock_bh(&atalk_router_lock); + write_unlock_bh(&atalk_routes_lock); out: return retval; } @@ -695,11 +623,11 @@ out: /* Delete a route. Find it and discard it */ static int atrtr_delete(struct atalk_addr * addr) { - struct atalk_route **r = &atalk_router_list; + struct atalk_route **r = &atalk_routes; int retval = 0; struct atalk_route *tmp; - write_lock_bh(&atalk_router_lock); + write_lock_bh(&atalk_routes_lock); while ((tmp = *r) != NULL) { if (tmp->target.s_net == addr->s_net && (!(tmp->flags&RTF_GATEWAY) || @@ -712,7 +640,7 @@ static int atrtr_delete(struct atalk_addr * addr) } retval = -ENOENT; out: - write_unlock_bh(&atalk_router_lock); + write_unlock_bh(&atalk_routes_lock); return retval; } @@ -722,10 +650,10 @@ out: */ void atrtr_device_down(struct net_device *dev) { - struct atalk_route **r = &atalk_router_list; + struct atalk_route **r = &atalk_routes; struct atalk_route *tmp; - write_lock_bh(&atalk_router_lock); + write_lock_bh(&atalk_routes_lock); while ((tmp = *r) != NULL) { if (tmp->dev == dev) { *r = tmp->next; @@ -733,7 +661,7 @@ void atrtr_device_down(struct net_device *dev) } else r = &tmp->next; } - write_unlock_bh(&atalk_router_lock); + write_unlock_bh(&atalk_routes_lock); if (atrtr_default.dev == dev) atrtr_set_default(NULL); @@ -1013,81 +941,6 @@ static int atrtr_ioctl(unsigned int cmd, void *arg) return -EINVAL; } -/* Called from proc fs - just make it print the ifaces neatly */ -static int atalk_if_get_info(char *buffer, char **start, off_t offset, - int length) -{ - off_t pos = 0; - off_t begin = 0; - struct atalk_iface *iface; - int len = sprintf(buffer, "Interface Address " - "Networks Status\n"); - - spin_lock_bh(&atalk_iface_lock); - for (iface = atalk_iface_list; iface; iface = iface->next) { - len += sprintf(buffer + len, "%-16s %04X:%02X %04X-%04X %d\n", - iface->dev->name, ntohs(iface->address.s_net), - iface->address.s_node, - ntohs(iface->nets.nr_firstnet), - ntohs(iface->nets.nr_lastnet), iface->status); - pos = begin + len; - if (pos < offset) { - len = 0; - begin = pos; - } - if (pos > offset + length) - break; - } - spin_unlock_bh(&atalk_iface_lock); - - *start = buffer + (offset - begin); - len -= (offset - begin); - if (len > length) - len = length; - return len; -} - -/* Called from proc fs - just make it print the routes neatly */ -static int atalk_rt_get_info(char *buffer, char **start, off_t offset, - int length) -{ - off_t pos = 0; - off_t begin = 0; - int len = sprintf(buffer, "Target Router Flags Dev\n"); - struct atalk_route *rt; - - if (atrtr_default.dev) { - rt = &atrtr_default; - len += sprintf(buffer + len, - "Default %04X:%02X %-4d %s\n", - ntohs(rt->gateway.s_net), rt->gateway.s_node, - rt->flags, rt->dev->name); - } - - read_lock_bh(&atalk_router_lock); - for (rt = atalk_router_list; rt; rt = rt->next) { - len += sprintf(buffer + len, - "%04X:%02X %04X:%02X %-4d %s\n", - ntohs(rt->target.s_net), rt->target.s_node, - ntohs(rt->gateway.s_net), rt->gateway.s_node, - rt->flags, rt->dev->name); - pos = begin + len; - if (pos < offset) { - len = 0; - begin = pos; - } - if (pos > offset + length) - break; - } - read_unlock_bh(&atalk_router_lock); - - *start = buffer + (offset - begin); - len -= (offset - begin); - if (len > length) - len = length; - return len; -} - /**************************************************************************\ * * * Handling for system calls applied via the various interfaces to an * @@ -1991,17 +1844,14 @@ static int __init atalk_init(void) register_netdevice_notifier(&ddp_notifier); aarp_proto_init(); - - proc_net_create("appletalk", 0, atalk_get_info); - proc_net_create("atalk_route", 0, atalk_rt_get_info); - proc_net_create("atalk_iface", 0, atalk_if_get_info); + atalk_proc_init(); #ifdef CONFIG_PROC_FS aarp_register_proc_fs(); #endif /* CONFIG_PROC_FS */ #ifdef CONFIG_SYSCTL atalk_register_sysctl(); #endif /* CONFIG_SYSCTL */ - printk(KERN_INFO "NET4: AppleTalk 0.18a for Linux NET4.0\n"); + printk(KERN_INFO "NET4: AppleTalk 0.20 for Linux NET4.0\n"); return 0; } module_init(atalk_init); @@ -2024,9 +1874,7 @@ static void __exit atalk_exit(void) #ifdef CONFIG_SYSCTL atalk_unregister_sysctl(); #endif /* CONFIG_SYSCTL */ - proc_net_remove("appletalk"); - proc_net_remove("atalk_route"); - proc_net_remove("atalk_iface"); + atalk_proc_exit(); #ifdef CONFIG_PROC_FS aarp_unregister_proc_fs(); #endif /* CONFIG_PROC_FS */ @@ -2039,3 +1887,7 @@ static void __exit atalk_exit(void) } module_exit(atalk_exit); #endif /* MODULE */ + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Alan Cox "); +MODULE_DESCRIPTION("AppleTalk 0.20 for Linux NET4.0\n"); diff --git a/net/appletalk/sysctl_net_atalk.c b/net/appletalk/sysctl_net_atalk.c index 663df18c826a..ea6a990c77d8 100644 --- a/net/appletalk/sysctl_net_atalk.c +++ b/net/appletalk/sysctl_net_atalk.c @@ -7,7 +7,6 @@ */ #include -#include #include extern int sysctl_aarp_expiry_time; @@ -16,7 +15,7 @@ extern int sysctl_aarp_retransmit_limit; extern int sysctl_aarp_resolve_time; #ifdef CONFIG_SYSCTL -static ctl_table atalk_table[] = { +static struct ctl_table atalk_table[] = { { .ctl_name = NET_ATALK_AARP_EXPIRY_TIME, .procname = "aarp-expiry-time", @@ -52,7 +51,7 @@ static ctl_table atalk_table[] = { { 0 }, }; -static ctl_table atalk_dir_table[] = { +static struct ctl_table atalk_dir_table[] = { { .ctl_name = NET_ATALK, .procname = "appletalk", @@ -62,7 +61,7 @@ static ctl_table atalk_dir_table[] = { { 0 }, }; -static ctl_table atalk_root_table[] = { +static struct ctl_table atalk_root_table[] = { { .ctl_name = CTL_NET, .procname = "net", -- cgit v1.2.3