| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531 |
- /*-
- * SPDX-License-Identifier: BSD-3-Clause
- *
- * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
- * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
- * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * a) Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * b) Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the distribution.
- *
- * c) Neither the name of Cisco Systems, Inc. nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- #include <sys/cdefs.h>
- __FBSDID("$FreeBSD$");
- #endif
- #include <netinet/sctp_os.h>
- #include <netinet/sctp_var.h>
- #include <netinet/sctp_sysctl.h>
- #include <netinet/sctp_pcb.h>
- #include <netinet/sctp_header.h>
- #include <netinet/sctputil.h>
- #include <netinet/sctp_output.h>
- #include <netinet/sctp_asconf.h>
- #include <netinet/sctp_timer.h>
- /*
- * debug flags:
- * SCTP_DEBUG_ASCONF1: protocol info, general info and errors
- * SCTP_DEBUG_ASCONF2: detailed info
- */
- /*
- * RFC 5061
- *
- * An ASCONF parameter queue exists per asoc which holds the pending address
- * operations. Lists are updated upon receipt of ASCONF-ACK.
- *
- * A restricted_addrs list exists per assoc to hold local addresses that are
- * not (yet) usable by the assoc as a source address. These addresses are
- * either pending an ASCONF operation (and exist on the ASCONF parameter
- * queue), or they are permanently restricted (the peer has returned an
- * ERROR indication to an ASCONF(ADD), or the peer does not support ASCONF).
- *
- * Deleted addresses are always immediately removed from the lists as they will
- * (shortly) no longer exist in the kernel. We send ASCONFs as a courtesy,
- * only if allowed.
- */
- /*
- * ASCONF parameter processing.
- * response_required: set if a reply is required (eg. SUCCESS_REPORT).
- * returns a mbuf to an "error" response parameter or NULL/"success" if ok.
- * FIX: allocating this many mbufs on the fly is pretty inefficient...
- */
- static struct mbuf *
- sctp_asconf_success_response(uint32_t id)
- {
- struct mbuf *m_reply = NULL;
- struct sctp_asconf_paramhdr *aph;
- m_reply = sctp_get_mbuf_for_msg(sizeof(struct sctp_asconf_paramhdr),
- 0, M_NOWAIT, 1, MT_DATA);
- if (m_reply == NULL) {
- SCTPDBG(SCTP_DEBUG_ASCONF1,
- "asconf_success_response: couldn't get mbuf!\n");
- return (NULL);
- }
- aph = mtod(m_reply, struct sctp_asconf_paramhdr *);
- aph->correlation_id = id;
- aph->ph.param_type = htons(SCTP_SUCCESS_REPORT);
- aph->ph.param_length = sizeof(struct sctp_asconf_paramhdr);
- SCTP_BUF_LEN(m_reply) = aph->ph.param_length;
- aph->ph.param_length = htons(aph->ph.param_length);
- return (m_reply);
- }
- static struct mbuf *
- sctp_asconf_error_response(uint32_t id, uint16_t cause, uint8_t *error_tlv,
- uint16_t tlv_length)
- {
- struct mbuf *m_reply = NULL;
- struct sctp_asconf_paramhdr *aph;
- struct sctp_error_cause *error;
- uint32_t buf_len;
- uint16_t i, param_length, cause_length, padding_length;
- uint8_t *tlv;
- if (error_tlv == NULL) {
- tlv_length = 0;
- }
- cause_length = sizeof(struct sctp_error_cause) + tlv_length;
- param_length = sizeof(struct sctp_asconf_paramhdr) + cause_length;
- padding_length = tlv_length % 4;
- if (padding_length != 0) {
- padding_length = 4 - padding_length;
- }
- buf_len = param_length + padding_length;
- if (buf_len > MLEN) {
- SCTPDBG(SCTP_DEBUG_ASCONF1,
- "asconf_error_response: tlv_length (%xh) too big\n",
- tlv_length);
- return (NULL);
- }
- m_reply = sctp_get_mbuf_for_msg(buf_len, 0, M_NOWAIT, 1, MT_DATA);
- if (m_reply == NULL) {
- SCTPDBG(SCTP_DEBUG_ASCONF1,
- "asconf_error_response: couldn't get mbuf!\n");
- return (NULL);
- }
- aph = mtod(m_reply, struct sctp_asconf_paramhdr *);
- aph->ph.param_type = htons(SCTP_ERROR_CAUSE_IND);
- aph->ph.param_length = htons(param_length);
- aph->correlation_id = id;
- error = (struct sctp_error_cause *)(aph + 1);
- error->code = htons(cause);
- error->length = htons(cause_length);
- if (error_tlv != NULL) {
- tlv = (uint8_t *) (error + 1);
- memcpy(tlv, error_tlv, tlv_length);
- for (i = 0; i < padding_length; i++) {
- tlv[tlv_length + i] = 0;
- }
- }
- SCTP_BUF_LEN(m_reply) = buf_len;
- return (m_reply);
- }
- static struct mbuf *
- sctp_process_asconf_add_ip(struct sockaddr *src, struct sctp_asconf_paramhdr *aph,
- struct sctp_tcb *stcb, int send_hb, int response_required)
- {
- struct sctp_nets *net;
- struct mbuf *m_reply = NULL;
- union sctp_sockstore store;
- struct sctp_paramhdr *ph;
- uint16_t param_type, aparam_length;
- #if defined(INET) || defined(INET6)
- uint16_t param_length;
- #endif
- struct sockaddr *sa;
- int zero_address = 0;
- int bad_address = 0;
- #ifdef INET
- struct sockaddr_in *sin;
- struct sctp_ipv4addr_param *v4addr;
- #endif
- #ifdef INET6
- struct sockaddr_in6 *sin6;
- struct sctp_ipv6addr_param *v6addr;
- #endif
- aparam_length = ntohs(aph->ph.param_length);
- if (aparam_length < sizeof(struct sctp_asconf_paramhdr) + sizeof(struct sctp_paramhdr)) {
- return (NULL);
- }
- ph = (struct sctp_paramhdr *)(aph + 1);
- param_type = ntohs(ph->param_type);
- #if defined(INET) || defined(INET6)
- param_length = ntohs(ph->param_length);
- if (param_length + sizeof(struct sctp_asconf_paramhdr) != aparam_length) {
- return (NULL);
- }
- #endif
- sa = &store.sa;
- switch (param_type) {
- #ifdef INET
- case SCTP_IPV4_ADDRESS:
- if (param_length != sizeof(struct sctp_ipv4addr_param)) {
- /* invalid param size */
- return (NULL);
- }
- v4addr = (struct sctp_ipv4addr_param *)ph;
- sin = &store.sin;
- memset(sin, 0, sizeof(*sin));
- sin->sin_family = AF_INET;
- #ifdef HAVE_SIN_LEN
- sin->sin_len = sizeof(struct sockaddr_in);
- #endif
- sin->sin_port = stcb->rport;
- sin->sin_addr.s_addr = v4addr->addr;
- if ((sin->sin_addr.s_addr == INADDR_BROADCAST) ||
- IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
- bad_address = 1;
- }
- if (sin->sin_addr.s_addr == INADDR_ANY)
- zero_address = 1;
- SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_add_ip: adding ");
- SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa);
- break;
- #endif
- #ifdef INET6
- case SCTP_IPV6_ADDRESS:
- if (param_length != sizeof(struct sctp_ipv6addr_param)) {
- /* invalid param size */
- return (NULL);
- }
- v6addr = (struct sctp_ipv6addr_param *)ph;
- sin6 = &store.sin6;
- memset(sin6, 0, sizeof(*sin6));
- sin6->sin6_family = AF_INET6;
- #ifdef HAVE_SIN6_LEN
- sin6->sin6_len = sizeof(struct sockaddr_in6);
- #endif
- sin6->sin6_port = stcb->rport;
- memcpy((caddr_t)&sin6->sin6_addr, v6addr->addr,
- sizeof(struct in6_addr));
- if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
- bad_address = 1;
- }
- if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))
- zero_address = 1;
- SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_add_ip: adding ");
- SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa);
- break;
- #endif
- default:
- m_reply = sctp_asconf_error_response(aph->correlation_id,
- SCTP_CAUSE_INVALID_PARAM, (uint8_t *) aph,
- aparam_length);
- return (m_reply);
- } /* end switch */
- /* if 0.0.0.0/::0, add the source address instead */
- if (zero_address && SCTP_BASE_SYSCTL(sctp_nat_friendly)) {
- sa = src;
- SCTPDBG(SCTP_DEBUG_ASCONF1,
- "process_asconf_add_ip: using source addr ");
- SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, src);
- }
- net = NULL;
- /* add the address */
- if (bad_address) {
- m_reply = sctp_asconf_error_response(aph->correlation_id,
- SCTP_CAUSE_INVALID_PARAM, (uint8_t *) aph,
- aparam_length);
- } else if (sctp_add_remote_addr(stcb, sa, &net, stcb->asoc.port,
- SCTP_DONOT_SETSCOPE,
- SCTP_ADDR_DYNAMIC_ADDED) != 0) {
- SCTPDBG(SCTP_DEBUG_ASCONF1,
- "process_asconf_add_ip: error adding address\n");
- m_reply = sctp_asconf_error_response(aph->correlation_id,
- SCTP_CAUSE_RESOURCE_SHORTAGE, (uint8_t *) aph,
- aparam_length);
- } else {
- if (response_required) {
- m_reply =
- sctp_asconf_success_response(aph->correlation_id);
- }
- if (net != NULL) {
- /* notify upper layer */
- sctp_ulp_notify(SCTP_NOTIFY_ASCONF_ADD_IP, stcb, 0, sa, SCTP_SO_NOT_LOCKED);
- sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, stcb->sctp_ep, stcb, net);
- sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep,
- stcb, net);
- if (send_hb) {
- sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED);
- }
- }
- }
- return (m_reply);
- }
- static int
- sctp_asconf_del_remote_addrs_except(struct sctp_tcb *stcb, struct sockaddr *src)
- {
- struct sctp_nets *src_net, *net, *nnet;
- /* make sure the source address exists as a destination net */
- src_net = sctp_findnet(stcb, src);
- if (src_net == NULL) {
- /* not found */
- return (-1);
- }
- /* delete all destination addresses except the source */
- TAILQ_FOREACH_SAFE(net, &stcb->asoc.nets, sctp_next, nnet) {
- if (net != src_net) {
- /* delete this address */
- SCTPDBG(SCTP_DEBUG_ASCONF1,
- "asconf_del_remote_addrs_except: deleting ");
- SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1,
- (struct sockaddr *)&net->ro._l_addr);
- /* notify upper layer */
- sctp_ulp_notify(SCTP_NOTIFY_ASCONF_DELETE_IP, stcb, 0,
- (struct sockaddr *)&net->ro._l_addr, SCTP_SO_NOT_LOCKED);
- sctp_remove_net(stcb, net);
- }
- }
- return (0);
- }
- static struct mbuf *
- sctp_process_asconf_delete_ip(struct sockaddr *src,
- struct sctp_asconf_paramhdr *aph,
- struct sctp_tcb *stcb, int response_required)
- {
- struct mbuf *m_reply = NULL;
- union sctp_sockstore store;
- struct sctp_paramhdr *ph;
- uint16_t param_type, aparam_length;
- #if defined(INET) || defined(INET6)
- uint16_t param_length;
- #endif
- struct sockaddr *sa;
- int zero_address = 0;
- int result;
- #ifdef INET
- struct sockaddr_in *sin;
- struct sctp_ipv4addr_param *v4addr;
- #endif
- #ifdef INET6
- struct sockaddr_in6 *sin6;
- struct sctp_ipv6addr_param *v6addr;
- #endif
- aparam_length = ntohs(aph->ph.param_length);
- if (aparam_length < sizeof(struct sctp_asconf_paramhdr) + sizeof(struct sctp_paramhdr)) {
- return (NULL);
- }
- ph = (struct sctp_paramhdr *)(aph + 1);
- param_type = ntohs(ph->param_type);
- #if defined(INET) || defined(INET6)
- param_length = ntohs(ph->param_length);
- if (param_length + sizeof(struct sctp_asconf_paramhdr) != aparam_length) {
- return (NULL);
- }
- #endif
- sa = &store.sa;
- switch (param_type) {
- #ifdef INET
- case SCTP_IPV4_ADDRESS:
- if (param_length != sizeof(struct sctp_ipv4addr_param)) {
- /* invalid param size */
- return (NULL);
- }
- v4addr = (struct sctp_ipv4addr_param *)ph;
- sin = &store.sin;
- memset(sin, 0, sizeof(*sin));
- sin->sin_family = AF_INET;
- #ifdef HAVE_SIN_LEN
- sin->sin_len = sizeof(struct sockaddr_in);
- #endif
- sin->sin_port = stcb->rport;
- sin->sin_addr.s_addr = v4addr->addr;
- if (sin->sin_addr.s_addr == INADDR_ANY)
- zero_address = 1;
- SCTPDBG(SCTP_DEBUG_ASCONF1,
- "process_asconf_delete_ip: deleting ");
- SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa);
- break;
- #endif
- #ifdef INET6
- case SCTP_IPV6_ADDRESS:
- if (param_length != sizeof(struct sctp_ipv6addr_param)) {
- /* invalid param size */
- return (NULL);
- }
- v6addr = (struct sctp_ipv6addr_param *)ph;
- sin6 = &store.sin6;
- memset(sin6, 0, sizeof(*sin6));
- sin6->sin6_family = AF_INET6;
- #ifdef HAVE_SIN6_LEN
- sin6->sin6_len = sizeof(struct sockaddr_in6);
- #endif
- sin6->sin6_port = stcb->rport;
- memcpy(&sin6->sin6_addr, v6addr->addr,
- sizeof(struct in6_addr));
- if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))
- zero_address = 1;
- SCTPDBG(SCTP_DEBUG_ASCONF1,
- "process_asconf_delete_ip: deleting ");
- SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa);
- break;
- #endif
- default:
- m_reply = sctp_asconf_error_response(aph->correlation_id,
- SCTP_CAUSE_UNRESOLVABLE_ADDR, (uint8_t *) aph,
- aparam_length);
- return (m_reply);
- }
- /* make sure the source address is not being deleted */
- if (sctp_cmpaddr(sa, src)) {
- /* trying to delete the source address! */
- SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_delete_ip: tried to delete source addr\n");
- m_reply = sctp_asconf_error_response(aph->correlation_id,
- SCTP_CAUSE_DELETING_SRC_ADDR, (uint8_t *) aph,
- aparam_length);
- return (m_reply);
- }
- /* if deleting 0.0.0.0/::0, delete all addresses except src addr */
- if (zero_address && SCTP_BASE_SYSCTL(sctp_nat_friendly)) {
- result = sctp_asconf_del_remote_addrs_except(stcb, src);
- if (result) {
- /* src address did not exist? */
- SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_delete_ip: src addr does not exist?\n");
- /* what error to reply with?? */
- m_reply =
- sctp_asconf_error_response(aph->correlation_id,
- SCTP_CAUSE_REQUEST_REFUSED, (uint8_t *) aph,
- aparam_length);
- } else if (response_required) {
- m_reply =
- sctp_asconf_success_response(aph->correlation_id);
- }
- return (m_reply);
- }
- /* delete the address */
- result = sctp_del_remote_addr(stcb, sa);
- /*
- * note if result == -2, the address doesn't exist in the asoc but
- * since it's being deleted anyways, we just ack the delete -- but
- * this probably means something has already gone awry
- */
- if (result == -1) {
- /* only one address in the asoc */
- SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_delete_ip: tried to delete last IP addr!\n");
- m_reply = sctp_asconf_error_response(aph->correlation_id,
- SCTP_CAUSE_DELETING_LAST_ADDR, (uint8_t *) aph,
- aparam_length);
- } else {
- if (response_required) {
- m_reply = sctp_asconf_success_response(aph->correlation_id);
- }
- /* notify upper layer */
- sctp_ulp_notify(SCTP_NOTIFY_ASCONF_DELETE_IP, stcb, 0, sa, SCTP_SO_NOT_LOCKED);
- }
- return (m_reply);
- }
- static struct mbuf *
- sctp_process_asconf_set_primary(struct sockaddr *src,
- struct sctp_asconf_paramhdr *aph,
- struct sctp_tcb *stcb, int response_required)
- {
- struct mbuf *m_reply = NULL;
- union sctp_sockstore store;
- struct sctp_paramhdr *ph;
- uint16_t param_type, aparam_length;
- #if defined(INET) || defined(INET6)
- uint16_t param_length;
- #endif
- struct sockaddr *sa;
- int zero_address = 0;
- #ifdef INET
- struct sockaddr_in *sin;
- struct sctp_ipv4addr_param *v4addr;
- #endif
- #ifdef INET6
- struct sockaddr_in6 *sin6;
- struct sctp_ipv6addr_param *v6addr;
- #endif
- aparam_length = ntohs(aph->ph.param_length);
- if (aparam_length < sizeof(struct sctp_asconf_paramhdr) + sizeof(struct sctp_paramhdr)) {
- return (NULL);
- }
- ph = (struct sctp_paramhdr *)(aph + 1);
- param_type = ntohs(ph->param_type);
- #if defined(INET) || defined(INET6)
- param_length = ntohs(ph->param_length);
- if (param_length + sizeof(struct sctp_asconf_paramhdr) != aparam_length) {
- return (NULL);
- }
- #endif
- sa = &store.sa;
- switch (param_type) {
- #ifdef INET
- case SCTP_IPV4_ADDRESS:
- if (param_length != sizeof(struct sctp_ipv4addr_param)) {
- /* invalid param size */
- return (NULL);
- }
- v4addr = (struct sctp_ipv4addr_param *)ph;
- sin = &store.sin;
- memset(sin, 0, sizeof(*sin));
- sin->sin_family = AF_INET;
- #ifdef HAVE_SIN_LEN
- sin->sin_len = sizeof(struct sockaddr_in);
- #endif
- sin->sin_addr.s_addr = v4addr->addr;
- if (sin->sin_addr.s_addr == INADDR_ANY)
- zero_address = 1;
- SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_set_primary: ");
- SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa);
- break;
- #endif
- #ifdef INET6
- case SCTP_IPV6_ADDRESS:
- if (param_length != sizeof(struct sctp_ipv6addr_param)) {
- /* invalid param size */
- return (NULL);
- }
- v6addr = (struct sctp_ipv6addr_param *)ph;
- sin6 = &store.sin6;
- memset(sin6, 0, sizeof(*sin6));
- sin6->sin6_family = AF_INET6;
- #ifdef HAVE_SIN6_LEN
- sin6->sin6_len = sizeof(struct sockaddr_in6);
- #endif
- memcpy((caddr_t)&sin6->sin6_addr, v6addr->addr,
- sizeof(struct in6_addr));
- if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))
- zero_address = 1;
- SCTPDBG(SCTP_DEBUG_ASCONF1, "process_asconf_set_primary: ");
- SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa);
- break;
- #endif
- default:
- m_reply = sctp_asconf_error_response(aph->correlation_id,
- SCTP_CAUSE_UNRESOLVABLE_ADDR, (uint8_t *) aph,
- aparam_length);
- return (m_reply);
- }
- /* if 0.0.0.0/::0, use the source address instead */
- if (zero_address && SCTP_BASE_SYSCTL(sctp_nat_friendly)) {
- sa = src;
- SCTPDBG(SCTP_DEBUG_ASCONF1,
- "process_asconf_set_primary: using source addr ");
- SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, src);
- }
- /* set the primary address */
- if (sctp_set_primary_addr(stcb, sa, NULL) == 0) {
- SCTPDBG(SCTP_DEBUG_ASCONF1,
- "process_asconf_set_primary: primary address set\n");
- /* notify upper layer */
- sctp_ulp_notify(SCTP_NOTIFY_ASCONF_SET_PRIMARY, stcb, 0, sa, SCTP_SO_NOT_LOCKED);
- if ((stcb->asoc.primary_destination->dest_state & SCTP_ADDR_REACHABLE) &&
- ((stcb->asoc.primary_destination->dest_state & SCTP_ADDR_PF) == 0) &&
- (stcb->asoc.alternate != NULL)) {
- sctp_free_remote_addr(stcb->asoc.alternate);
- stcb->asoc.alternate = NULL;
- }
- if (response_required) {
- m_reply = sctp_asconf_success_response(aph->correlation_id);
- }
- /* Mobility adaptation.
- Ideally, when the reception of SET PRIMARY with DELETE IP
- ADDRESS of the previous primary destination, unacknowledged
- DATA are retransmitted immediately to the new primary
- destination for seamless handover.
- If the destination is UNCONFIRMED and marked to REQ_PRIM,
- The retransmission occur when reception of the
- HEARTBEAT-ACK. (See sctp_handle_heartbeat_ack in
- sctp_input.c)
- Also, when change of the primary destination, it is better
- that all subsequent new DATA containing already queued DATA
- are transmitted to the new primary destination. (by micchie)
- */
- if ((sctp_is_mobility_feature_on(stcb->sctp_ep,
- SCTP_MOBILITY_BASE) ||
- sctp_is_mobility_feature_on(stcb->sctp_ep,
- SCTP_MOBILITY_FASTHANDOFF)) &&
- sctp_is_mobility_feature_on(stcb->sctp_ep,
- SCTP_MOBILITY_PRIM_DELETED) &&
- (stcb->asoc.primary_destination->dest_state &
- SCTP_ADDR_UNCONFIRMED) == 0) {
- sctp_timer_stop(SCTP_TIMER_TYPE_PRIM_DELETED,
- stcb->sctp_ep, stcb, NULL,
- SCTP_FROM_SCTP_ASCONF + SCTP_LOC_1);
- if (sctp_is_mobility_feature_on(stcb->sctp_ep,
- SCTP_MOBILITY_FASTHANDOFF)) {
- sctp_assoc_immediate_retrans(stcb,
- stcb->asoc.primary_destination);
- }
- if (sctp_is_mobility_feature_on(stcb->sctp_ep,
- SCTP_MOBILITY_BASE)) {
- sctp_move_chunks_from_net(stcb,
- stcb->asoc.deleted_primary);
- }
- sctp_delete_prim_timer(stcb->sctp_ep, stcb);
- }
- } else {
- /* couldn't set the requested primary address! */
- SCTPDBG(SCTP_DEBUG_ASCONF1,
- "process_asconf_set_primary: set primary failed!\n");
- /* must have been an invalid address, so report */
- m_reply = sctp_asconf_error_response(aph->correlation_id,
- SCTP_CAUSE_UNRESOLVABLE_ADDR, (uint8_t *) aph,
- aparam_length);
- }
- return (m_reply);
- }
- /*
- * handles an ASCONF chunk.
- * if all parameters are processed ok, send a plain (empty) ASCONF-ACK
- */
- void
- sctp_handle_asconf(struct mbuf *m, unsigned int offset,
- struct sockaddr *src,
- struct sctp_asconf_chunk *cp, struct sctp_tcb *stcb,
- int first)
- {
- struct sctp_association *asoc;
- uint32_t serial_num;
- struct mbuf *n, *m_ack, *m_result, *m_tail;
- struct sctp_asconf_ack_chunk *ack_cp;
- struct sctp_asconf_paramhdr *aph;
- struct sctp_ipv6addr_param *p_addr;
- unsigned int asconf_limit, cnt;
- int error = 0; /* did an error occur? */
- /* asconf param buffer */
- uint8_t aparam_buf[SCTP_PARAM_BUFFER_SIZE];
- struct sctp_asconf_ack *ack, *ack_next;
- /* verify minimum length */
- if (ntohs(cp->ch.chunk_length) < sizeof(struct sctp_asconf_chunk)) {
- SCTPDBG(SCTP_DEBUG_ASCONF1,
- "handle_asconf: chunk too small = %xh\n",
- ntohs(cp->ch.chunk_length));
- return;
- }
- asoc = &stcb->asoc;
- serial_num = ntohl(cp->serial_number);
- if (SCTP_TSN_GE(asoc->asconf_seq_in, serial_num)) {
- /* got a duplicate ASCONF */
- SCTPDBG(SCTP_DEBUG_ASCONF1,
- "handle_asconf: got duplicate serial number = %xh\n",
- serial_num);
- return;
- } else if (serial_num != (asoc->asconf_seq_in + 1)) {
- SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: incorrect serial number = %xh (expected next = %xh)\n",
- serial_num, asoc->asconf_seq_in + 1);
- return;
- }
- /* it's the expected "next" sequence number, so process it */
- asoc->asconf_seq_in = serial_num; /* update sequence */
- /* get length of all the param's in the ASCONF */
- asconf_limit = offset + ntohs(cp->ch.chunk_length);
- SCTPDBG(SCTP_DEBUG_ASCONF1,
- "handle_asconf: asconf_limit=%u, sequence=%xh\n",
- asconf_limit, serial_num);
- if (first) {
- /* delete old cache */
- SCTPDBG(SCTP_DEBUG_ASCONF1,"handle_asconf: Now processing first ASCONF. Try to delete old cache\n");
- TAILQ_FOREACH_SAFE(ack, &asoc->asconf_ack_sent, next, ack_next) {
- if (ack->serial_number == serial_num)
- break;
- SCTPDBG(SCTP_DEBUG_ASCONF1,"handle_asconf: delete old(%u) < first(%u)\n",
- ack->serial_number, serial_num);
- TAILQ_REMOVE(&asoc->asconf_ack_sent, ack, next);
- if (ack->data != NULL) {
- sctp_m_freem(ack->data);
- }
- SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_asconf_ack), ack);
- }
- }
- m_ack = sctp_get_mbuf_for_msg(sizeof(struct sctp_asconf_ack_chunk), 0,
- M_NOWAIT, 1, MT_DATA);
- if (m_ack == NULL) {
- SCTPDBG(SCTP_DEBUG_ASCONF1,
- "handle_asconf: couldn't get mbuf!\n");
- return;
- }
- m_tail = m_ack; /* current reply chain's tail */
- /* fill in ASCONF-ACK header */
- ack_cp = mtod(m_ack, struct sctp_asconf_ack_chunk *);
- ack_cp->ch.chunk_type = SCTP_ASCONF_ACK;
- ack_cp->ch.chunk_flags = 0;
- ack_cp->serial_number = htonl(serial_num);
- /* set initial lengths (eg. just an ASCONF-ACK), ntohx at the end! */
- SCTP_BUF_LEN(m_ack) = sizeof(struct sctp_asconf_ack_chunk);
- ack_cp->ch.chunk_length = sizeof(struct sctp_asconf_ack_chunk);
- /* skip the lookup address parameter */
- offset += sizeof(struct sctp_asconf_chunk);
- p_addr = (struct sctp_ipv6addr_param *)sctp_m_getptr(m, offset, sizeof(struct sctp_paramhdr), (uint8_t *)&aparam_buf);
- if (p_addr == NULL) {
- SCTPDBG(SCTP_DEBUG_ASCONF1,
- "handle_asconf: couldn't get lookup addr!\n");
- /* respond with a missing/invalid mandatory parameter error */
- sctp_m_freem(m_ack);
- return;
- }
- /* skip lookup addr */
- offset += SCTP_SIZE32(ntohs(p_addr->ph.param_length));
- /* get pointer to first asconf param in ASCONF */
- aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(m, offset, sizeof(struct sctp_asconf_paramhdr), (uint8_t *)&aparam_buf);
- if (aph == NULL) {
- SCTPDBG(SCTP_DEBUG_ASCONF1, "Empty ASCONF received?\n");
- goto send_reply;
- }
- /* process through all parameters */
- cnt = 0;
- while (aph != NULL) {
- unsigned int param_length, param_type;
- param_type = ntohs(aph->ph.param_type);
- param_length = ntohs(aph->ph.param_length);
- if (offset + param_length > asconf_limit) {
- /* parameter goes beyond end of chunk! */
- sctp_m_freem(m_ack);
- return;
- }
- m_result = NULL;
- if (param_length > sizeof(aparam_buf)) {
- SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: param length (%u) larger than buffer size!\n", param_length);
- sctp_m_freem(m_ack);
- return;
- }
- if (param_length < sizeof(struct sctp_asconf_paramhdr)) {
- SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: param length (%u) too short\n", param_length);
- sctp_m_freem(m_ack);
- return;
- }
- /* get the entire parameter */
- aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(m, offset, param_length, aparam_buf);
- if (aph == NULL) {
- SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: couldn't get entire param\n");
- sctp_m_freem(m_ack);
- return;
- }
- switch (param_type) {
- case SCTP_ADD_IP_ADDRESS:
- m_result = sctp_process_asconf_add_ip(src, aph, stcb,
- (cnt < SCTP_BASE_SYSCTL(sctp_hb_maxburst)), error);
- cnt++;
- break;
- case SCTP_DEL_IP_ADDRESS:
- m_result = sctp_process_asconf_delete_ip(src, aph, stcb,
- error);
- break;
- case SCTP_ERROR_CAUSE_IND:
- /* not valid in an ASCONF chunk */
- break;
- case SCTP_SET_PRIM_ADDR:
- m_result = sctp_process_asconf_set_primary(src, aph,
- stcb, error);
- break;
- case SCTP_NAT_VTAGS:
- SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: sees a NAT VTAG state parameter\n");
- break;
- case SCTP_SUCCESS_REPORT:
- /* not valid in an ASCONF chunk */
- break;
- case SCTP_ULP_ADAPTATION:
- /* FIX */
- break;
- default:
- if ((param_type & 0x8000) == 0) {
- /* Been told to STOP at this param */
- asconf_limit = offset;
- /*
- * FIX FIX - We need to call
- * sctp_arethere_unrecognized_parameters()
- * to get a operr and send it for any
- * param's with the 0x4000 bit set OR do it
- * here ourselves... note we still must STOP
- * if the 0x8000 bit is clear.
- */
- }
- /* unknown/invalid param type */
- break;
- } /* switch */
- /* add any (error) result to the reply mbuf chain */
- if (m_result != NULL) {
- SCTP_BUF_NEXT(m_tail) = m_result;
- m_tail = m_result;
- ack_cp->ch.chunk_length += SCTP_BUF_LEN(m_result);
- /* set flag to force success reports */
- error = 1;
- }
- offset += SCTP_SIZE32(param_length);
- /* update remaining ASCONF message length to process */
- if (offset >= asconf_limit) {
- /* no more data in the mbuf chain */
- break;
- }
- /* get pointer to next asconf param */
- aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(m, offset,
- sizeof(struct sctp_asconf_paramhdr),
- (uint8_t *)&aparam_buf);
- if (aph == NULL) {
- /* can't get an asconf paramhdr */
- SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: can't get asconf param hdr!\n");
- /* FIX ME - add error here... */
- }
- }
- send_reply:
- ack_cp->ch.chunk_length = htons(ack_cp->ch.chunk_length);
- /* save the ASCONF-ACK reply */
- ack = SCTP_ZONE_GET(SCTP_BASE_INFO(ipi_zone_asconf_ack),
- struct sctp_asconf_ack);
- if (ack == NULL) {
- sctp_m_freem(m_ack);
- return;
- }
- ack->serial_number = serial_num;
- ack->last_sent_to = NULL;
- ack->data = m_ack;
- ack->len = 0;
- for (n = m_ack; n != NULL; n = SCTP_BUF_NEXT(n)) {
- ack->len += SCTP_BUF_LEN(n);
- }
- TAILQ_INSERT_TAIL(&stcb->asoc.asconf_ack_sent, ack, next);
- /* see if last_control_chunk_from is set properly (use IP src addr) */
- if (stcb->asoc.last_control_chunk_from == NULL) {
- /*
- * this could happen if the source address was just newly
- * added
- */
- SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: looking up net for IP source address\n");
- SCTPDBG(SCTP_DEBUG_ASCONF1, "Looking for IP source: ");
- SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, src);
- /* look up the from address */
- stcb->asoc.last_control_chunk_from = sctp_findnet(stcb, src);
- #ifdef SCTP_DEBUG
- if (stcb->asoc.last_control_chunk_from == NULL) {
- SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf: IP source address not found?!\n");
- }
- #endif
- }
- }
- /*
- * does the address match? returns 0 if not, 1 if so
- */
- static uint32_t
- sctp_asconf_addr_match(struct sctp_asconf_addr *aa, struct sockaddr *sa)
- {
- switch (sa->sa_family) {
- #ifdef INET6
- case AF_INET6:
- {
- /* XXX scopeid */
- struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
- if ((aa->ap.addrp.ph.param_type == SCTP_IPV6_ADDRESS) &&
- (memcmp(&aa->ap.addrp.addr, &sin6->sin6_addr,
- sizeof(struct in6_addr)) == 0)) {
- return (1);
- }
- break;
- }
- #endif
- #ifdef INET
- case AF_INET:
- {
- struct sockaddr_in *sin = (struct sockaddr_in *)sa;
- if ((aa->ap.addrp.ph.param_type == SCTP_IPV4_ADDRESS) &&
- (memcmp(&aa->ap.addrp.addr, &sin->sin_addr,
- sizeof(struct in_addr)) == 0)) {
- return (1);
- }
- break;
- }
- #endif
- default:
- break;
- }
- return (0);
- }
- /*
- * does the address match? returns 0 if not, 1 if so
- */
- static uint32_t
- sctp_addr_match(struct sctp_paramhdr *ph, struct sockaddr *sa)
- {
- #if defined(INET) || defined(INET6)
- uint16_t param_type, param_length;
- param_type = ntohs(ph->param_type);
- param_length = ntohs(ph->param_length);
- #endif
- switch (sa->sa_family) {
- #ifdef INET6
- case AF_INET6:
- {
- /* XXX scopeid */
- struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
- struct sctp_ipv6addr_param *v6addr;
- v6addr = (struct sctp_ipv6addr_param *)ph;
- if ((param_type == SCTP_IPV6_ADDRESS) &&
- (param_length == sizeof(struct sctp_ipv6addr_param)) &&
- (memcmp(&v6addr->addr, &sin6->sin6_addr,
- sizeof(struct in6_addr)) == 0)) {
- return (1);
- }
- break;
- }
- #endif
- #ifdef INET
- case AF_INET:
- {
- struct sockaddr_in *sin = (struct sockaddr_in *)sa;
- struct sctp_ipv4addr_param *v4addr;
- v4addr = (struct sctp_ipv4addr_param *)ph;
- if ((param_type == SCTP_IPV4_ADDRESS) &&
- (param_length == sizeof(struct sctp_ipv4addr_param)) &&
- (memcmp(&v4addr->addr, &sin->sin_addr,
- sizeof(struct in_addr)) == 0)) {
- return (1);
- }
- break;
- }
- #endif
- default:
- break;
- }
- return (0);
- }
- /*
- * Cleanup for non-responded/OP ERR'd ASCONF
- */
- void
- sctp_asconf_cleanup(struct sctp_tcb *stcb)
- {
- /*
- * clear out any existing asconfs going out
- */
- sctp_timer_stop(SCTP_TIMER_TYPE_ASCONF, stcb->sctp_ep, stcb, NULL,
- SCTP_FROM_SCTP_ASCONF + SCTP_LOC_2);
- stcb->asoc.asconf_seq_out_acked = stcb->asoc.asconf_seq_out;
- /* remove the old ASCONF on our outbound queue */
- sctp_toss_old_asconf(stcb);
- }
- /*
- * cleanup any cached source addresses that may be topologically
- * incorrect after a new address has been added to this interface.
- */
- static void
- sctp_asconf_nets_cleanup(struct sctp_tcb *stcb, struct sctp_ifn *ifn)
- {
- struct sctp_nets *net;
- /*
- * Ideally, we want to only clear cached routes and source addresses
- * that are topologically incorrect. But since there is no easy way
- * to know whether the newly added address on the ifn would cause a
- * routing change (i.e. a new egress interface would be chosen)
- * without doing a new routing lookup and source address selection,
- * we will (for now) just flush any cached route using a different
- * ifn (and cached source addrs) and let output re-choose them during
- * the next send on that net.
- */
- TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
- /*
- * clear any cached route (and cached source address) if the
- * route's interface is NOT the same as the address change.
- * If it's the same interface, just clear the cached source
- * address.
- */
- if (SCTP_ROUTE_HAS_VALID_IFN(&net->ro) &&
- ((ifn == NULL) ||
- (SCTP_GET_IF_INDEX_FROM_ROUTE(&net->ro) != ifn->ifn_index))) {
- /* clear any cached route */
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- RO_NHFREE(&net->ro);
- #else
- RTFREE(net->ro.ro_rt);
- net->ro.ro_rt = NULL;
- #endif
- }
- /* clear any cached source address */
- if (net->src_addr_selected) {
- sctp_free_ifa(net->ro._s_addr);
- net->ro._s_addr = NULL;
- net->src_addr_selected = 0;
- }
- }
- }
- void
- sctp_assoc_immediate_retrans(struct sctp_tcb *stcb, struct sctp_nets *dstnet)
- {
- int error;
- if (dstnet->dest_state & SCTP_ADDR_UNCONFIRMED) {
- return;
- }
- if (stcb->asoc.deleted_primary == NULL) {
- return;
- }
- if (!TAILQ_EMPTY(&stcb->asoc.sent_queue)) {
- SCTPDBG(SCTP_DEBUG_ASCONF1, "assoc_immediate_retrans: Deleted primary is ");
- SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, &stcb->asoc.deleted_primary->ro._l_addr.sa);
- SCTPDBG(SCTP_DEBUG_ASCONF1, "Current Primary is ");
- SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, &stcb->asoc.primary_destination->ro._l_addr.sa);
- sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb,
- stcb->asoc.deleted_primary,
- SCTP_FROM_SCTP_ASCONF + SCTP_LOC_3);
- stcb->asoc.num_send_timers_up--;
- if (stcb->asoc.num_send_timers_up < 0) {
- stcb->asoc.num_send_timers_up = 0;
- }
- SCTP_TCB_LOCK_ASSERT(stcb);
- error = sctp_t3rxt_timer(stcb->sctp_ep, stcb,
- stcb->asoc.deleted_primary);
- if (error) {
- SCTP_INP_DECR_REF(stcb->sctp_ep);
- return;
- }
- SCTP_TCB_LOCK_ASSERT(stcb);
- #ifdef SCTP_AUDITING_ENABLED
- sctp_auditing(4, stcb->sctp_ep, stcb, stcb->asoc.deleted_primary);
- #endif
- sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED);
- if ((stcb->asoc.num_send_timers_up == 0) &&
- (stcb->asoc.sent_queue_cnt > 0)) {
- struct sctp_tmit_chunk *chk;
- TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
- if (chk->whoTo != NULL) {
- break;
- }
- }
- if (chk != NULL) {
- sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, chk->whoTo);
- }
- }
- }
- return;
- }
- #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Userspace__)
- static int
- sctp_asconf_queue_mgmt(struct sctp_tcb *, struct sctp_ifa *, uint16_t);
- void
- sctp_net_immediate_retrans(struct sctp_tcb *stcb, struct sctp_nets *net)
- {
- struct sctp_tmit_chunk *chk;
- SCTPDBG(SCTP_DEBUG_ASCONF1, "net_immediate_retrans: RTO is %d\n", net->RTO);
- sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, net,
- SCTP_FROM_SCTP_ASCONF + SCTP_LOC_4);
- stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net);
- net->error_count = 0;
- TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
- if (chk->whoTo == net) {
- if (chk->sent < SCTP_DATAGRAM_RESEND) {
- chk->sent = SCTP_DATAGRAM_RESEND;
- sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
- sctp_flight_size_decrease(chk);
- sctp_total_flight_decrease(stcb, chk);
- net->marked_retrans++;
- stcb->asoc.marked_retrans++;
- }
- }
- }
- if (net->marked_retrans) {
- sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED);
- }
- }
- static void
- sctp_path_check_and_react(struct sctp_tcb *stcb, struct sctp_ifa *newifa)
- {
- struct sctp_nets *net;
- int addrnum, changed;
- /* If number of local valid addresses is 1, the valid address is
- probably newly added address.
- Several valid addresses in this association. A source address
- may not be changed. Additionally, they can be configured on a
- same interface as "alias" addresses. (by micchie)
- */
- addrnum = sctp_local_addr_count(stcb);
- SCTPDBG(SCTP_DEBUG_ASCONF1, "p_check_react(): %d local addresses\n",
- addrnum);
- if (addrnum == 1) {
- TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
- /* clear any cached route and source address */
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- RO_NHFREE(&net->ro);
- #else
- if (net->ro.ro_rt) {
- RTFREE(net->ro.ro_rt);
- net->ro.ro_rt = NULL;
- }
- #endif
- if (net->src_addr_selected) {
- sctp_free_ifa(net->ro._s_addr);
- net->ro._s_addr = NULL;
- net->src_addr_selected = 0;
- }
- /* Retransmit unacknowledged DATA chunks immediately */
- if (sctp_is_mobility_feature_on(stcb->sctp_ep,
- SCTP_MOBILITY_FASTHANDOFF)) {
- sctp_net_immediate_retrans(stcb, net);
- }
- /* also, SET PRIMARY is maybe already sent */
- }
- return;
- }
- /* Multiple local addresses exist in the association. */
- TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
- /* clear any cached route and source address */
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- RO_NHFREE(&net->ro);
- #else
- if (net->ro.ro_rt) {
- RTFREE(net->ro.ro_rt);
- net->ro.ro_rt = NULL;
- }
- #endif
- if (net->src_addr_selected) {
- sctp_free_ifa(net->ro._s_addr);
- net->ro._s_addr = NULL;
- net->src_addr_selected = 0;
- }
- /* Check if the nexthop is corresponding to the new address.
- If the new address is corresponding to the current nexthop,
- the path will be changed.
- If the new address is NOT corresponding to the current
- nexthop, the path will not be changed.
- */
- SCTP_RTALLOC((sctp_route_t *)&net->ro,
- stcb->sctp_ep->def_vrf_id,
- stcb->sctp_ep->fibnum);
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- if (net->ro.ro_nh == NULL)
- #else
- if (net->ro.ro_rt == NULL)
- #endif
- continue;
- changed = 0;
- switch (net->ro._l_addr.sa.sa_family) {
- #ifdef INET
- case AF_INET:
- if (sctp_v4src_match_nexthop(newifa, (sctp_route_t *)&net->ro)) {
- changed = 1;
- }
- break;
- #endif
- #ifdef INET6
- case AF_INET6:
- if (sctp_v6src_match_nexthop(
- &newifa->address.sin6, (sctp_route_t *)&net->ro)) {
- changed = 1;
- }
- break;
- #endif
- default:
- break;
- }
- /* if the newly added address does not relate routing
- information, we skip.
- */
- if (changed == 0)
- continue;
- /* Retransmit unacknowledged DATA chunks immediately */
- if (sctp_is_mobility_feature_on(stcb->sctp_ep,
- SCTP_MOBILITY_FASTHANDOFF)) {
- sctp_net_immediate_retrans(stcb, net);
- }
- /* Send SET PRIMARY for this new address */
- if (net == stcb->asoc.primary_destination) {
- (void)sctp_asconf_queue_mgmt(stcb, newifa,
- SCTP_SET_PRIM_ADDR);
- }
- }
- }
- #endif
- /*
- * process an ADD/DELETE IP ack from peer.
- * addr: corresponding sctp_ifa to the address being added/deleted.
- * type: SCTP_ADD_IP_ADDRESS or SCTP_DEL_IP_ADDRESS.
- * flag: 1=success, 0=failure.
- */
- static void
- sctp_asconf_addr_mgmt_ack(struct sctp_tcb *stcb, struct sctp_ifa *addr, uint32_t flag)
- {
- /*
- * do the necessary asoc list work- if we get a failure indication,
- * leave the address on the assoc's restricted list. If we get a
- * success indication, remove the address from the restricted list.
- */
- /*
- * Note: this will only occur for ADD_IP_ADDRESS, since
- * DEL_IP_ADDRESS is never actually added to the list...
- */
- if (flag) {
- /* success case, so remove from the restricted list */
- sctp_del_local_addr_restricted(stcb, addr);
- #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Userspace__)
- if (sctp_is_mobility_feature_on(stcb->sctp_ep,
- SCTP_MOBILITY_BASE) ||
- sctp_is_mobility_feature_on(stcb->sctp_ep,
- SCTP_MOBILITY_FASTHANDOFF)) {
- sctp_path_check_and_react(stcb, addr);
- return;
- }
- #endif
- /* clear any cached/topologically incorrect source addresses */
- sctp_asconf_nets_cleanup(stcb, addr->ifn_p);
- }
- /* else, leave it on the list */
- }
- /*
- * add an asconf add/delete/set primary IP address parameter to the queue.
- * type = SCTP_ADD_IP_ADDRESS, SCTP_DEL_IP_ADDRESS, SCTP_SET_PRIM_ADDR.
- * returns 0 if queued, -1 if not queued/removed.
- * NOTE: if adding, but a delete for the same address is already scheduled
- * (and not yet sent out), simply remove it from queue. Same for deleting
- * an address already scheduled for add. If a duplicate operation is found,
- * ignore the new one.
- */
- static int
- sctp_asconf_queue_mgmt(struct sctp_tcb *stcb, struct sctp_ifa *ifa,
- uint16_t type)
- {
- struct sctp_asconf_addr *aa, *aa_next;
- /* make sure the request isn't already in the queue */
- TAILQ_FOREACH_SAFE(aa, &stcb->asoc.asconf_queue, next, aa_next) {
- /* address match? */
- if (sctp_asconf_addr_match(aa, &ifa->address.sa) == 0)
- continue;
- /* is the request already in queue but not sent?
- * pass the request already sent in order to resolve the following case:
- * 1. arrival of ADD, then sent
- * 2. arrival of DEL. we can't remove the ADD request already sent
- * 3. arrival of ADD
- */
- if (aa->ap.aph.ph.param_type == type && aa->sent == 0) {
- return (-1);
- }
- /* is the negative request already in queue, and not sent */
- if ((aa->sent == 0) && (type == SCTP_ADD_IP_ADDRESS) &&
- (aa->ap.aph.ph.param_type == SCTP_DEL_IP_ADDRESS)) {
- /* add requested, delete already queued */
- TAILQ_REMOVE(&stcb->asoc.asconf_queue, aa, next);
- /* remove the ifa from the restricted list */
- sctp_del_local_addr_restricted(stcb, ifa);
- /* free the asconf param */
- SCTP_FREE(aa, SCTP_M_ASC_ADDR);
- SCTPDBG(SCTP_DEBUG_ASCONF2, "asconf_queue_mgmt: add removes queued entry\n");
- return (-1);
- }
- if ((aa->sent == 0) && (type == SCTP_DEL_IP_ADDRESS) &&
- (aa->ap.aph.ph.param_type == SCTP_ADD_IP_ADDRESS)) {
- /* delete requested, add already queued */
- TAILQ_REMOVE(&stcb->asoc.asconf_queue, aa, next);
- /* remove the aa->ifa from the restricted list */
- sctp_del_local_addr_restricted(stcb, aa->ifa);
- /* free the asconf param */
- SCTP_FREE(aa, SCTP_M_ASC_ADDR);
- SCTPDBG(SCTP_DEBUG_ASCONF2, "asconf_queue_mgmt: delete removes queued entry\n");
- return (-1);
- }
- } /* for each aa */
- /* adding new request to the queue */
- SCTP_MALLOC(aa, struct sctp_asconf_addr *, sizeof(*aa),
- SCTP_M_ASC_ADDR);
- if (aa == NULL) {
- /* didn't get memory */
- SCTPDBG(SCTP_DEBUG_ASCONF1, "asconf_queue_mgmt: failed to get memory!\n");
- return (-1);
- }
- aa->special_del = 0;
- /* fill in asconf address parameter fields */
- /* top level elements are "networked" during send */
- aa->ap.aph.ph.param_type = type;
- aa->ifa = ifa;
- atomic_add_int(&ifa->refcount, 1);
- /* correlation_id filled in during send routine later... */
- switch (ifa->address.sa.sa_family) {
- #ifdef INET6
- case AF_INET6:
- {
- struct sockaddr_in6 *sin6;
- sin6 = &ifa->address.sin6;
- aa->ap.addrp.ph.param_type = SCTP_IPV6_ADDRESS;
- aa->ap.addrp.ph.param_length = (sizeof(struct sctp_ipv6addr_param));
- aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_paramhdr) +
- sizeof(struct sctp_ipv6addr_param);
- memcpy(&aa->ap.addrp.addr, &sin6->sin6_addr,
- sizeof(struct in6_addr));
- break;
- }
- #endif
- #ifdef INET
- case AF_INET:
- {
- struct sockaddr_in *sin;
- sin = &ifa->address.sin;
- aa->ap.addrp.ph.param_type = SCTP_IPV4_ADDRESS;
- aa->ap.addrp.ph.param_length = (sizeof(struct sctp_ipv4addr_param));
- aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_paramhdr) +
- sizeof(struct sctp_ipv4addr_param);
- memcpy(&aa->ap.addrp.addr, &sin->sin_addr,
- sizeof(struct in_addr));
- break;
- }
- #endif
- default:
- /* invalid family! */
- SCTP_FREE(aa, SCTP_M_ASC_ADDR);
- sctp_free_ifa(ifa);
- return (-1);
- }
- aa->sent = 0; /* clear sent flag */
- TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next);
- #ifdef SCTP_DEBUG
- if (SCTP_BASE_SYSCTL(sctp_debug_on) & SCTP_DEBUG_ASCONF2) {
- if (type == SCTP_ADD_IP_ADDRESS) {
- SCTP_PRINTF("asconf_queue_mgmt: inserted asconf ADD_IP_ADDRESS: ");
- SCTPDBG_ADDR(SCTP_DEBUG_ASCONF2, &ifa->address.sa);
- } else if (type == SCTP_DEL_IP_ADDRESS) {
- SCTP_PRINTF("asconf_queue_mgmt: appended asconf DEL_IP_ADDRESS: ");
- SCTPDBG_ADDR(SCTP_DEBUG_ASCONF2, &ifa->address.sa);
- } else {
- SCTP_PRINTF("asconf_queue_mgmt: appended asconf SET_PRIM_ADDR: ");
- SCTPDBG_ADDR(SCTP_DEBUG_ASCONF2, &ifa->address.sa);
- }
- }
- #endif
- return (0);
- }
- /*
- * add an asconf operation for the given ifa and type.
- * type = SCTP_ADD_IP_ADDRESS, SCTP_DEL_IP_ADDRESS, SCTP_SET_PRIM_ADDR.
- * returns 0 if completed, -1 if not completed, 1 if immediate send is
- * advisable.
- */
- static int
- sctp_asconf_queue_add(struct sctp_tcb *stcb, struct sctp_ifa *ifa,
- uint16_t type)
- {
- uint32_t status;
- int pending_delete_queued = 0;
- int last;
- /* see if peer supports ASCONF */
- if (stcb->asoc.asconf_supported == 0) {
- return (-1);
- }
- /*
- * if this is deleting the last address from the assoc, mark it as
- * pending.
- */
- if ((type == SCTP_DEL_IP_ADDRESS) && !stcb->asoc.asconf_del_pending) {
- if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
- last = (sctp_local_addr_count(stcb) == 0);
- } else {
- last = (sctp_local_addr_count(stcb) == 1);
- }
- if (last) {
- /* set the pending delete info only */
- stcb->asoc.asconf_del_pending = 1;
- stcb->asoc.asconf_addr_del_pending = ifa;
- atomic_add_int(&ifa->refcount, 1);
- SCTPDBG(SCTP_DEBUG_ASCONF2,
- "asconf_queue_add: mark delete last address pending\n");
- return (-1);
- }
- }
- /* queue an asconf parameter */
- status = sctp_asconf_queue_mgmt(stcb, ifa, type);
- /*
- * if this is an add, and there is a delete also pending (i.e. the
- * last local address is being changed), queue the pending delete too.
- */
- if ((type == SCTP_ADD_IP_ADDRESS) && stcb->asoc.asconf_del_pending && (status == 0)) {
- /* queue in the pending delete */
- if (sctp_asconf_queue_mgmt(stcb,
- stcb->asoc.asconf_addr_del_pending,
- SCTP_DEL_IP_ADDRESS) == 0) {
- SCTPDBG(SCTP_DEBUG_ASCONF2, "asconf_queue_add: queuing pending delete\n");
- pending_delete_queued = 1;
- /* clear out the pending delete info */
- stcb->asoc.asconf_del_pending = 0;
- sctp_free_ifa(stcb->asoc.asconf_addr_del_pending);
- stcb->asoc.asconf_addr_del_pending = NULL;
- }
- }
- if (pending_delete_queued) {
- struct sctp_nets *net;
- /*
- * since we know that the only/last address is now being
- * changed in this case, reset the cwnd/rto on all nets to
- * start as a new address and path. Also clear the error
- * counts to give the assoc the best chance to complete the
- * address change.
- */
- TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
- stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb,
- net);
- net->RTO = 0;
- net->error_count = 0;
- }
- stcb->asoc.overall_error_count = 0;
- if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) {
- sctp_misc_ints(SCTP_THRESHOLD_CLEAR,
- stcb->asoc.overall_error_count,
- 0,
- SCTP_FROM_SCTP_ASCONF,
- __LINE__);
- }
- /* queue in an advisory set primary too */
- (void)sctp_asconf_queue_mgmt(stcb, ifa, SCTP_SET_PRIM_ADDR);
- /* let caller know we should send this out immediately */
- status = 1;
- }
- return (status);
- }
- /*-
- * add an asconf delete IP address parameter to the queue by sockaddr and
- * possibly with no sctp_ifa available. This is only called by the routine
- * that checks the addresses in an INIT-ACK against the current address list.
- * returns 0 if completed, non-zero if not completed.
- * NOTE: if an add is already scheduled (and not yet sent out), simply
- * remove it from queue. If a duplicate operation is found, ignore the
- * new one.
- */
- static int
- sctp_asconf_queue_sa_delete(struct sctp_tcb *stcb, struct sockaddr *sa)
- {
- struct sctp_ifa *ifa;
- struct sctp_asconf_addr *aa, *aa_next;
- if (stcb == NULL) {
- return (-1);
- }
- /* see if peer supports ASCONF */
- if (stcb->asoc.asconf_supported == 0) {
- return (-1);
- }
- /* make sure the request isn't already in the queue */
- TAILQ_FOREACH_SAFE(aa, &stcb->asoc.asconf_queue, next, aa_next) {
- /* address match? */
- if (sctp_asconf_addr_match(aa, sa) == 0)
- continue;
- /* is the request already in queue (sent or not) */
- if (aa->ap.aph.ph.param_type == SCTP_DEL_IP_ADDRESS) {
- return (-1);
- }
- /* is the negative request already in queue, and not sent */
- if (aa->sent == 1)
- continue;
- if (aa->ap.aph.ph.param_type == SCTP_ADD_IP_ADDRESS) {
- /* add already queued, so remove existing entry */
- TAILQ_REMOVE(&stcb->asoc.asconf_queue, aa, next);
- sctp_del_local_addr_restricted(stcb, aa->ifa);
- /* free the entry */
- SCTP_FREE(aa, SCTP_M_ASC_ADDR);
- return (-1);
- }
- } /* for each aa */
- /* find any existing ifa-- NOTE ifa CAN be allowed to be NULL */
- ifa = sctp_find_ifa_by_addr(sa, stcb->asoc.vrf_id, SCTP_ADDR_NOT_LOCKED);
- /* adding new request to the queue */
- SCTP_MALLOC(aa, struct sctp_asconf_addr *, sizeof(*aa),
- SCTP_M_ASC_ADDR);
- if (aa == NULL) {
- /* didn't get memory */
- SCTPDBG(SCTP_DEBUG_ASCONF1,
- "sctp_asconf_queue_sa_delete: failed to get memory!\n");
- return (-1);
- }
- aa->special_del = 0;
- /* fill in asconf address parameter fields */
- /* top level elements are "networked" during send */
- aa->ap.aph.ph.param_type = SCTP_DEL_IP_ADDRESS;
- aa->ifa = ifa;
- if (ifa)
- atomic_add_int(&ifa->refcount, 1);
- /* correlation_id filled in during send routine later... */
- switch (sa->sa_family) {
- #ifdef INET6
- case AF_INET6:
- {
- /* IPv6 address */
- struct sockaddr_in6 *sin6;
- sin6 = (struct sockaddr_in6 *)sa;
- aa->ap.addrp.ph.param_type = SCTP_IPV6_ADDRESS;
- aa->ap.addrp.ph.param_length = (sizeof(struct sctp_ipv6addr_param));
- aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_paramhdr) + sizeof(struct sctp_ipv6addr_param);
- memcpy(&aa->ap.addrp.addr, &sin6->sin6_addr,
- sizeof(struct in6_addr));
- break;
- }
- #endif
- #ifdef INET
- case AF_INET:
- {
- /* IPv4 address */
- struct sockaddr_in *sin = (struct sockaddr_in *)sa;
- aa->ap.addrp.ph.param_type = SCTP_IPV4_ADDRESS;
- aa->ap.addrp.ph.param_length = (sizeof(struct sctp_ipv4addr_param));
- aa->ap.aph.ph.param_length = sizeof(struct sctp_asconf_paramhdr) + sizeof(struct sctp_ipv4addr_param);
- memcpy(&aa->ap.addrp.addr, &sin->sin_addr,
- sizeof(struct in_addr));
- break;
- }
- #endif
- default:
- /* invalid family! */
- SCTP_FREE(aa, SCTP_M_ASC_ADDR);
- if (ifa)
- sctp_free_ifa(ifa);
- return (-1);
- }
- aa->sent = 0; /* clear sent flag */
- /* delete goes to the back of the queue */
- TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa, next);
- /* sa_ignore MEMLEAK {memory is put on the tailq} */
- return (0);
- }
- /*
- * find a specific asconf param on our "sent" queue
- */
- static struct sctp_asconf_addr *
- sctp_asconf_find_param(struct sctp_tcb *stcb, uint32_t correlation_id)
- {
- struct sctp_asconf_addr *aa;
- TAILQ_FOREACH(aa, &stcb->asoc.asconf_queue, next) {
- if (aa->ap.aph.correlation_id == correlation_id &&
- aa->sent == 1) {
- /* found it */
- return (aa);
- }
- }
- /* didn't find it */
- return (NULL);
- }
- /*
- * process an SCTP_ERROR_CAUSE_IND for a ASCONF-ACK parameter and do
- * notifications based on the error response
- */
- static void
- sctp_asconf_process_error(struct sctp_tcb *stcb SCTP_UNUSED,
- struct sctp_asconf_paramhdr *aph)
- {
- struct sctp_error_cause *eh;
- struct sctp_paramhdr *ph;
- uint16_t param_type;
- uint16_t error_code;
- eh = (struct sctp_error_cause *)(aph + 1);
- ph = (struct sctp_paramhdr *)(eh + 1);
- /* validate lengths */
- if (htons(eh->length) + sizeof(struct sctp_error_cause) >
- htons(aph->ph.param_length)) {
- /* invalid error cause length */
- SCTPDBG(SCTP_DEBUG_ASCONF1,
- "asconf_process_error: cause element too long\n");
- return;
- }
- if (htons(ph->param_length) + sizeof(struct sctp_paramhdr) >
- htons(eh->length)) {
- /* invalid included TLV length */
- SCTPDBG(SCTP_DEBUG_ASCONF1,
- "asconf_process_error: included TLV too long\n");
- return;
- }
- /* which error code ? */
- error_code = ntohs(eh->code);
- param_type = ntohs(aph->ph.param_type);
- /* FIX: this should go back up the REMOTE_ERROR ULP notify */
- switch (error_code) {
- case SCTP_CAUSE_RESOURCE_SHORTAGE:
- /* we allow ourselves to "try again" for this error */
- break;
- default:
- /* peer can't handle it... */
- switch (param_type) {
- case SCTP_ADD_IP_ADDRESS:
- case SCTP_DEL_IP_ADDRESS:
- case SCTP_SET_PRIM_ADDR:
- break;
- default:
- break;
- }
- }
- }
- /*
- * process an asconf queue param.
- * aparam: parameter to process, will be removed from the queue.
- * flag: 1=success case, 0=failure case
- */
- static void
- sctp_asconf_process_param_ack(struct sctp_tcb *stcb,
- struct sctp_asconf_addr *aparam, uint32_t flag)
- {
- uint16_t param_type;
- /* process this param */
- param_type = aparam->ap.aph.ph.param_type;
- switch (param_type) {
- case SCTP_ADD_IP_ADDRESS:
- SCTPDBG(SCTP_DEBUG_ASCONF1,
- "process_param_ack: added IP address\n");
- sctp_asconf_addr_mgmt_ack(stcb, aparam->ifa, flag);
- break;
- case SCTP_DEL_IP_ADDRESS:
- SCTPDBG(SCTP_DEBUG_ASCONF1,
- "process_param_ack: deleted IP address\n");
- /* nothing really to do... lists already updated */
- break;
- case SCTP_SET_PRIM_ADDR:
- SCTPDBG(SCTP_DEBUG_ASCONF1,
- "process_param_ack: set primary IP address\n");
- /* nothing to do... peer may start using this addr */
- break;
- default:
- /* should NEVER happen */
- break;
- }
- /* remove the param and free it */
- TAILQ_REMOVE(&stcb->asoc.asconf_queue, aparam, next);
- if (aparam->ifa)
- sctp_free_ifa(aparam->ifa);
- SCTP_FREE(aparam, SCTP_M_ASC_ADDR);
- }
- /*
- * cleanup from a bad asconf ack parameter
- */
- static void
- sctp_asconf_ack_clear(struct sctp_tcb *stcb SCTP_UNUSED)
- {
- /* assume peer doesn't really know how to do asconfs */
- /* XXX we could free the pending queue here */
- }
- void
- sctp_handle_asconf_ack(struct mbuf *m, int offset,
- struct sctp_asconf_ack_chunk *cp, struct sctp_tcb *stcb,
- struct sctp_nets *net, int *abort_no_unlock)
- {
- struct sctp_association *asoc;
- uint32_t serial_num;
- uint16_t ack_length;
- struct sctp_asconf_paramhdr *aph;
- struct sctp_asconf_addr *aa, *aa_next;
- uint32_t last_error_id = 0; /* last error correlation id */
- uint32_t id;
- struct sctp_asconf_addr *ap;
- /* asconf param buffer */
- uint8_t aparam_buf[SCTP_PARAM_BUFFER_SIZE];
- /* verify minimum length */
- if (ntohs(cp->ch.chunk_length) < sizeof(struct sctp_asconf_ack_chunk)) {
- SCTPDBG(SCTP_DEBUG_ASCONF1,
- "handle_asconf_ack: chunk too small = %xh\n",
- ntohs(cp->ch.chunk_length));
- return;
- }
- asoc = &stcb->asoc;
- serial_num = ntohl(cp->serial_number);
- /*
- * NOTE: we may want to handle this differently- currently, we will
- * abort when we get an ack for the expected serial number + 1 (eg.
- * we didn't send it), process an ack normally if it is the expected
- * serial number, and re-send the previous ack for *ALL* other
- * serial numbers
- */
- /*
- * if the serial number is the next expected, but I didn't send it,
- * abort the asoc, since someone probably just hijacked us...
- */
- if (serial_num == (asoc->asconf_seq_out + 1)) {
- struct mbuf *op_err;
- char msg[SCTP_DIAG_INFO_LEN];
- SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf_ack: got unexpected next serial number! Aborting asoc!\n");
- SCTP_SNPRINTF(msg, sizeof(msg), "Never sent serial number %8.8x", serial_num);
- op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
- sctp_abort_an_association(stcb->sctp_ep, stcb, op_err, false, SCTP_SO_NOT_LOCKED);
- *abort_no_unlock = 1;
- return;
- }
- if (serial_num != asoc->asconf_seq_out_acked + 1) {
- /* got a duplicate/unexpected ASCONF-ACK */
- SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf_ack: got duplicate/unexpected serial number = %xh (expected = %xh)\n",
- serial_num, asoc->asconf_seq_out_acked + 1);
- return;
- }
- if (serial_num == asoc->asconf_seq_out - 1) {
- /* stop our timer */
- sctp_timer_stop(SCTP_TIMER_TYPE_ASCONF, stcb->sctp_ep, stcb, NULL,
- SCTP_FROM_SCTP_ASCONF + SCTP_LOC_5);
- }
- /* process the ASCONF-ACK contents */
- ack_length = ntohs(cp->ch.chunk_length) -
- sizeof(struct sctp_asconf_ack_chunk);
- offset += sizeof(struct sctp_asconf_ack_chunk);
- /* process through all parameters */
- while (ack_length >= sizeof(struct sctp_asconf_paramhdr)) {
- unsigned int param_length, param_type;
- /* get pointer to next asconf parameter */
- aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(m, offset,
- sizeof(struct sctp_asconf_paramhdr), aparam_buf);
- if (aph == NULL) {
- /* can't get an asconf paramhdr */
- sctp_asconf_ack_clear(stcb);
- return;
- }
- param_type = ntohs(aph->ph.param_type);
- param_length = ntohs(aph->ph.param_length);
- if (param_length > ack_length) {
- sctp_asconf_ack_clear(stcb);
- return;
- }
- if (param_length < sizeof(struct sctp_asconf_paramhdr)) {
- sctp_asconf_ack_clear(stcb);
- return;
- }
- /* get the complete parameter... */
- if (param_length > sizeof(aparam_buf)) {
- SCTPDBG(SCTP_DEBUG_ASCONF1,
- "param length (%u) larger than buffer size!\n", param_length);
- sctp_asconf_ack_clear(stcb);
- return;
- }
- aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(m, offset, param_length, aparam_buf);
- if (aph == NULL) {
- sctp_asconf_ack_clear(stcb);
- return;
- }
- /* correlation_id is transparent to peer, no ntohl needed */
- id = aph->correlation_id;
- switch (param_type) {
- case SCTP_ERROR_CAUSE_IND:
- last_error_id = id;
- /* find the corresponding asconf param in our queue */
- ap = sctp_asconf_find_param(stcb, id);
- if (ap == NULL) {
- /* hmm... can't find this in our queue! */
- break;
- }
- /* process the parameter, failed flag */
- sctp_asconf_process_param_ack(stcb, ap, 0);
- /* process the error response */
- sctp_asconf_process_error(stcb, aph);
- break;
- case SCTP_SUCCESS_REPORT:
- /* find the corresponding asconf param in our queue */
- ap = sctp_asconf_find_param(stcb, id);
- if (ap == NULL) {
- /* hmm... can't find this in our queue! */
- break;
- }
- /* process the parameter, success flag */
- sctp_asconf_process_param_ack(stcb, ap, 1);
- break;
- default:
- break;
- } /* switch */
- /* update remaining ASCONF-ACK message length to process */
- if (ack_length > SCTP_SIZE32(param_length)) {
- ack_length -= SCTP_SIZE32(param_length);
- } else {
- break;
- }
- offset += SCTP_SIZE32(param_length);
- } /* while */
- /*
- * if there are any "sent" params still on the queue, these are
- * implicitly "success", or "failed" (if we got an error back) ...
- * so process these appropriately
- *
- * we assume that the correlation_id's are monotonically increasing
- * beginning from 1 and that we don't have *that* many outstanding
- * at any given time
- */
- if (last_error_id == 0)
- last_error_id--; /* set to "max" value */
- TAILQ_FOREACH_SAFE(aa, &stcb->asoc.asconf_queue, next, aa_next) {
- if (aa->sent == 1) {
- /*
- * implicitly successful or failed if correlation_id
- * < last_error_id, then success else, failure
- */
- if (aa->ap.aph.correlation_id < last_error_id)
- sctp_asconf_process_param_ack(stcb, aa, 1);
- else
- sctp_asconf_process_param_ack(stcb, aa, 0);
- } else {
- /*
- * since we always process in order (FIFO queue) if
- * we reach one that hasn't been sent, the rest
- * should not have been sent either. so, we're
- * done...
- */
- break;
- }
- }
- /* update the next sequence number to use */
- asoc->asconf_seq_out_acked++;
- /* remove the old ASCONF on our outbound queue */
- sctp_toss_old_asconf(stcb);
- if (!TAILQ_EMPTY(&stcb->asoc.asconf_queue)) {
- #ifdef SCTP_TIMER_BASED_ASCONF
- /* we have more params, so restart our timer */
- sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, stcb->sctp_ep,
- stcb, net);
- #else
- /* we have more params, so send out more */
- sctp_send_asconf(stcb, net, SCTP_ADDR_NOT_LOCKED);
- #endif
- }
- }
- #ifdef INET6
- static uint32_t
- sctp_is_scopeid_in_nets(struct sctp_tcb *stcb, struct sockaddr *sa)
- {
- struct sockaddr_in6 *sin6, *net6;
- struct sctp_nets *net;
- if (sa->sa_family != AF_INET6) {
- /* wrong family */
- return (0);
- }
- sin6 = (struct sockaddr_in6 *)sa;
- if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) == 0) {
- /* not link local address */
- return (0);
- }
- /* hunt through our destination nets list for this scope_id */
- TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
- if (((struct sockaddr *)(&net->ro._l_addr))->sa_family !=
- AF_INET6)
- continue;
- net6 = (struct sockaddr_in6 *)&net->ro._l_addr;
- if (IN6_IS_ADDR_LINKLOCAL(&net6->sin6_addr) == 0)
- continue;
- if (sctp_is_same_scope(sin6, net6)) {
- /* found one */
- return (1);
- }
- }
- /* didn't find one */
- return (0);
- }
- #endif
- /*
- * address management functions
- */
- static void
- sctp_addr_mgmt_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
- struct sctp_ifa *ifa, uint16_t type, int addr_locked)
- {
- int status;
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0 ||
- sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DO_ASCONF)) {
- /* subset bound, no ASCONF allowed case, so ignore */
- return;
- }
- /*
- * note: we know this is not the subset bound, no ASCONF case eg.
- * this is boundall or subset bound w/ASCONF allowed
- */
- /* first, make sure that the address is IPv4 or IPv6 and not jailed */
- switch (ifa->address.sa.sa_family) {
- #ifdef INET6
- case AF_INET6:
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- if (prison_check_ip6(inp->ip_inp.inp.inp_cred,
- &ifa->address.sin6.sin6_addr) != 0) {
- return;
- }
- #endif
- break;
- #endif
- #ifdef INET
- case AF_INET:
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- if (prison_check_ip4(inp->ip_inp.inp.inp_cred,
- &ifa->address.sin.sin_addr) != 0) {
- return;
- }
- #endif
- break;
- #endif
- default:
- return;
- }
- #ifdef INET6
- /* make sure we're "allowed" to add this type of addr */
- if (ifa->address.sa.sa_family == AF_INET6) {
- /* invalid if we're not a v6 endpoint */
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0)
- return;
- /* is the v6 addr really valid ? */
- if (ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) {
- return;
- }
- }
- #endif
- /* put this address on the "pending/do not use yet" list */
- sctp_add_local_addr_restricted(stcb, ifa);
- /*
- * check address scope if address is out of scope, don't queue
- * anything... note: this would leave the address on both inp and
- * asoc lists
- */
- switch (ifa->address.sa.sa_family) {
- #ifdef INET6
- case AF_INET6:
- {
- struct sockaddr_in6 *sin6;
- sin6 = &ifa->address.sin6;
- if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
- /* we skip unspecified addresses */
- return;
- }
- if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
- if (stcb->asoc.scope.local_scope == 0) {
- return;
- }
- /* is it the right link local scope? */
- if (sctp_is_scopeid_in_nets(stcb, &ifa->address.sa) == 0) {
- return;
- }
- }
- if (stcb->asoc.scope.site_scope == 0 &&
- IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)) {
- return;
- }
- break;
- }
- #endif
- #ifdef INET
- case AF_INET:
- {
- struct sockaddr_in *sin;
- /* invalid if we are a v6 only endpoint */
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
- SCTP_IPV6_V6ONLY(inp))
- return;
- sin = &ifa->address.sin;
- if (sin->sin_addr.s_addr == 0) {
- /* we skip unspecified addresses */
- return;
- }
- if (stcb->asoc.scope.ipv4_local_scope == 0 &&
- IN4_ISPRIVATE_ADDRESS(&sin->sin_addr)) {
- return;
- }
- break;
- }
- #endif
- default:
- /* else, not AF_INET or AF_INET6, so skip */
- return;
- }
- /* queue an asconf for this address add/delete */
- if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_DO_ASCONF)) {
- /* does the peer do asconf? */
- if (stcb->asoc.asconf_supported) {
- /* queue an asconf for this addr */
- status = sctp_asconf_queue_add(stcb, ifa, type);
- /*
- * if queued ok, and in the open state, send out the
- * ASCONF. If in the non-open state, these will be
- * sent when the state goes open.
- */
- if (status == 0 &&
- ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) ||
- (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED))) {
- #ifdef SCTP_TIMER_BASED_ASCONF
- sctp_timer_start(SCTP_TIMER_TYPE_ASCONF, inp,
- stcb, stcb->asoc.primary_destination);
- #else
- sctp_send_asconf(stcb, NULL, addr_locked);
- #endif
- }
- }
- }
- }
- int
- sctp_asconf_iterator_ep(struct sctp_inpcb *inp, void *ptr, uint32_t val SCTP_UNUSED)
- {
- struct sctp_asconf_iterator *asc;
- struct sctp_ifa *ifa;
- struct sctp_laddr *l;
- int cnt_invalid = 0;
- asc = (struct sctp_asconf_iterator *)ptr;
- LIST_FOREACH(l, &asc->list_of_work, sctp_nxt_addr) {
- ifa = l->ifa;
- switch (ifa->address.sa.sa_family) {
- #ifdef INET6
- case AF_INET6:
- /* invalid if we're not a v6 endpoint */
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) {
- cnt_invalid++;
- if (asc->cnt == cnt_invalid)
- return (1);
- }
- break;
- #endif
- #ifdef INET
- case AF_INET:
- {
- /* invalid if we are a v6 only endpoint */
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
- SCTP_IPV6_V6ONLY(inp)) {
- cnt_invalid++;
- if (asc->cnt == cnt_invalid)
- return (1);
- }
- break;
- }
- #endif
- default:
- /* invalid address family */
- cnt_invalid++;
- if (asc->cnt == cnt_invalid)
- return (1);
- }
- }
- return (0);
- }
- static int
- sctp_asconf_iterator_ep_end(struct sctp_inpcb *inp, void *ptr, uint32_t val SCTP_UNUSED)
- {
- struct sctp_ifa *ifa;
- struct sctp_asconf_iterator *asc;
- struct sctp_laddr *laddr, *nladdr, *l;
- /* Only for specific case not bound all */
- asc = (struct sctp_asconf_iterator *)ptr;
- LIST_FOREACH(l, &asc->list_of_work, sctp_nxt_addr) {
- ifa = l->ifa;
- if (l->action == SCTP_ADD_IP_ADDRESS) {
- LIST_FOREACH(laddr, &inp->sctp_addr_list,
- sctp_nxt_addr) {
- if (laddr->ifa == ifa) {
- laddr->action = 0;
- break;
- }
- }
- } else if (l->action == SCTP_DEL_IP_ADDRESS) {
- LIST_FOREACH_SAFE(laddr, &inp->sctp_addr_list, sctp_nxt_addr, nladdr) {
- /* remove only after all guys are done */
- if (laddr->ifa == ifa) {
- sctp_del_local_addr_ep(inp, ifa);
- }
- }
- }
- }
- return (0);
- }
- void
- sctp_asconf_iterator_stcb(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
- void *ptr, uint32_t val SCTP_UNUSED)
- {
- struct sctp_asconf_iterator *asc;
- struct sctp_ifa *ifa;
- struct sctp_laddr *l;
- int cnt_invalid = 0;
- int type, status;
- int num_queued = 0;
- asc = (struct sctp_asconf_iterator *)ptr;
- LIST_FOREACH(l, &asc->list_of_work, sctp_nxt_addr) {
- ifa = l->ifa;
- type = l->action;
- /* address's vrf_id must be the vrf_id of the assoc */
- if (ifa->vrf_id != stcb->asoc.vrf_id) {
- continue;
- }
- /* Same checks again for assoc */
- switch (ifa->address.sa.sa_family) {
- #ifdef INET6
- case AF_INET6:
- {
- /* invalid if we're not a v6 endpoint */
- struct sockaddr_in6 *sin6;
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) {
- cnt_invalid++;
- if (asc->cnt == cnt_invalid)
- return;
- else
- continue;
- }
- sin6 = &ifa->address.sin6;
- if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
- /* we skip unspecified addresses */
- continue;
- }
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- if (prison_check_ip6(inp->ip_inp.inp.inp_cred,
- &sin6->sin6_addr) != 0) {
- continue;
- }
- #endif
- if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
- if (stcb->asoc.scope.local_scope == 0) {
- continue;
- }
- /* is it the right link local scope? */
- if (sctp_is_scopeid_in_nets(stcb, &ifa->address.sa) == 0) {
- continue;
- }
- }
- break;
- }
- #endif
- #ifdef INET
- case AF_INET:
- {
- /* invalid if we are a v6 only endpoint */
- struct sockaddr_in *sin;
- /* invalid if we are a v6 only endpoint */
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
- SCTP_IPV6_V6ONLY(inp))
- continue;
- sin = &ifa->address.sin;
- if (sin->sin_addr.s_addr == 0) {
- /* we skip unspecified addresses */
- continue;
- }
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- if (prison_check_ip4(inp->ip_inp.inp.inp_cred,
- &sin->sin_addr) != 0) {
- continue;
- }
- #endif
- if (stcb->asoc.scope.ipv4_local_scope == 0 &&
- IN4_ISPRIVATE_ADDRESS(&sin->sin_addr)) {
- continue;
- }
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
- SCTP_IPV6_V6ONLY(inp)) {
- cnt_invalid++;
- if (asc->cnt == cnt_invalid)
- return;
- else
- continue;
- }
- break;
- }
- #endif
- default:
- /* invalid address family */
- cnt_invalid++;
- if (asc->cnt == cnt_invalid)
- return;
- else
- continue;
- }
- if (type == SCTP_ADD_IP_ADDRESS) {
- /* prevent this address from being used as a source */
- sctp_add_local_addr_restricted(stcb, ifa);
- } else if (type == SCTP_DEL_IP_ADDRESS) {
- struct sctp_nets *net;
- TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
- /* delete this address if cached */
- if (net->ro._s_addr == ifa) {
- sctp_free_ifa(net->ro._s_addr);
- net->ro._s_addr = NULL;
- net->src_addr_selected = 0;
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- RO_NHFREE(&net->ro);
- #else
- if (net->ro.ro_rt) {
- RTFREE(net->ro.ro_rt);
- net->ro.ro_rt = NULL;
- }
- #endif
- /*
- * Now we deleted our src address,
- * should we not also now reset the
- * cwnd/rto to start as if its a new
- * address?
- */
- stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net);
- net->RTO = 0;
- }
- }
- } else if (type == SCTP_SET_PRIM_ADDR) {
- if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) {
- /* must validate the ifa is in the ep */
- if (sctp_is_addr_in_ep(stcb->sctp_ep, ifa) == 0) {
- continue;
- }
- } else {
- /* Need to check scopes for this guy */
- if (sctp_is_address_in_scope(ifa, &stcb->asoc.scope, 0) == 0) {
- continue;
- }
- }
- }
- /* queue an asconf for this address add/delete */
- if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_DO_ASCONF) &&
- stcb->asoc.asconf_supported == 1) {
- /* queue an asconf for this addr */
- status = sctp_asconf_queue_add(stcb, ifa, type);
- /*
- * if queued ok, and in the open state, update the
- * count of queued params. If in the non-open state,
- * these get sent when the assoc goes open.
- */
- if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) ||
- (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
- if (status >= 0) {
- num_queued++;
- }
- }
- }
- }
- /*
- * If we have queued params in the open state, send out an ASCONF.
- */
- if (num_queued > 0) {
- sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED);
- }
- }
- void
- sctp_asconf_iterator_end(void *ptr, uint32_t val SCTP_UNUSED)
- {
- struct sctp_asconf_iterator *asc;
- struct sctp_ifa *ifa;
- struct sctp_laddr *l, *nl;
- asc = (struct sctp_asconf_iterator *)ptr;
- LIST_FOREACH_SAFE(l, &asc->list_of_work, sctp_nxt_addr, nl) {
- ifa = l->ifa;
- if (l->action == SCTP_ADD_IP_ADDRESS) {
- /* Clear the defer use flag */
- ifa->localifa_flags &= ~SCTP_ADDR_DEFER_USE;
- }
- sctp_free_ifa(ifa);
- SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_laddr), l);
- SCTP_DECR_LADDR_COUNT();
- }
- SCTP_FREE(asc, SCTP_M_ASC_IT);
- }
- /*
- * sa is the sockaddr to ask the peer to set primary to.
- * returns: 0 = completed, -1 = error
- */
- int32_t
- sctp_set_primary_ip_address_sa(struct sctp_tcb *stcb, struct sockaddr *sa)
- {
- uint32_t vrf_id;
- struct sctp_ifa *ifa;
- /* find the ifa for the desired set primary */
- vrf_id = stcb->asoc.vrf_id;
- ifa = sctp_find_ifa_by_addr(sa, vrf_id, SCTP_ADDR_NOT_LOCKED);
- if (ifa == NULL) {
- /* Invalid address */
- return (-1);
- }
- /* queue an ASCONF:SET_PRIM_ADDR to be sent */
- if (!sctp_asconf_queue_add(stcb, ifa, SCTP_SET_PRIM_ADDR)) {
- /* set primary queuing succeeded */
- SCTPDBG(SCTP_DEBUG_ASCONF1,
- "set_primary_ip_address_sa: queued on tcb=%p, ",
- (void *)stcb);
- SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa);
- if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) ||
- (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
- #ifdef SCTP_TIMER_BASED_ASCONF
- sctp_timer_start(SCTP_TIMER_TYPE_ASCONF,
- stcb->sctp_ep, stcb,
- stcb->asoc.primary_destination);
- #else
- sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED);
- #endif
- }
- } else {
- SCTPDBG(SCTP_DEBUG_ASCONF1, "set_primary_ip_address_sa: failed to add to queue on tcb=%p, ",
- (void *)stcb);
- SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, sa);
- return (-1);
- }
- return (0);
- }
- int
- sctp_is_addr_pending(struct sctp_tcb *stcb, struct sctp_ifa *sctp_ifa)
- {
- struct sctp_tmit_chunk *chk, *nchk;
- unsigned int offset, asconf_limit;
- struct sctp_asconf_chunk *acp;
- struct sctp_asconf_paramhdr *aph;
- uint8_t aparam_buf[SCTP_PARAM_BUFFER_SIZE];
- struct sctp_paramhdr *ph;
- int add_cnt, del_cnt;
- uint16_t last_param_type;
- add_cnt = del_cnt = 0;
- last_param_type = 0;
- TAILQ_FOREACH_SAFE(chk, &stcb->asoc.asconf_send_queue, sctp_next, nchk) {
- if (chk->data == NULL) {
- SCTPDBG(SCTP_DEBUG_ASCONF1, "is_addr_pending: No mbuf data?\n");
- continue;
- }
- offset = 0;
- acp = mtod(chk->data, struct sctp_asconf_chunk *);
- offset += sizeof(struct sctp_asconf_chunk);
- asconf_limit = ntohs(acp->ch.chunk_length);
- ph = (struct sctp_paramhdr *)sctp_m_getptr(chk->data, offset, sizeof(struct sctp_paramhdr), aparam_buf);
- if (ph == NULL) {
- SCTPDBG(SCTP_DEBUG_ASCONF1, "is_addr_pending: couldn't get lookup addr!\n");
- continue;
- }
- offset += ntohs(ph->param_length);
- aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(chk->data, offset, sizeof(struct sctp_asconf_paramhdr), aparam_buf);
- if (aph == NULL) {
- SCTPDBG(SCTP_DEBUG_ASCONF1, "is_addr_pending: Empty ASCONF will be sent?\n");
- continue;
- }
- while (aph != NULL) {
- unsigned int param_length, param_type;
- param_type = ntohs(aph->ph.param_type);
- param_length = ntohs(aph->ph.param_length);
- if (offset + param_length > asconf_limit) {
- /* parameter goes beyond end of chunk! */
- break;
- }
- if (param_length > sizeof(aparam_buf)) {
- SCTPDBG(SCTP_DEBUG_ASCONF1, "is_addr_pending: param length (%u) larger than buffer size!\n", param_length);
- break;
- }
- if (param_length <= sizeof(struct sctp_paramhdr)) {
- SCTPDBG(SCTP_DEBUG_ASCONF1, "is_addr_pending: param length(%u) too short\n", param_length);
- break;
- }
- aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(chk->data, offset, param_length, aparam_buf);
- if (aph == NULL) {
- SCTPDBG(SCTP_DEBUG_ASCONF1, "is_addr_pending: couldn't get entire param\n");
- break;
- }
- ph = (struct sctp_paramhdr *)(aph + 1);
- if (sctp_addr_match(ph, &sctp_ifa->address.sa) != 0) {
- switch (param_type) {
- case SCTP_ADD_IP_ADDRESS:
- add_cnt++;
- break;
- case SCTP_DEL_IP_ADDRESS:
- del_cnt++;
- break;
- default:
- break;
- }
- last_param_type = param_type;
- }
- offset += SCTP_SIZE32(param_length);
- if (offset >= asconf_limit) {
- /* no more data in the mbuf chain */
- break;
- }
- /* get pointer to next asconf param */
- aph = (struct sctp_asconf_paramhdr *)sctp_m_getptr(chk->data, offset, sizeof(struct sctp_asconf_paramhdr), aparam_buf);
- }
- }
- /* we want to find the sequences which consist of ADD -> DEL -> ADD or DEL -> ADD */
- if (add_cnt > del_cnt ||
- (add_cnt == del_cnt && last_param_type == SCTP_ADD_IP_ADDRESS)) {
- return (1);
- }
- return (0);
- }
- static struct sockaddr *
- sctp_find_valid_localaddr(struct sctp_tcb *stcb, int addr_locked)
- {
- struct sctp_vrf *vrf = NULL;
- struct sctp_ifn *sctp_ifn;
- struct sctp_ifa *sctp_ifa;
- if (addr_locked == SCTP_ADDR_NOT_LOCKED)
- SCTP_IPI_ADDR_RLOCK();
- vrf = sctp_find_vrf(stcb->asoc.vrf_id);
- if (vrf == NULL) {
- if (addr_locked == SCTP_ADDR_NOT_LOCKED)
- SCTP_IPI_ADDR_RUNLOCK();
- return (NULL);
- }
- LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
- if (stcb->asoc.scope.loopback_scope == 0 &&
- SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) {
- /* Skip if loopback_scope not set */
- continue;
- }
- LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
- switch (sctp_ifa->address.sa.sa_family) {
- #ifdef INET
- case AF_INET:
- if (stcb->asoc.scope.ipv4_addr_legal) {
- struct sockaddr_in *sin;
- sin = &sctp_ifa->address.sin;
- if (sin->sin_addr.s_addr == 0) {
- /* skip unspecified addresses */
- continue;
- }
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- if (prison_check_ip4(stcb->sctp_ep->ip_inp.inp.inp_cred,
- &sin->sin_addr) != 0) {
- continue;
- }
- #endif
- if (stcb->asoc.scope.ipv4_local_scope == 0 &&
- IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))
- continue;
- if (sctp_is_addr_restricted(stcb, sctp_ifa) &&
- (!sctp_is_addr_pending(stcb, sctp_ifa)))
- continue;
- /* found a valid local v4 address to use */
- if (addr_locked == SCTP_ADDR_NOT_LOCKED)
- SCTP_IPI_ADDR_RUNLOCK();
- return (&sctp_ifa->address.sa);
- }
- break;
- #endif
- #ifdef INET6
- case AF_INET6:
- if (stcb->asoc.scope.ipv6_addr_legal) {
- struct sockaddr_in6 *sin6;
- if (sctp_ifa->localifa_flags & SCTP_ADDR_IFA_UNUSEABLE) {
- continue;
- }
- sin6 = &sctp_ifa->address.sin6;
- if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
- /* we skip unspecified addresses */
- continue;
- }
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- if (prison_check_ip6(stcb->sctp_ep->ip_inp.inp.inp_cred,
- &sin6->sin6_addr) != 0) {
- continue;
- }
- #endif
- if (stcb->asoc.scope.local_scope == 0 &&
- IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
- continue;
- if (stcb->asoc.scope.site_scope == 0 &&
- IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))
- continue;
- if (sctp_is_addr_restricted(stcb, sctp_ifa) &&
- (!sctp_is_addr_pending(stcb, sctp_ifa)))
- continue;
- /* found a valid local v6 address to use */
- if (addr_locked == SCTP_ADDR_NOT_LOCKED)
- SCTP_IPI_ADDR_RUNLOCK();
- return (&sctp_ifa->address.sa);
- }
- break;
- #endif
- default:
- break;
- }
- }
- }
- /* no valid addresses found */
- if (addr_locked == SCTP_ADDR_NOT_LOCKED)
- SCTP_IPI_ADDR_RUNLOCK();
- return (NULL);
- }
- static struct sockaddr *
- sctp_find_valid_localaddr_ep(struct sctp_tcb *stcb)
- {
- struct sctp_laddr *laddr;
- LIST_FOREACH(laddr, &stcb->sctp_ep->sctp_addr_list, sctp_nxt_addr) {
- if (laddr->ifa == NULL) {
- continue;
- }
- /* is the address restricted ? */
- if (sctp_is_addr_restricted(stcb, laddr->ifa) &&
- (!sctp_is_addr_pending(stcb, laddr->ifa)))
- continue;
- /* found a valid local address to use */
- return (&laddr->ifa->address.sa);
- }
- /* no valid addresses found */
- return (NULL);
- }
- /*
- * builds an ASCONF chunk from queued ASCONF params.
- * returns NULL on error (no mbuf, no ASCONF params queued, etc).
- */
- struct mbuf *
- sctp_compose_asconf(struct sctp_tcb *stcb, int *retlen, int addr_locked)
- {
- struct mbuf *m_asconf, *m_asconf_chk;
- struct sctp_asconf_addr *aa;
- struct sctp_asconf_chunk *acp;
- struct sctp_asconf_paramhdr *aph;
- struct sctp_asconf_addr_param *aap;
- uint32_t p_length, overhead;
- uint32_t correlation_id = 1; /* 0 is reserved... */
- caddr_t ptr, lookup_ptr;
- uint8_t lookup_used = 0;
- /* are there any asconf params to send? */
- TAILQ_FOREACH(aa, &stcb->asoc.asconf_queue, next) {
- if (aa->sent == 0)
- break;
- }
- if (aa == NULL)
- return (NULL);
- /* Consider IP header and SCTP common header. */
- if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
- overhead = SCTP_MIN_OVERHEAD;
- } else {
- overhead = SCTP_MIN_V4_OVERHEAD;
- }
- /* Consider ASONF chunk. */
- overhead += sizeof(struct sctp_asconf_chunk);
- /* Consider AUTH chunk. */
- overhead += sctp_get_auth_chunk_len(stcb->asoc.peer_hmac_id);
- if (stcb->asoc.smallest_mtu <= overhead) {
- /* MTU too small. */
- return (NULL);
- }
- /*
- * get a chunk header mbuf and a cluster for the asconf params since
- * it's simpler to fill in the asconf chunk header lookup address on
- * the fly
- */
- m_asconf_chk = sctp_get_mbuf_for_msg(sizeof(struct sctp_asconf_chunk), 0, M_NOWAIT, 1, MT_DATA);
- if (m_asconf_chk == NULL) {
- /* no mbuf's */
- SCTPDBG(SCTP_DEBUG_ASCONF1,
- "sctp_compose_asconf: couldn't get chunk mbuf!\n");
- return (NULL);
- }
- m_asconf = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_NOWAIT, 1, MT_DATA);
- if (m_asconf == NULL) {
- /* no mbuf's */
- SCTPDBG(SCTP_DEBUG_ASCONF1,
- "sctp_compose_asconf: couldn't get mbuf!\n");
- sctp_m_freem(m_asconf_chk);
- return (NULL);
- }
- SCTP_BUF_LEN(m_asconf_chk) = sizeof(struct sctp_asconf_chunk);
- SCTP_BUF_LEN(m_asconf) = 0;
- acp = mtod(m_asconf_chk, struct sctp_asconf_chunk *);
- memset(acp, 0, sizeof(struct sctp_asconf_chunk));
- /* save pointers to lookup address and asconf params */
- lookup_ptr = (caddr_t)(acp + 1); /* after the header */
- ptr = mtod(m_asconf, caddr_t); /* beginning of cluster */
- /* fill in chunk header info */
- acp->ch.chunk_type = SCTP_ASCONF;
- acp->ch.chunk_flags = 0;
- acp->serial_number = htonl(stcb->asoc.asconf_seq_out);
- stcb->asoc.asconf_seq_out++;
- /* add parameters... up to smallest MTU allowed */
- TAILQ_FOREACH(aa, &stcb->asoc.asconf_queue, next) {
- if (aa->sent)
- continue;
- /* get the parameter length */
- p_length = SCTP_SIZE32(aa->ap.aph.ph.param_length);
- /* will it fit in current chunk? */
- if ((SCTP_BUF_LEN(m_asconf) + p_length > stcb->asoc.smallest_mtu - overhead) ||
- (SCTP_BUF_LEN(m_asconf) + p_length > MCLBYTES)) {
- /* won't fit, so we're done with this chunk */
- break;
- }
- /* assign (and store) a correlation id */
- aa->ap.aph.correlation_id = correlation_id++;
- /*
- * fill in address if we're doing a delete this is a simple
- * way for us to fill in the correlation address, which
- * should only be used by the peer if we're deleting our
- * source address and adding a new address (e.g. renumbering
- * case)
- */
- if (lookup_used == 0 &&
- (aa->special_del == 0) &&
- aa->ap.aph.ph.param_type == SCTP_DEL_IP_ADDRESS) {
- struct sctp_ipv6addr_param *lookup;
- uint16_t p_size, addr_size;
- lookup = (struct sctp_ipv6addr_param *)lookup_ptr;
- lookup->ph.param_type =
- htons(aa->ap.addrp.ph.param_type);
- if (aa->ap.addrp.ph.param_type == SCTP_IPV6_ADDRESS) {
- /* copy IPv6 address */
- p_size = sizeof(struct sctp_ipv6addr_param);
- addr_size = sizeof(struct in6_addr);
- } else {
- /* copy IPv4 address */
- p_size = sizeof(struct sctp_ipv4addr_param);
- addr_size = sizeof(struct in_addr);
- }
- lookup->ph.param_length = htons(SCTP_SIZE32(p_size));
- memcpy(lookup->addr, &aa->ap.addrp.addr, addr_size);
- SCTP_BUF_LEN(m_asconf_chk) += SCTP_SIZE32(p_size);
- lookup_used = 1;
- }
- /* copy into current space */
- memcpy(ptr, &aa->ap, p_length);
- /* network elements and update lengths */
- aph = (struct sctp_asconf_paramhdr *)ptr;
- aap = (struct sctp_asconf_addr_param *)ptr;
- /* correlation_id is transparent to peer, no htonl needed */
- aph->ph.param_type = htons(aph->ph.param_type);
- aph->ph.param_length = htons(aph->ph.param_length);
- aap->addrp.ph.param_type = htons(aap->addrp.ph.param_type);
- aap->addrp.ph.param_length = htons(aap->addrp.ph.param_length);
- SCTP_BUF_LEN(m_asconf) += SCTP_SIZE32(p_length);
- ptr += SCTP_SIZE32(p_length);
- /*
- * these params are removed off the pending list upon
- * getting an ASCONF-ACK back from the peer, just set flag
- */
- aa->sent = 1;
- }
- /* check to see if the lookup addr has been populated yet */
- if (lookup_used == 0) {
- /* NOTE: if the address param is optional, can skip this... */
- /* add any valid (existing) address... */
- struct sctp_ipv6addr_param *lookup;
- uint16_t p_size, addr_size;
- struct sockaddr *found_addr;
- caddr_t addr_ptr;
- if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL)
- found_addr = sctp_find_valid_localaddr(stcb,
- addr_locked);
- else
- found_addr = sctp_find_valid_localaddr_ep(stcb);
- lookup = (struct sctp_ipv6addr_param *)lookup_ptr;
- if (found_addr != NULL) {
- switch (found_addr->sa_family) {
- #ifdef INET6
- case AF_INET6:
- /* copy IPv6 address */
- lookup->ph.param_type =
- htons(SCTP_IPV6_ADDRESS);
- p_size = sizeof(struct sctp_ipv6addr_param);
- addr_size = sizeof(struct in6_addr);
- addr_ptr = (caddr_t)&((struct sockaddr_in6 *)
- found_addr)->sin6_addr;
- break;
- #endif
- #ifdef INET
- case AF_INET:
- /* copy IPv4 address */
- lookup->ph.param_type =
- htons(SCTP_IPV4_ADDRESS);
- p_size = sizeof(struct sctp_ipv4addr_param);
- addr_size = sizeof(struct in_addr);
- addr_ptr = (caddr_t)&((struct sockaddr_in *)
- found_addr)->sin_addr;
- break;
- #endif
- default:
- SCTPDBG(SCTP_DEBUG_ASCONF1,
- "sctp_compose_asconf: no usable lookup addr (family = %d)!\n",
- found_addr->sa_family);
- sctp_m_freem(m_asconf_chk);
- sctp_m_freem(m_asconf);
- return (NULL);
- }
- lookup->ph.param_length = htons(SCTP_SIZE32(p_size));
- memcpy(lookup->addr, addr_ptr, addr_size);
- SCTP_BUF_LEN(m_asconf_chk) += SCTP_SIZE32(p_size);
- } else {
- /* uh oh... don't have any address?? */
- SCTPDBG(SCTP_DEBUG_ASCONF1,
- "sctp_compose_asconf: no lookup addr!\n");
- sctp_m_freem(m_asconf_chk);
- sctp_m_freem(m_asconf);
- return (NULL);
- }
- }
- /* chain it all together */
- SCTP_BUF_NEXT(m_asconf_chk) = m_asconf;
- *retlen = SCTP_BUF_LEN(m_asconf_chk) + SCTP_BUF_LEN(m_asconf);
- acp->ch.chunk_length = htons(*retlen);
- return (m_asconf_chk);
- }
- /*
- * section to handle address changes before an association is up eg. changes
- * during INIT/INIT-ACK/COOKIE-ECHO handshake
- */
- /*
- * processes the (local) addresses in the INIT-ACK chunk
- */
- static void
- sctp_process_initack_addresses(struct sctp_tcb *stcb, struct mbuf *m,
- unsigned int offset, unsigned int length)
- {
- struct sctp_paramhdr tmp_param, *ph;
- uint16_t plen, ptype;
- struct sctp_ifa *sctp_ifa;
- union sctp_sockstore store;
- #ifdef INET6
- struct sctp_ipv6addr_param addr6_store;
- #endif
- #ifdef INET
- struct sctp_ipv4addr_param addr4_store;
- #endif
- SCTPDBG(SCTP_DEBUG_ASCONF2, "processing init-ack addresses\n");
- if (stcb == NULL) /* Un-needed check for SA */
- return;
- /* convert to upper bound */
- length += offset;
- if ((offset + sizeof(struct sctp_paramhdr)) > length) {
- return;
- }
- /* go through the addresses in the init-ack */
- ph = (struct sctp_paramhdr *)
- sctp_m_getptr(m, offset, sizeof(struct sctp_paramhdr),
- (uint8_t *)&tmp_param);
- while (ph != NULL) {
- ptype = ntohs(ph->param_type);
- plen = ntohs(ph->param_length);
- switch (ptype) {
- #ifdef INET6
- case SCTP_IPV6_ADDRESS:
- {
- struct sctp_ipv6addr_param *a6p;
- /* get the entire IPv6 address param */
- a6p = (struct sctp_ipv6addr_param *)
- sctp_m_getptr(m, offset,
- sizeof(struct sctp_ipv6addr_param),
- (uint8_t *)&addr6_store);
- if (plen != sizeof(struct sctp_ipv6addr_param) ||
- a6p == NULL) {
- return;
- }
- memset(&store, 0, sizeof(union sctp_sockstore));
- store.sin6.sin6_family = AF_INET6;
- #ifdef HAVE_SIN6_LEN
- store.sin6.sin6_len = sizeof(struct sockaddr_in6);
- #endif
- store.sin6.sin6_port = stcb->rport;
- memcpy(&store.sin6.sin6_addr, a6p->addr, sizeof(struct in6_addr));
- break;
- }
- #endif
- #ifdef INET
- case SCTP_IPV4_ADDRESS:
- {
- struct sctp_ipv4addr_param *a4p;
- /* get the entire IPv4 address param */
- a4p = (struct sctp_ipv4addr_param *)sctp_m_getptr(m, offset,
- sizeof(struct sctp_ipv4addr_param),
- (uint8_t *)&addr4_store);
- if (plen != sizeof(struct sctp_ipv4addr_param) ||
- a4p == NULL) {
- return;
- }
- memset(&store, 0, sizeof(union sctp_sockstore));
- store.sin.sin_family = AF_INET;
- #ifdef HAVE_SIN_LEN
- store.sin.sin_len = sizeof(struct sockaddr_in);
- #endif
- store.sin.sin_port = stcb->rport;
- store.sin.sin_addr.s_addr = a4p->addr;
- break;
- }
- #endif
- default:
- goto next_addr;
- }
- /* see if this address really (still) exists */
- sctp_ifa = sctp_find_ifa_by_addr(&store.sa, stcb->asoc.vrf_id,
- SCTP_ADDR_NOT_LOCKED);
- if (sctp_ifa == NULL) {
- /* address doesn't exist anymore */
- int status;
- /* are ASCONFs allowed ? */
- if ((sctp_is_feature_on(stcb->sctp_ep,
- SCTP_PCB_FLAGS_DO_ASCONF)) &&
- stcb->asoc.asconf_supported) {
- /* queue an ASCONF DEL_IP_ADDRESS */
- status = sctp_asconf_queue_sa_delete(stcb, &store.sa);
- /*
- * if queued ok, and in correct state, send
- * out the ASCONF.
- */
- if (status == 0 &&
- SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) {
- #ifdef SCTP_TIMER_BASED_ASCONF
- sctp_timer_start(SCTP_TIMER_TYPE_ASCONF,
- stcb->sctp_ep, stcb,
- stcb->asoc.primary_destination);
- #else
- sctp_send_asconf(stcb, NULL, SCTP_ADDR_NOT_LOCKED);
- #endif
- }
- }
- }
- next_addr:
- /*
- * Sanity check: Make sure the length isn't 0, otherwise
- * we'll be stuck in this loop for a long time...
- */
- if (SCTP_SIZE32(plen) == 0) {
- SCTP_PRINTF("process_initack_addrs: bad len (%d) type=%xh\n",
- plen, ptype);
- return;
- }
- /* get next parameter */
- offset += SCTP_SIZE32(plen);
- if ((offset + sizeof(struct sctp_paramhdr)) > length)
- return;
- ph = (struct sctp_paramhdr *)sctp_m_getptr(m, offset,
- sizeof(struct sctp_paramhdr), (uint8_t *)&tmp_param);
- } /* while */
- }
- /* FIX ME: need to verify return result for v6 address type if v6 disabled */
- /*
- * checks to see if a specific address is in the initack address list returns
- * 1 if found, 0 if not
- */
- static uint32_t
- sctp_addr_in_initack(struct mbuf *m, uint32_t offset, uint32_t length, struct sockaddr *sa)
- {
- struct sctp_paramhdr tmp_param, *ph;
- uint16_t plen, ptype;
- #ifdef INET
- struct sockaddr_in *sin;
- struct sctp_ipv4addr_param *a4p;
- struct sctp_ipv6addr_param addr4_store;
- #endif
- #ifdef INET6
- struct sockaddr_in6 *sin6;
- struct sctp_ipv6addr_param *a6p;
- struct sctp_ipv6addr_param addr6_store;
- #ifdef SCTP_EMBEDDED_V6_SCOPE
- struct sockaddr_in6 sin6_tmp;
- #endif
- #endif
- switch (sa->sa_family) {
- #ifdef INET
- case AF_INET:
- break;
- #endif
- #ifdef INET6
- case AF_INET6:
- break;
- #endif
- default:
- return (0);
- }
- SCTPDBG(SCTP_DEBUG_ASCONF2, "find_initack_addr: starting search for ");
- SCTPDBG_ADDR(SCTP_DEBUG_ASCONF2, sa);
- /* convert to upper bound */
- length += offset;
- if ((offset + sizeof(struct sctp_paramhdr)) > length) {
- SCTPDBG(SCTP_DEBUG_ASCONF1,
- "find_initack_addr: invalid offset?\n");
- return (0);
- }
- /* go through the addresses in the init-ack */
- ph = (struct sctp_paramhdr *)sctp_m_getptr(m, offset,
- sizeof(struct sctp_paramhdr), (uint8_t *) & tmp_param);
- while (ph != NULL) {
- ptype = ntohs(ph->param_type);
- plen = ntohs(ph->param_length);
- switch (ptype) {
- #ifdef INET6
- case SCTP_IPV6_ADDRESS:
- if (sa->sa_family == AF_INET6) {
- /* get the entire IPv6 address param */
- if (plen != sizeof(struct sctp_ipv6addr_param)) {
- break;
- }
- /* get the entire IPv6 address param */
- a6p = (struct sctp_ipv6addr_param *)
- sctp_m_getptr(m, offset,
- sizeof(struct sctp_ipv6addr_param),
- (uint8_t *)&addr6_store);
- if (a6p == NULL) {
- return (0);
- }
- sin6 = (struct sockaddr_in6 *)sa;
- #ifdef SCTP_EMBEDDED_V6_SCOPE
- if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) {
- /* create a copy and clear scope */
- memcpy(&sin6_tmp, sin6,
- sizeof(struct sockaddr_in6));
- sin6 = &sin6_tmp;
- in6_clearscope(&sin6->sin6_addr);
- }
- #endif /* SCTP_EMBEDDED_V6_SCOPE */
- if (memcmp(&sin6->sin6_addr, a6p->addr,
- sizeof(struct in6_addr)) == 0) {
- /* found it */
- return (1);
- }
- }
- break;
- #endif /* INET6 */
- #ifdef INET
- case SCTP_IPV4_ADDRESS:
- if (sa->sa_family == AF_INET) {
- if (plen != sizeof(struct sctp_ipv4addr_param)) {
- break;
- }
- /* get the entire IPv4 address param */
- a4p = (struct sctp_ipv4addr_param *)
- sctp_m_getptr(m, offset,
- sizeof(struct sctp_ipv4addr_param),
- (uint8_t *)&addr4_store);
- if (a4p == NULL) {
- return (0);
- }
- sin = (struct sockaddr_in *)sa;
- if (sin->sin_addr.s_addr == a4p->addr) {
- /* found it */
- return (1);
- }
- }
- break;
- #endif
- default:
- break;
- }
- /* get next parameter */
- offset += SCTP_SIZE32(plen);
- if (offset + sizeof(struct sctp_paramhdr) > length) {
- return (0);
- }
- ph = (struct sctp_paramhdr *)
- sctp_m_getptr(m, offset, sizeof(struct sctp_paramhdr),
- (uint8_t *) & tmp_param);
- } /* while */
- /* not found! */
- return (0);
- }
- /*
- * makes sure that the current endpoint local addr list is consistent with
- * the new association (eg. subset bound, asconf allowed) adds addresses as
- * necessary
- */
- static void
- sctp_check_address_list_ep(struct sctp_tcb *stcb, struct mbuf *m, int offset,
- int length, struct sockaddr *init_addr)
- {
- struct sctp_laddr *laddr;
- /* go through the endpoint list */
- LIST_FOREACH(laddr, &stcb->sctp_ep->sctp_addr_list, sctp_nxt_addr) {
- /* be paranoid and validate the laddr */
- if (laddr->ifa == NULL) {
- SCTPDBG(SCTP_DEBUG_ASCONF1,
- "check_addr_list_ep: laddr->ifa is NULL");
- continue;
- }
- /* do i have it implicitly? */
- if (sctp_cmpaddr(&laddr->ifa->address.sa, init_addr)) {
- continue;
- }
- /* check to see if in the init-ack */
- if (!sctp_addr_in_initack(m, offset, length, &laddr->ifa->address.sa)) {
- /* try to add it */
- sctp_addr_mgmt_assoc(stcb->sctp_ep, stcb, laddr->ifa,
- SCTP_ADD_IP_ADDRESS, SCTP_ADDR_NOT_LOCKED);
- }
- }
- }
- /*
- * makes sure that the current kernel address list is consistent with the new
- * association (with all addrs bound) adds addresses as necessary
- */
- static void
- sctp_check_address_list_all(struct sctp_tcb *stcb, struct mbuf *m, int offset,
- int length, struct sockaddr *init_addr,
- uint16_t local_scope, uint16_t site_scope,
- uint16_t ipv4_scope, uint16_t loopback_scope)
- {
- struct sctp_vrf *vrf = NULL;
- struct sctp_ifn *sctp_ifn;
- struct sctp_ifa *sctp_ifa;
- uint32_t vrf_id;
- #ifdef INET
- struct sockaddr_in *sin;
- #endif
- #ifdef INET6
- struct sockaddr_in6 *sin6;
- #endif
- if (stcb) {
- vrf_id = stcb->asoc.vrf_id;
- } else {
- return;
- }
- SCTP_IPI_ADDR_RLOCK();
- vrf = sctp_find_vrf(vrf_id);
- if (vrf == NULL) {
- SCTP_IPI_ADDR_RUNLOCK();
- return;
- }
- /* go through all our known interfaces */
- LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
- if (loopback_scope == 0 && SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) {
- /* skip loopback interface */
- continue;
- }
- /* go through each interface address */
- LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
- /* do i have it implicitly? */
- if (sctp_cmpaddr(&sctp_ifa->address.sa, init_addr)) {
- continue;
- }
- switch (sctp_ifa->address.sa.sa_family) {
- #ifdef INET
- case AF_INET:
- sin = &sctp_ifa->address.sin;
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- if (prison_check_ip4(stcb->sctp_ep->ip_inp.inp.inp_cred,
- &sin->sin_addr) != 0) {
- continue;
- }
- #endif
- if ((ipv4_scope == 0) &&
- (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) {
- /* private address not in scope */
- continue;
- }
- break;
- #endif
- #ifdef INET6
- case AF_INET6:
- sin6 = &sctp_ifa->address.sin6;
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- if (prison_check_ip6(stcb->sctp_ep->ip_inp.inp.inp_cred,
- &sin6->sin6_addr) != 0) {
- continue;
- }
- #endif
- if ((local_scope == 0) &&
- (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))) {
- continue;
- }
- if ((site_scope == 0) &&
- (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) {
- continue;
- }
- break;
- #endif
- default:
- break;
- }
- /* check to see if in the init-ack */
- if (!sctp_addr_in_initack(m, offset, length, &sctp_ifa->address.sa)) {
- /* try to add it */
- sctp_addr_mgmt_assoc(stcb->sctp_ep, stcb,
- sctp_ifa, SCTP_ADD_IP_ADDRESS,
- SCTP_ADDR_LOCKED);
- }
- } /* end foreach ifa */
- } /* end foreach ifn */
- SCTP_IPI_ADDR_RUNLOCK();
- }
- /*
- * validates an init-ack chunk (from a cookie-echo) with current addresses
- * adds addresses from the init-ack into our local address list, if needed
- * queues asconf adds/deletes addresses as needed and makes appropriate list
- * changes for source address selection m, offset: points to the start of the
- * address list in an init-ack chunk length: total length of the address
- * params only init_addr: address where my INIT-ACK was sent from
- */
- void
- sctp_check_address_list(struct sctp_tcb *stcb, struct mbuf *m, int offset,
- int length, struct sockaddr *init_addr,
- uint16_t local_scope, uint16_t site_scope,
- uint16_t ipv4_scope, uint16_t loopback_scope)
- {
- /* process the local addresses in the initack */
- sctp_process_initack_addresses(stcb, m, offset, length);
- if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
- /* bound all case */
- sctp_check_address_list_all(stcb, m, offset, length, init_addr,
- local_scope, site_scope, ipv4_scope, loopback_scope);
- } else {
- /* subset bound case */
- if (sctp_is_feature_on(stcb->sctp_ep,
- SCTP_PCB_FLAGS_DO_ASCONF)) {
- /* asconf's allowed */
- sctp_check_address_list_ep(stcb, m, offset, length,
- init_addr);
- }
- /* else, no asconfs allowed, so what we sent is what we get */
- }
- }
- /*
- * sctp_bindx() support
- */
- uint32_t
- sctp_addr_mgmt_ep_sa(struct sctp_inpcb *inp, struct sockaddr *sa,
- uint32_t type, uint32_t vrf_id)
- {
- struct sctp_ifa *ifa;
- struct sctp_laddr *laddr, *nladdr;
- #ifdef HAVE_SA_LEN
- if (sa->sa_len == 0) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_ASCONF, EINVAL);
- return (EINVAL);
- }
- #endif
- if (type == SCTP_ADD_IP_ADDRESS) {
- /* For an add the address MUST be on the system */
- ifa = sctp_find_ifa_by_addr(sa, vrf_id, SCTP_ADDR_NOT_LOCKED);
- } else if (type == SCTP_DEL_IP_ADDRESS) {
- /* For a delete we need to find it in the inp */
- ifa = sctp_find_ifa_in_ep(inp, sa, SCTP_ADDR_NOT_LOCKED);
- } else {
- ifa = NULL;
- }
- if (ifa != NULL) {
- if (type == SCTP_ADD_IP_ADDRESS) {
- sctp_add_local_addr_ep(inp, ifa, type);
- } else if (type == SCTP_DEL_IP_ADDRESS) {
- if (inp->laddr_count < 2) {
- /* can't delete the last local address */
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_ASCONF, EINVAL);
- return (EINVAL);
- }
- LIST_FOREACH(laddr, &inp->sctp_addr_list,
- sctp_nxt_addr) {
- if (ifa == laddr->ifa) {
- /* Mark in the delete */
- laddr->action = type;
- }
- }
- }
- if (LIST_EMPTY(&inp->sctp_asoc_list)) {
- /*
- * There is no need to start the iterator if
- * the inp has no associations.
- */
- if (type == SCTP_DEL_IP_ADDRESS) {
- LIST_FOREACH_SAFE(laddr, &inp->sctp_addr_list, sctp_nxt_addr, nladdr) {
- if (laddr->ifa == ifa) {
- sctp_del_local_addr_ep(inp, ifa);
- }
- }
- }
- } else {
- struct sctp_asconf_iterator *asc;
- struct sctp_laddr *wi;
- int ret;
- SCTP_MALLOC(asc, struct sctp_asconf_iterator *,
- sizeof(struct sctp_asconf_iterator),
- SCTP_M_ASC_IT);
- if (asc == NULL) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_ASCONF, ENOMEM);
- return (ENOMEM);
- }
- wi = SCTP_ZONE_GET(SCTP_BASE_INFO(ipi_zone_laddr), struct sctp_laddr);
- if (wi == NULL) {
- SCTP_FREE(asc, SCTP_M_ASC_IT);
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_ASCONF, ENOMEM);
- return (ENOMEM);
- }
- LIST_INIT(&asc->list_of_work);
- asc->cnt = 1;
- SCTP_INCR_LADDR_COUNT();
- wi->ifa = ifa;
- wi->action = type;
- atomic_add_int(&ifa->refcount, 1);
- LIST_INSERT_HEAD(&asc->list_of_work, wi, sctp_nxt_addr);
- ret = sctp_initiate_iterator(sctp_asconf_iterator_ep,
- sctp_asconf_iterator_stcb,
- sctp_asconf_iterator_ep_end,
- SCTP_PCB_ANY_FLAGS,
- SCTP_PCB_ANY_FEATURES,
- SCTP_ASOC_ANY_STATE,
- (void *)asc, 0,
- sctp_asconf_iterator_end, inp, 0);
- if (ret) {
- SCTP_PRINTF("Failed to initiate iterator for addr_mgmt_ep_sa\n");
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_ASCONF, EFAULT);
- sctp_asconf_iterator_end(asc, 0);
- return (EFAULT);
- }
- }
- return (0);
- } else {
- /* invalid address! */
- SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_ASCONF, EADDRNOTAVAIL);
- return (EADDRNOTAVAIL);
- }
- }
- void
- sctp_asconf_send_nat_state_update(struct sctp_tcb *stcb, struct sctp_nets *net)
- {
- struct sctp_asconf_addr *aa_vtag, *aa_add, *aa_del;
- struct sctp_ifa *sctp_ifap;
- struct sctp_asconf_tag_param *vtag;
- #ifdef INET
- struct sockaddr_in *to;
- #endif
- #ifdef INET6
- struct sockaddr_in6 *to6;
- #endif
- if (net == NULL) {
- SCTPDBG(SCTP_DEBUG_ASCONF1, "sctp_asconf_send_nat_state_update: Missing net\n");
- return;
- }
- if (stcb == NULL) {
- SCTPDBG(SCTP_DEBUG_ASCONF1, "sctp_asconf_send_nat_state_update: Missing stcb\n");
- return;
- }
- /* Need to have in the ASCONF:
- * - VTAG(my_vtag/peer_vtag)
- * - ADD(wildcard)
- * - DEL(wildcard)
- * - ADD(Any global addresses)
- */
- SCTP_MALLOC(aa_vtag, struct sctp_asconf_addr *, sizeof(struct sctp_asconf_addr), SCTP_M_ASC_ADDR);
- SCTP_MALLOC(aa_add, struct sctp_asconf_addr *, sizeof(struct sctp_asconf_addr), SCTP_M_ASC_ADDR);
- SCTP_MALLOC(aa_del, struct sctp_asconf_addr *, sizeof(struct sctp_asconf_addr), SCTP_M_ASC_ADDR);
- if ((aa_vtag == NULL) || (aa_add == NULL) || (aa_del == NULL)) {
- /* Didn't get memory */
- SCTPDBG(SCTP_DEBUG_ASCONF1, "sctp_asconf_send_nat_state_update: failed to get memory!\n");
- out:
- if (aa_vtag != NULL) {
- SCTP_FREE(aa_vtag, SCTP_M_ASC_ADDR);
- }
- if (aa_add != NULL) {
- SCTP_FREE(aa_add, SCTP_M_ASC_ADDR);
- }
- if (aa_del != NULL) {
- SCTP_FREE(aa_del, SCTP_M_ASC_ADDR);
- }
- return;
- }
- memset(aa_vtag, 0, sizeof(struct sctp_asconf_addr));
- aa_vtag->special_del = 0;
- /* Fill in ASCONF address parameter fields. */
- /* Top level elements are "networked" during send. */
- aa_vtag->ifa = NULL;
- aa_vtag->sent = 0; /* clear sent flag */
- vtag = (struct sctp_asconf_tag_param *)&aa_vtag->ap.aph;
- vtag->aph.ph.param_type = SCTP_NAT_VTAGS;
- vtag->aph.ph.param_length = sizeof(struct sctp_asconf_tag_param);
- vtag->local_vtag = htonl(stcb->asoc.my_vtag);
- vtag->remote_vtag = htonl(stcb->asoc.peer_vtag);
- memset(aa_add, 0, sizeof(struct sctp_asconf_addr));
- memset(aa_del, 0, sizeof(struct sctp_asconf_addr));
- switch (net->ro._l_addr.sa.sa_family) {
- #ifdef INET
- case AF_INET:
- aa_add->ap.aph.ph.param_type = SCTP_ADD_IP_ADDRESS;
- aa_add->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addrv4_param);
- aa_add->ap.addrp.ph.param_type = SCTP_IPV4_ADDRESS;
- aa_add->ap.addrp.ph.param_length = sizeof (struct sctp_ipv4addr_param);
- /* No need to fill the address, we are using 0.0.0.0 */
- aa_del->ap.aph.ph.param_type = SCTP_DEL_IP_ADDRESS;
- aa_del->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addrv4_param);
- aa_del->ap.addrp.ph.param_type = SCTP_IPV4_ADDRESS;
- aa_del->ap.addrp.ph.param_length = sizeof (struct sctp_ipv4addr_param);
- /* No need to fill the address, we are using 0.0.0.0 */
- break;
- #endif
- #ifdef INET6
- case AF_INET6:
- aa_add->ap.aph.ph.param_type = SCTP_ADD_IP_ADDRESS;
- aa_add->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addr_param);
- aa_add->ap.addrp.ph.param_type = SCTP_IPV6_ADDRESS;
- aa_add->ap.addrp.ph.param_length = sizeof (struct sctp_ipv6addr_param);
- /* No need to fill the address, we are using ::0 */
- aa_del->ap.aph.ph.param_type = SCTP_DEL_IP_ADDRESS;
- aa_del->ap.aph.ph.param_length = sizeof(struct sctp_asconf_addr_param);
- aa_del->ap.addrp.ph.param_type = SCTP_IPV6_ADDRESS;
- aa_del->ap.addrp.ph.param_length = sizeof (struct sctp_ipv6addr_param);
- /* No need to fill the address, we are using ::0 */
- break;
- #endif
- default:
- SCTPDBG(SCTP_DEBUG_ASCONF1,
- "sctp_asconf_send_nat_state_update: unknown address family %d\n",
- net->ro._l_addr.sa.sa_family);
- goto out;
- }
- TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa_vtag, next);
- TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa_add, next);
- TAILQ_INSERT_TAIL(&stcb->asoc.asconf_queue, aa_del, next);
- /* Now we must hunt the addresses and add all global addresses */
- if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
- struct sctp_vrf *vrf = NULL;
- struct sctp_ifn *sctp_ifnp;
- uint32_t vrf_id;
- vrf_id = stcb->sctp_ep->def_vrf_id;
- vrf = sctp_find_vrf(vrf_id);
- if (vrf == NULL) {
- goto skip_rest;
- }
- SCTP_IPI_ADDR_RLOCK();
- LIST_FOREACH(sctp_ifnp, &vrf->ifnlist, next_ifn) {
- LIST_FOREACH(sctp_ifap, &sctp_ifnp->ifalist, next_ifa) {
- switch (sctp_ifap->address.sa.sa_family) {
- #ifdef INET
- case AF_INET:
- to = &sctp_ifap->address.sin;
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- if (prison_check_ip4(stcb->sctp_ep->ip_inp.inp.inp_cred,
- &to->sin_addr) != 0) {
- continue;
- }
- #endif
- if (IN4_ISPRIVATE_ADDRESS(&to->sin_addr)) {
- continue;
- }
- if (IN4_ISLOOPBACK_ADDRESS(&to->sin_addr)) {
- continue;
- }
- break;
- #endif
- #ifdef INET6
- case AF_INET6:
- to6 = &sctp_ifap->address.sin6;
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- if (prison_check_ip6(stcb->sctp_ep->ip_inp.inp.inp_cred,
- &to6->sin6_addr) != 0) {
- continue;
- }
- #endif
- if (IN6_IS_ADDR_LOOPBACK(&to6->sin6_addr)) {
- continue;
- }
- if (IN6_IS_ADDR_LINKLOCAL(&to6->sin6_addr)) {
- continue;
- }
- break;
- #endif
- default:
- continue;
- }
- sctp_asconf_queue_mgmt(stcb, sctp_ifap, SCTP_ADD_IP_ADDRESS);
- }
- }
- SCTP_IPI_ADDR_RUNLOCK();
- } else {
- struct sctp_laddr *laddr;
- LIST_FOREACH(laddr, &stcb->sctp_ep->sctp_addr_list, sctp_nxt_addr) {
- if (laddr->ifa == NULL) {
- continue;
- }
- if (laddr->ifa->localifa_flags & SCTP_BEING_DELETED)
- /* Address being deleted by the system, dont
- * list.
- */
- continue;
- if (laddr->action == SCTP_DEL_IP_ADDRESS) {
- /* Address being deleted on this ep
- * don't list.
- */
- continue;
- }
- sctp_ifap = laddr->ifa;
- switch (sctp_ifap->address.sa.sa_family) {
- #ifdef INET
- case AF_INET:
- to = &sctp_ifap->address.sin;
- if (IN4_ISPRIVATE_ADDRESS(&to->sin_addr)) {
- continue;
- }
- if (IN4_ISLOOPBACK_ADDRESS(&to->sin_addr)) {
- continue;
- }
- break;
- #endif
- #ifdef INET6
- case AF_INET6:
- to6 = &sctp_ifap->address.sin6;
- if (IN6_IS_ADDR_LOOPBACK(&to6->sin6_addr)) {
- continue;
- }
- if (IN6_IS_ADDR_LINKLOCAL(&to6->sin6_addr)) {
- continue;
- }
- break;
- #endif
- default:
- continue;
- }
- sctp_asconf_queue_mgmt(stcb, sctp_ifap, SCTP_ADD_IP_ADDRESS);
- }
- }
- skip_rest:
- /* Now we must send the asconf into the queue */
- sctp_send_asconf(stcb, net, SCTP_ADDR_NOT_LOCKED);
- }
|