| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075 |
- /*-
- * SPDX-License-Identifier: BSD-3-Clause
- *
- * Copyright (c) 2001-2008, 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>
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- #include <sys/proc.h>
- #endif
- #include <netinet/sctp_pcb.h>
- #include <netinet/sctp_header.h>
- #include <netinet/sctp_var.h>
- #ifdef INET6
- #include <netinet6/sctp6_var.h>
- #endif
- #include <netinet/sctp_sysctl.h>
- #include <netinet/sctp_output.h>
- #include <netinet/sctp_uio.h>
- #include <netinet/sctp_asconf.h>
- #include <netinet/sctputil.h>
- #include <netinet/sctp_indata.h>
- #include <netinet/sctp_timer.h>
- #include <netinet/sctp_auth.h>
- #include <netinet/sctp_bsd_addr.h>
- #if defined(__Userspace__)
- #include <netinet/sctp_callout.h>
- #else
- #include <netinet/udp.h>
- #endif
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- #include <sys/eventhandler.h>
- #endif
- #if defined(HAVE_SCTP_PEELOFF_SOCKOPT)
- #include <netinet/sctp_peeloff.h>
- #endif /* HAVE_SCTP_PEELOFF_SOCKOPT */
- extern const struct sctp_cc_functions sctp_cc_functions[];
- extern const struct sctp_ss_functions sctp_ss_functions[];
- #if defined(__Userspace__)
- void
- sctp_init(uint16_t port,
- int (*conn_output)(void *addr, void *buffer, size_t length, uint8_t tos, uint8_t set_df),
- void (*debug_printf)(const char *format, ...), int start_threads)
- #elif defined(__APPLE__) && (!defined(APPLE_LEOPARD) && !defined(APPLE_SNOWLEOPARD) &&!defined(APPLE_LION) && !defined(APPLE_MOUNTAINLION))
- void
- sctp_init(struct protosw *pp SCTP_UNUSED, struct domain *dp SCTP_UNUSED)
- #elif defined(__FreeBSD__)
- static void
- sctp_init(void *arg SCTP_UNUSED)
- #else
- void
- sctp_init(void)
- #endif
- {
- #if !defined(__Userspace__)
- u_long sb_max_adj;
- #else
- init_random();
- #endif
- /* Initialize and modify the sysctled variables */
- sctp_init_sysctls();
- #if defined(__Userspace__)
- SCTP_BASE_SYSCTL(sctp_udp_tunneling_port) = port;
- #else
- #if defined(__APPLE__) && !defined(__Userspace__)
- sb_max_adj = (u_long)((u_quad_t) (sb_max) * MCLBYTES / (MSIZE + MCLBYTES));
- SCTP_BASE_SYSCTL(sctp_sendspace) = sb_max_adj;
- #else
- if ((nmbclusters / 8) > SCTP_ASOC_MAX_CHUNKS_ON_QUEUE)
- SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue) = (nmbclusters / 8);
- /*
- * Allow a user to take no more than 1/2 the number of clusters or
- * the SB_MAX, whichever is smaller, for the send window.
- */
- sb_max_adj = (u_long)((u_quad_t) (SB_MAX) * MCLBYTES / (MSIZE + MCLBYTES));
- SCTP_BASE_SYSCTL(sctp_sendspace) = min(sb_max_adj,
- (((uint32_t)nmbclusters / 2) * MCLBYTES));
- #endif
- /*
- * Now for the recv window, should we take the same amount? or
- * should I do 1/2 the SB_MAX instead in the SB_MAX min above. For
- * now I will just copy.
- */
- SCTP_BASE_SYSCTL(sctp_recvspace) = SCTP_BASE_SYSCTL(sctp_sendspace);
- #endif
- SCTP_BASE_VAR(first_time) = 0;
- SCTP_BASE_VAR(sctp_pcb_initialized) = 0;
- #if defined(__Userspace__)
- #if !defined(_WIN32)
- #if defined(INET) || defined(INET6)
- SCTP_BASE_VAR(userspace_route) = -1;
- #endif
- #endif
- #ifdef INET
- SCTP_BASE_VAR(userspace_rawsctp) = -1;
- SCTP_BASE_VAR(userspace_udpsctp) = -1;
- #endif
- #ifdef INET6
- SCTP_BASE_VAR(userspace_rawsctp6) = -1;
- SCTP_BASE_VAR(userspace_udpsctp6) = -1;
- #endif
- SCTP_BASE_VAR(timer_thread_should_exit) = 0;
- SCTP_BASE_VAR(conn_output) = conn_output;
- SCTP_BASE_VAR(debug_printf) = debug_printf;
- SCTP_BASE_VAR(crc32c_offloaded) = 0;
- SCTP_BASE_VAR(iterator_thread_started) = 0;
- SCTP_BASE_VAR(timer_thread_started) = 0;
- #endif
- #if defined(__Userspace__)
- sctp_pcb_init(start_threads);
- if (start_threads) {
- sctp_start_timer_thread();
- }
- #else
- sctp_pcb_init();
- #endif
- #if defined(SCTP_PACKET_LOGGING)
- SCTP_BASE_VAR(packet_log_writers) = 0;
- SCTP_BASE_VAR(packet_log_end) = 0;
- memset(&SCTP_BASE_VAR(packet_log_buffer), 0, SCTP_PACKET_LOG_SIZE);
- #endif
- #if defined(__APPLE__) && !defined(__Userspace__)
- SCTP_BASE_VAR(sctp_main_timer_ticks) = 0;
- sctp_start_main_timer();
- timeout(sctp_delayed_startup, NULL, 1);
- #endif
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- SCTP_BASE_VAR(eh_tag) = EVENTHANDLER_REGISTER(rt_addrmsg,
- sctp_addr_change_event_handler, NULL, EVENTHANDLER_PRI_FIRST);
- #endif
- }
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- VNET_SYSINIT(sctp_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, sctp_init, NULL);
- #ifdef VIMAGE
- static void
- sctp_finish(void *unused __unused)
- {
- EVENTHANDLER_DEREGISTER(rt_addrmsg, SCTP_BASE_VAR(eh_tag));
- sctp_pcb_finish();
- }
- VNET_SYSUNINIT(sctp, SI_SUB_PROTO_DOMAIN, SI_ORDER_FOURTH, sctp_finish, NULL);
- #endif
- #else
- void
- sctp_finish(void)
- {
- #if defined(__APPLE__) && !defined(__Userspace__)
- untimeout(sctp_delayed_startup, NULL);
- sctp_over_udp_stop();
- sctp_address_monitor_stop();
- sctp_stop_main_timer();
- #endif
- #if defined(__Userspace__)
- #if defined(INET) || defined(INET6)
- recv_thread_destroy();
- #endif
- sctp_stop_timer_thread();
- #endif
- sctp_pcb_finish();
- #if defined(_WIN32) && !defined(__Userspace__)
- sctp_finish_sysctls();
- #endif
- #if defined(__Userspace__)
- finish_random();
- #endif
- }
- #endif
- void
- sctp_pathmtu_adjustment(struct sctp_tcb *stcb, uint32_t mtu, bool resend)
- {
- struct sctp_association *asoc;
- struct sctp_tmit_chunk *chk;
- uint32_t overhead;
- asoc = &stcb->asoc;
- KASSERT(mtu < asoc->smallest_mtu,
- ("Currently only reducing association MTU %u supported (MTU %u)",
- asoc->smallest_mtu, mtu));
- asoc->smallest_mtu = mtu;
- if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
- overhead = SCTP_MIN_OVERHEAD;
- } else {
- #if defined(__Userspace__)
- if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_CONN) {
- overhead = sizeof(struct sctphdr);
- } else {
- overhead = SCTP_MIN_V4_OVERHEAD;
- }
- #else
- overhead = SCTP_MIN_V4_OVERHEAD;
- #endif
- }
- if (asoc->idata_supported) {
- if (sctp_auth_is_required_chunk(SCTP_IDATA, asoc->peer_auth_chunks)) {
- overhead += sctp_get_auth_chunk_len(asoc->peer_hmac_id);
- }
- } else {
- if (sctp_auth_is_required_chunk(SCTP_DATA, asoc->peer_auth_chunks)) {
- overhead += sctp_get_auth_chunk_len(asoc->peer_hmac_id);
- }
- }
- KASSERT(overhead % 4 == 0,
- ("overhead (%u) not a multiple of 4", overhead));
- TAILQ_FOREACH(chk, &asoc->send_queue, sctp_next) {
- if (((uint32_t)chk->send_size + overhead) > mtu) {
- chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
- }
- }
- TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) {
- if (((uint32_t)chk->send_size + overhead) > mtu) {
- chk->flags |= CHUNK_FLAGS_FRAGMENT_OK;
- if (resend && chk->sent < SCTP_DATAGRAM_RESEND) {
- /*
- * If requested, mark the chunk for immediate
- * resend, since we sent it being too big.
- */
- sctp_flight_size_decrease(chk);
- sctp_total_flight_decrease(stcb, chk);
- chk->sent = SCTP_DATAGRAM_RESEND;
- sctp_ucount_incr(asoc->sent_queue_retran_cnt);
- chk->rec.data.doing_fast_retransmit = 0;
- if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) {
- sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_PMTU,
- chk->whoTo->flight_size,
- chk->book_size,
- (uint32_t)(uintptr_t)chk->whoTo,
- chk->rec.data.tsn);
- }
- /* Clear any time, so NO RTT is being done. */
- if (chk->do_rtt == 1) {
- chk->do_rtt = 0;
- chk->whoTo->rto_needed = 1;
- }
- }
- }
- }
- }
- #ifdef INET
- #if !defined(__Userspace__)
- void
- sctp_notify(struct sctp_inpcb *inp,
- struct sctp_tcb *stcb,
- struct sctp_nets *net,
- uint8_t icmp_type,
- uint8_t icmp_code,
- uint16_t ip_len,
- uint32_t next_mtu)
- {
- #if defined(__APPLE__) && !defined(__Userspace__)
- struct socket *so;
- #endif
- int timer_stopped;
- if (icmp_type != ICMP_UNREACH) {
- /* We only care about unreachable */
- SCTP_TCB_UNLOCK(stcb);
- return;
- }
- if ((icmp_code == ICMP_UNREACH_NET) ||
- (icmp_code == ICMP_UNREACH_HOST) ||
- (icmp_code == ICMP_UNREACH_NET_UNKNOWN) ||
- (icmp_code == ICMP_UNREACH_HOST_UNKNOWN) ||
- (icmp_code == ICMP_UNREACH_ISOLATED) ||
- (icmp_code == ICMP_UNREACH_NET_PROHIB) ||
- (icmp_code == ICMP_UNREACH_HOST_PROHIB) ||
- #if defined(__NetBSD__)
- (icmp_code == ICMP_UNREACH_ADMIN_PROHIBIT)) {
- #else
- (icmp_code == ICMP_UNREACH_FILTER_PROHIB)) {
- #endif
- /* Mark the net unreachable. */
- if (net->dest_state & SCTP_ADDR_REACHABLE) {
- /* OK, that destination is NOT reachable. */
- net->dest_state &= ~SCTP_ADDR_REACHABLE;
- net->dest_state &= ~SCTP_ADDR_PF;
- sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
- stcb, 0,
- (void *)net, SCTP_SO_NOT_LOCKED);
- }
- SCTP_TCB_UNLOCK(stcb);
- } else if ((icmp_code == ICMP_UNREACH_PROTOCOL) ||
- (icmp_code == ICMP_UNREACH_PORT)) {
- /* Treat it like an ABORT. */
- sctp_abort_notification(stcb, true, false, 0, NULL, SCTP_SO_NOT_LOCKED);
- #if defined(__APPLE__) && !defined(__Userspace__)
- so = SCTP_INP_SO(inp);
- atomic_add_int(&stcb->asoc.refcnt, 1);
- SCTP_TCB_UNLOCK(stcb);
- SCTP_SOCKET_LOCK(so, 1);
- SCTP_TCB_LOCK(stcb);
- atomic_subtract_int(&stcb->asoc.refcnt, 1);
- #endif
- (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
- SCTP_FROM_SCTP_USRREQ + SCTP_LOC_2);
- #if defined(__APPLE__) && !defined(__Userspace__)
- SCTP_SOCKET_UNLOCK(so, 1);
- /* SCTP_TCB_UNLOCK(stcb); MT: I think this is not needed.*/
- #endif
- /* no need to unlock here, since the TCB is gone */
- } else if (icmp_code == ICMP_UNREACH_NEEDFRAG) {
- if (net->dest_state & SCTP_ADDR_NO_PMTUD) {
- SCTP_TCB_UNLOCK(stcb);
- return;
- }
- /* Find the next (smaller) MTU */
- if (next_mtu == 0) {
- /*
- * Old type router that does not tell us what the next
- * MTU is.
- * Rats we will have to guess (in a educated fashion
- * of course).
- */
- next_mtu = sctp_get_prev_mtu(ip_len);
- }
- /* Stop the PMTU timer. */
- if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
- timer_stopped = 1;
- sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
- SCTP_FROM_SCTP_USRREQ + SCTP_LOC_1);
- } else {
- timer_stopped = 0;
- }
- /* Update the path MTU. */
- if (net->port) {
- next_mtu -= sizeof(struct udphdr);
- }
- if (net->mtu > next_mtu) {
- net->mtu = next_mtu;
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- if (net->port) {
- sctp_hc_set_mtu(&net->ro._l_addr, inp->fibnum, next_mtu + sizeof(struct udphdr));
- } else {
- sctp_hc_set_mtu(&net->ro._l_addr, inp->fibnum, next_mtu);
- }
- #endif
- }
- /* Update the association MTU */
- if (stcb->asoc.smallest_mtu > next_mtu) {
- sctp_pathmtu_adjustment(stcb, next_mtu, true);
- }
- /* Finally, start the PMTU timer if it was running before. */
- if (timer_stopped) {
- sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
- }
- SCTP_TCB_UNLOCK(stcb);
- } else {
- SCTP_TCB_UNLOCK(stcb);
- }
- }
- #endif
- #if !defined(__Userspace__)
- void
- #if defined(__APPLE__) && !defined(APPLE_LEOPARD) && !defined(APPLE_SNOWLEOPARD) && !defined(APPLE_LION) && !defined(APPLE_MOUNTAINLION) && !defined(APPLE_ELCAPITAN)
- sctp_ctlinput(int cmd, struct sockaddr *sa, void *vip, struct ifnet *ifp SCTP_UNUSED)
- #else
- sctp_ctlinput(int cmd, struct sockaddr *sa, void *vip)
- #endif
- {
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- struct ip *outer_ip;
- #endif
- struct ip *inner_ip;
- struct sctphdr *sh;
- struct icmp *icmp;
- struct sctp_inpcb *inp;
- struct sctp_tcb *stcb;
- struct sctp_nets *net;
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- struct sctp_init_chunk *ch;
- #endif
- struct sockaddr_in src, dst;
- if (sa->sa_family != AF_INET ||
- ((struct sockaddr_in *)sa)->sin_addr.s_addr == INADDR_ANY) {
- return;
- }
- if (PRC_IS_REDIRECT(cmd)) {
- vip = NULL;
- } else if ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0) {
- return;
- }
- if (vip != NULL) {
- inner_ip = (struct ip *)vip;
- icmp = (struct icmp *)((caddr_t)inner_ip -
- (sizeof(struct icmp) - sizeof(struct ip)));
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- outer_ip = (struct ip *)((caddr_t)icmp - sizeof(struct ip));
- #endif
- sh = (struct sctphdr *)((caddr_t)inner_ip + (inner_ip->ip_hl << 2));
- memset(&src, 0, sizeof(struct sockaddr_in));
- src.sin_family = AF_INET;
- #ifdef HAVE_SIN_LEN
- src.sin_len = sizeof(struct sockaddr_in);
- #endif
- src.sin_port = sh->src_port;
- src.sin_addr = inner_ip->ip_src;
- memset(&dst, 0, sizeof(struct sockaddr_in));
- dst.sin_family = AF_INET;
- #ifdef HAVE_SIN_LEN
- dst.sin_len = sizeof(struct sockaddr_in);
- #endif
- dst.sin_port = sh->dest_port;
- dst.sin_addr = inner_ip->ip_dst;
- /*
- * 'dst' holds the dest of the packet that failed to be sent.
- * 'src' holds our local endpoint address. Thus we reverse
- * the dst and the src in the lookup.
- */
- inp = NULL;
- net = NULL;
- stcb = sctp_findassociation_addr_sa((struct sockaddr *)&dst,
- (struct sockaddr *)&src,
- &inp, &net, 1,
- SCTP_DEFAULT_VRFID);
- if ((stcb != NULL) &&
- (net != NULL) &&
- (inp != NULL)) {
- /* Check the verification tag */
- if (ntohl(sh->v_tag) != 0) {
- /*
- * This must be the verification tag used for
- * sending out packets. We don't consider
- * packets reflecting the verification tag.
- */
- if (ntohl(sh->v_tag) != stcb->asoc.peer_vtag) {
- SCTP_TCB_UNLOCK(stcb);
- return;
- }
- } else {
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- if (ntohs(outer_ip->ip_len) >=
- sizeof(struct ip) +
- 8 + (inner_ip->ip_hl << 2) + 20) {
- /*
- * In this case we can check if we
- * got an INIT chunk and if the
- * initiate tag matches.
- */
- ch = (struct sctp_init_chunk *)(sh + 1);
- if ((ch->ch.chunk_type != SCTP_INITIATION) ||
- (ntohl(ch->init.initiate_tag) != stcb->asoc.my_vtag)) {
- SCTP_TCB_UNLOCK(stcb);
- return;
- }
- } else {
- SCTP_TCB_UNLOCK(stcb);
- return;
- }
- #else
- SCTP_TCB_UNLOCK(stcb);
- return;
- #endif
- }
- sctp_notify(inp, stcb, net,
- icmp->icmp_type,
- icmp->icmp_code,
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- ntohs(inner_ip->ip_len),
- #else
- inner_ip->ip_len,
- #endif
- (uint32_t)ntohs(icmp->icmp_nextmtu));
- #if defined(__Userspace__)
- if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
- (stcb->sctp_socket != NULL)) {
- struct socket *upcall_socket;
- upcall_socket = stcb->sctp_socket;
- SOCK_LOCK(upcall_socket);
- soref(upcall_socket);
- SOCK_UNLOCK(upcall_socket);
- if ((upcall_socket->so_upcall != NULL) &&
- (upcall_socket->so_error != 0)) {
- (*upcall_socket->so_upcall)(upcall_socket, upcall_socket->so_upcallarg, M_NOWAIT);
- }
- ACCEPT_LOCK();
- SOCK_LOCK(upcall_socket);
- sorele(upcall_socket);
- }
- #endif
- } else {
- if ((stcb == NULL) && (inp != NULL)) {
- /* reduce ref-count */
- SCTP_INP_WLOCK(inp);
- SCTP_INP_DECR_REF(inp);
- SCTP_INP_WUNLOCK(inp);
- }
- if (stcb) {
- SCTP_TCB_UNLOCK(stcb);
- }
- }
- }
- return;
- }
- #endif
- #endif
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- static int
- sctp_getcred(SYSCTL_HANDLER_ARGS)
- {
- struct xucred xuc;
- struct sockaddr_in addrs[2];
- struct sctp_inpcb *inp;
- struct sctp_nets *net;
- struct sctp_tcb *stcb;
- int error;
- uint32_t vrf_id;
- /* FIX, for non-bsd is this right? */
- vrf_id = SCTP_DEFAULT_VRFID;
- error = priv_check(req->td, PRIV_NETINET_GETCRED);
- if (error)
- return (error);
- error = SYSCTL_IN(req, addrs, sizeof(addrs));
- if (error)
- return (error);
- stcb = sctp_findassociation_addr_sa(sintosa(&addrs[1]),
- sintosa(&addrs[0]),
- &inp, &net, 1, vrf_id);
- if (stcb == NULL || inp == NULL || inp->sctp_socket == NULL) {
- if ((inp != NULL) && (stcb == NULL)) {
- /* reduce ref-count */
- SCTP_INP_WLOCK(inp);
- SCTP_INP_DECR_REF(inp);
- goto cred_can_cont;
- }
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
- error = ENOENT;
- goto out;
- }
- SCTP_TCB_UNLOCK(stcb);
- /* We use the write lock here, only
- * since in the error leg we need it.
- * If we used RLOCK, then we would have
- * to wlock/decr/unlock/rlock. Which
- * in theory could create a hole. Better
- * to use higher wlock.
- */
- SCTP_INP_WLOCK(inp);
- cred_can_cont:
- error = cr_canseesocket(req->td->td_ucred, inp->sctp_socket);
- if (error) {
- SCTP_INP_WUNLOCK(inp);
- goto out;
- }
- cru2x(inp->sctp_socket->so_cred, &xuc);
- SCTP_INP_WUNLOCK(inp);
- error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred));
- out:
- return (error);
- }
- SYSCTL_PROC(_net_inet_sctp, OID_AUTO, getcred,
- CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
- 0, 0, sctp_getcred, "S,ucred",
- "Get the ucred of a SCTP connection");
- #endif
- #ifdef INET
- #if defined(_WIN32) || defined(__Userspace__)
- int
- #elif defined(__FreeBSD__)
- static void
- #else
- static int
- #endif
- sctp_abort(struct socket *so)
- {
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- struct epoch_tracker et;
- #endif
- struct sctp_inpcb *inp;
- inp = (struct sctp_inpcb *)so->so_pcb;
- if (inp == NULL) {
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- return;
- #else
- SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- return (EINVAL);
- #endif
- }
- SCTP_INP_WLOCK(inp);
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- NET_EPOCH_ENTER(et);
- #endif
- #ifdef SCTP_LOG_CLOSING
- sctp_log_closing(inp, NULL, 17);
- #endif
- if (((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0)) {
- inp->sctp_flags |= SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP;
- #ifdef SCTP_LOG_CLOSING
- sctp_log_closing(inp, NULL, 16);
- #endif
- SCTP_INP_WUNLOCK(inp);
- sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
- SCTP_CALLED_AFTER_CMPSET_OFCLOSE);
- SOCK_LOCK(so);
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- KASSERT(!SOLISTENING(so),
- ("sctp_abort: called on listening socket %p", so));
- #endif
- SCTP_SB_CLEAR(so->so_snd);
- SCTP_SB_CLEAR(so->so_rcv);
- #if defined(__APPLE__) && !defined(__Userspace__)
- so->so_usecount--;
- #else
- /* Now null out the reference, we are completely detached. */
- so->so_pcb = NULL;
- #endif
- SOCK_UNLOCK(so);
- } else {
- SCTP_INP_WUNLOCK(inp);
- }
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- NET_EPOCH_EXIT(et);
- #else
- return (0);
- #endif
- }
- #if defined(__Userspace__)
- int
- #else
- static int
- #endif
- #if defined(__Userspace__)
- sctp_attach(struct socket *so, int proto SCTP_UNUSED, uint32_t vrf_id)
- #elif defined(__FreeBSD__)
- sctp_attach(struct socket *so, int proto SCTP_UNUSED, struct thread *p SCTP_UNUSED)
- #elif defined(_WIN32)
- sctp_attach(struct socket *so, int proto SCTP_UNUSED, PKTHREAD p SCTP_UNUSED)
- #else
- sctp_attach(struct socket *so, int proto SCTP_UNUSED, struct proc *p SCTP_UNUSED)
- #endif
- {
- struct sctp_inpcb *inp;
- struct inpcb *ip_inp;
- int error;
- #if !defined(__Userspace__)
- uint32_t vrf_id = SCTP_DEFAULT_VRFID;
- #endif
- inp = (struct sctp_inpcb *)so->so_pcb;
- if (inp != NULL) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- return (EINVAL);
- }
- if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
- error = SCTP_SORESERVE(so, SCTP_BASE_SYSCTL(sctp_sendspace), SCTP_BASE_SYSCTL(sctp_recvspace));
- if (error) {
- return (error);
- }
- }
- error = sctp_inpcb_alloc(so, vrf_id);
- if (error) {
- return (error);
- }
- inp = (struct sctp_inpcb *)so->so_pcb;
- SCTP_INP_WLOCK(inp);
- inp->sctp_flags &= ~SCTP_PCB_FLAGS_BOUND_V6; /* I'm not v6! */
- ip_inp = &inp->ip_inp.inp;
- ip_inp->inp_vflag |= INP_IPV4;
- ip_inp->inp_ip_ttl = MODULE_GLOBAL(ip_defttl);
- SCTP_INP_WUNLOCK(inp);
- return (0);
- }
- #if defined(__Userspace__)
- int
- sctp_bind(struct socket *so, struct sockaddr *addr) {
- void *p = NULL;
- #elif defined(__FreeBSD__)
- static int
- sctp_bind(struct socket *so, struct sockaddr *addr, struct thread *p)
- {
- #elif defined(__APPLE__)
- static int
- sctp_bind(struct socket *so, struct sockaddr *addr, struct proc *p) {
- #elif defined(_WIN32)
- static int
- sctp_bind(struct socket *so, struct sockaddr *addr, PKTHREAD p) {
- #else
- static int
- sctp_bind(struct socket *so, struct mbuf *nam, struct proc *p)
- {
- struct sockaddr *addr = nam ? mtod(nam, struct sockaddr *): NULL;
- #endif
- struct sctp_inpcb *inp;
- inp = (struct sctp_inpcb *)so->so_pcb;
- if (inp == NULL) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- return (EINVAL);
- }
- if (addr != NULL) {
- #ifdef HAVE_SA_LEN
- if ((addr->sa_family != AF_INET) ||
- (addr->sa_len != sizeof(struct sockaddr_in))) {
- #else
- if (addr->sa_family != AF_INET) {
- #endif
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- return (EINVAL);
- }
- }
- return (sctp_inpcb_bind(so, addr, NULL, p));
- }
- #endif
- #if defined(__Userspace__)
- int
- sctpconn_attach(struct socket *so, int proto SCTP_UNUSED, uint32_t vrf_id)
- {
- struct sctp_inpcb *inp;
- struct inpcb *ip_inp;
- int error;
- inp = (struct sctp_inpcb *)so->so_pcb;
- if (inp != NULL) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- return (EINVAL);
- }
- if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
- error = SCTP_SORESERVE(so, SCTP_BASE_SYSCTL(sctp_sendspace), SCTP_BASE_SYSCTL(sctp_recvspace));
- if (error) {
- return (error);
- }
- }
- error = sctp_inpcb_alloc(so, vrf_id);
- if (error) {
- return (error);
- }
- inp = (struct sctp_inpcb *)so->so_pcb;
- SCTP_INP_WLOCK(inp);
- inp->sctp_flags &= ~SCTP_PCB_FLAGS_BOUND_V6;
- inp->sctp_flags |= SCTP_PCB_FLAGS_BOUND_CONN;
- ip_inp = &inp->ip_inp.inp;
- ip_inp->inp_vflag |= INP_CONN;
- ip_inp->inp_ip_ttl = MODULE_GLOBAL(ip_defttl);
- SCTP_INP_WUNLOCK(inp);
- return (0);
- }
- int
- sctpconn_bind(struct socket *so, struct sockaddr *addr)
- {
- struct sctp_inpcb *inp;
- inp = (struct sctp_inpcb *)so->so_pcb;
- if (inp == NULL) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- return (EINVAL);
- }
- if (addr != NULL) {
- #ifdef HAVE_SA_LEN
- if ((addr->sa_family != AF_CONN) ||
- (addr->sa_len != sizeof(struct sockaddr_conn))) {
- #else
- if (addr->sa_family != AF_CONN) {
- #endif
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- return (EINVAL);
- }
- }
- return (sctp_inpcb_bind(so, addr, NULL, NULL));
- }
- #endif
- #if defined(__FreeBSD__) || defined(_WIN32) || defined(__Userspace__)
- void
- sctp_close(struct socket *so)
- {
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- struct epoch_tracker et;
- #endif
- struct sctp_inpcb *inp;
- inp = (struct sctp_inpcb *)so->so_pcb;
- if (inp == NULL)
- return;
- /* Inform all the lower layer assoc that we
- * are done.
- */
- SCTP_INP_WLOCK(inp);
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- NET_EPOCH_ENTER(et);
- #endif
- #ifdef SCTP_LOG_CLOSING
- sctp_log_closing(inp, NULL, 17);
- #endif
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) {
- inp->sctp_flags |= SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP;
- #if defined(__Userspace__)
- if (((so->so_options & SCTP_SO_LINGER) && (so->so_linger == 0)) ||
- (SCTP_SBAVAIL(&so->so_rcv) > 0)) {
- #else
- if (((so->so_options & SO_LINGER) && (so->so_linger == 0)) ||
- (SCTP_SBAVAIL(&so->so_rcv) > 0)) {
- #endif
- #ifdef SCTP_LOG_CLOSING
- sctp_log_closing(inp, NULL, 13);
- #endif
- SCTP_INP_WUNLOCK(inp);
- sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
- SCTP_CALLED_AFTER_CMPSET_OFCLOSE);
- } else {
- #ifdef SCTP_LOG_CLOSING
- sctp_log_closing(inp, NULL, 14);
- #endif
- SCTP_INP_WUNLOCK(inp);
- sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_GRACEFUL_CLOSE,
- SCTP_CALLED_AFTER_CMPSET_OFCLOSE);
- }
- /* The socket is now detached, no matter what
- * the state of the SCTP association.
- */
- SOCK_LOCK(so);
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- if (!SOLISTENING(so)) {
- SCTP_SB_CLEAR(so->so_snd);
- SCTP_SB_CLEAR(so->so_rcv);
- }
- #else
- SCTP_SB_CLEAR(so->so_snd);
- SCTP_SB_CLEAR(so->so_rcv);
- #endif
- #if !(defined(__APPLE__) && !defined(__Userspace__))
- /* Now null out the reference, we are completely detached. */
- so->so_pcb = NULL;
- #endif
- SOCK_UNLOCK(so);
- } else {
- SCTP_INP_WUNLOCK(inp);
- }
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- NET_EPOCH_EXIT(et);
- #endif
- }
- #else
- int
- sctp_detach(struct socket *so)
- {
- struct sctp_inpcb *inp;
- uint32_t flags;
- inp = (struct sctp_inpcb *)so->so_pcb;
- if (inp == NULL) {
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- return;
- #else
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- return (EINVAL);
- #endif
- }
- sctp_must_try_again:
- flags = inp->sctp_flags;
- #ifdef SCTP_LOG_CLOSING
- sctp_log_closing(inp, NULL, 17);
- #endif
- if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
- (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) {
- #if defined(__Userspace__)
- if (((so->so_options & SCTP_SO_LINGER) && (so->so_linger == 0)) ||
- (SCTP_SBAVAIL(&so->so_rcv) > 0)) {
- #else
- if (((so->so_options & SO_LINGER) && (so->so_linger == 0)) ||
- (SCTP_SBAVAIL(&so->so_rcv) > 0)) {
- #endif
- #ifdef SCTP_LOG_CLOSING
- sctp_log_closing(inp, NULL, 13);
- #endif
- sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
- SCTP_CALLED_AFTER_CMPSET_OFCLOSE);
- } else {
- #ifdef SCTP_LOG_CLOSING
- sctp_log_closing(inp, NULL, 13);
- #endif
- sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_GRACEFUL_CLOSE,
- SCTP_CALLED_AFTER_CMPSET_OFCLOSE);
- }
- /* The socket is now detached, no matter what
- * the state of the SCTP association.
- */
- SCTP_SB_CLEAR(so->so_snd);
- /* same for the rcv ones, they are only
- * here for the accounting/select.
- */
- SCTP_SB_CLEAR(so->so_rcv);
- #if !(defined(__APPLE__) && !defined(__Userspace__))
- /* Now disconnect */
- so->so_pcb = NULL;
- #endif
- } else {
- flags = inp->sctp_flags;
- if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) {
- goto sctp_must_try_again;
- }
- }
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- return;
- #else
- return (0);
- #endif
- }
- #endif
- #if defined(__Userspace__)
- /* __Userspace__ is not calling sctp_sendm */
- #endif
- #if !(defined(_WIN32) && !defined(__Userspace__))
- int
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
- struct mbuf *control, struct thread *p);
- #else
- sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
- struct mbuf *control, struct proc *p);
- #endif
- int
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
- struct mbuf *control, struct thread *p)
- {
- #else
- sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
- struct mbuf *control, struct proc *p)
- {
- #endif
- struct sctp_inpcb *inp;
- int error;
- inp = (struct sctp_inpcb *)so->so_pcb;
- if (inp == NULL) {
- if (control) {
- sctp_m_freem(control);
- control = NULL;
- }
- SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- sctp_m_freem(m);
- return (EINVAL);
- }
- /* Got to have an to address if we are NOT a connected socket */
- if ((addr == NULL) &&
- ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE))) {
- goto connected_type;
- }
- error = 0;
- if (addr == NULL) {
- SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EDESTADDRREQ);
- error = EDESTADDRREQ;
- } else if (addr->sa_family != AF_INET) {
- SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EAFNOSUPPORT);
- error = EAFNOSUPPORT;
- #if defined(HAVE_SA_LEN)
- } else if (addr->sa_len != sizeof(struct sockaddr_in)) {
- SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- #endif
- }
- if (error != 0) {
- sctp_m_freem(m);
- if (control) {
- sctp_m_freem(control);
- control = NULL;
- }
- return (error);
- }
- connected_type:
- /* now what about control */
- if (control) {
- if (inp->control) {
- sctp_m_freem(inp->control);
- inp->control = NULL;
- }
- inp->control = control;
- }
- /* Place the data */
- if (inp->pkt) {
- SCTP_BUF_NEXT(inp->pkt_last) = m;
- inp->pkt_last = m;
- } else {
- inp->pkt_last = inp->pkt = m;
- }
- if (
- #if (defined(__FreeBSD__) || defined(__APPLE__)) && !defined(__Userspace__)
- /* FreeBSD uses a flag passed */
- ((flags & PRUS_MORETOCOME) == 0)
- #else
- 1 /* Open BSD does not have any "more to come"
- * indication */
- #endif
- ) {
- /*
- * note with the current version this code will only be used
- * by OpenBSD-- NetBSD, FreeBSD, and MacOS have methods for
- * re-defining sosend to use the sctp_sosend. One can
- * optionally switch back to this code (by changing back the
- * definitions) but this is not advisable. This code is used
- * by FreeBSD when sending a file with sendfile() though.
- */
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- struct epoch_tracker et;
- #endif
- int ret;
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- NET_EPOCH_ENTER(et);
- #endif
- ret = sctp_output(inp, inp->pkt, addr, inp->control, p, flags);
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- NET_EPOCH_EXIT(et);
- #endif
- inp->pkt = NULL;
- inp->control = NULL;
- return (ret);
- } else {
- return (0);
- }
- }
- #endif
- int
- sctp_disconnect(struct socket *so)
- {
- struct sctp_inpcb *inp;
- inp = (struct sctp_inpcb *)so->so_pcb;
- if (inp == NULL) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
- return (ENOTCONN);
- }
- SCTP_INP_RLOCK(inp);
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
- if (LIST_EMPTY(&inp->sctp_asoc_list)) {
- /* No connection */
- SCTP_INP_RUNLOCK(inp);
- return (0);
- } else {
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- struct epoch_tracker et;
- #endif
- struct sctp_association *asoc;
- struct sctp_tcb *stcb;
- stcb = LIST_FIRST(&inp->sctp_asoc_list);
- if (stcb == NULL) {
- SCTP_INP_RUNLOCK(inp);
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- return (EINVAL);
- }
- SCTP_TCB_LOCK(stcb);
- asoc = &stcb->asoc;
- if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
- /* We are about to be freed, out of here */
- SCTP_TCB_UNLOCK(stcb);
- SCTP_INP_RUNLOCK(inp);
- return (0);
- }
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- NET_EPOCH_ENTER(et);
- #endif
- #if defined(__Userspace__)
- if (((so->so_options & SCTP_SO_LINGER) && (so->so_linger == 0)) ||
- (SCTP_SBAVAIL(&so->so_rcv) > 0)) {
- #else
- if (((so->so_options & SO_LINGER) && (so->so_linger == 0)) ||
- (SCTP_SBAVAIL(&so->so_rcv) > 0)) {
- #endif
- if (SCTP_GET_STATE(stcb) != SCTP_STATE_COOKIE_WAIT) {
- /* Left with Data unread */
- struct mbuf *op_err;
- op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, "");
- sctp_send_abort_tcb(stcb, op_err, SCTP_SO_LOCKED);
- SCTP_STAT_INCR_COUNTER32(sctps_aborted);
- }
- SCTP_INP_RUNLOCK(inp);
- if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) ||
- (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
- SCTP_STAT_DECR_GAUGE32(sctps_currestab);
- }
- (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
- SCTP_FROM_SCTP_USRREQ + SCTP_LOC_3);
- /* No unlock tcb assoc is gone */
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- NET_EPOCH_EXIT(et);
- #endif
- return (0);
- }
- if (TAILQ_EMPTY(&asoc->send_queue) &&
- TAILQ_EMPTY(&asoc->sent_queue) &&
- (asoc->stream_queue_cnt == 0)) {
- /* there is nothing queued to send, so done */
- if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete)(stcb, asoc)) {
- goto abort_anyway;
- }
- if ((SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_SENT) &&
- (SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_ACK_SENT)) {
- /* only send SHUTDOWN 1st time thru */
- struct sctp_nets *netp;
- if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) ||
- (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
- SCTP_STAT_DECR_GAUGE32(sctps_currestab);
- }
- SCTP_SET_STATE(stcb, SCTP_STATE_SHUTDOWN_SENT);
- sctp_stop_timers_for_shutdown(stcb);
- if (stcb->asoc.alternate) {
- netp = stcb->asoc.alternate;
- } else {
- netp = stcb->asoc.primary_destination;
- }
- sctp_send_shutdown(stcb,netp);
- sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
- stcb->sctp_ep, stcb, netp);
- sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
- stcb->sctp_ep, stcb, NULL);
- sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_LOCKED);
- }
- } else {
- /*
- * we still got (or just got) data to send,
- * so set SHUTDOWN_PENDING
- */
- /*
- * XXX sockets draft says that SCTP_EOF
- * should be sent with no data. currently,
- * we will allow user data to be sent first
- * and move to SHUTDOWN-PENDING
- */
- SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_SHUTDOWN_PENDING);
- sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, NULL);
- if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete)(stcb, asoc)) {
- SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_PARTIAL_MSG_LEFT);
- }
- if (TAILQ_EMPTY(&asoc->send_queue) &&
- TAILQ_EMPTY(&asoc->sent_queue) &&
- (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) {
- struct mbuf *op_err;
- abort_anyway:
- op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, "");
- stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ + SCTP_LOC_4;
- sctp_send_abort_tcb(stcb, op_err, SCTP_SO_LOCKED);
- SCTP_STAT_INCR_COUNTER32(sctps_aborted);
- if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) ||
- (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
- SCTP_STAT_DECR_GAUGE32(sctps_currestab);
- }
- SCTP_INP_RUNLOCK(inp);
- (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
- SCTP_FROM_SCTP_USRREQ + SCTP_LOC_5);
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- NET_EPOCH_EXIT(et);
- #endif
- return (0);
- } else {
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED);
- }
- }
- soisdisconnecting(so);
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- NET_EPOCH_EXIT(et);
- #endif
- SCTP_TCB_UNLOCK(stcb);
- SCTP_INP_RUNLOCK(inp);
- return (0);
- }
- /* not reached */
- } else {
- /* UDP model does not support this */
- SCTP_INP_RUNLOCK(inp);
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
- return (EOPNOTSUPP);
- }
- }
- #if defined(__FreeBSD__) || defined(_WIN32) || defined(__Userspace__)
- int
- sctp_flush(struct socket *so, int how)
- {
- /*
- * We will just clear out the values and let
- * subsequent close clear out the data, if any.
- * Note if the user did a shutdown(SHUT_RD) they
- * will not be able to read the data, the socket
- * will block that from happening.
- */
- struct sctp_inpcb *inp;
- inp = (struct sctp_inpcb *)so->so_pcb;
- if (inp == NULL) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- return (EINVAL);
- }
- SCTP_INP_RLOCK(inp);
- /* For the 1 to many model this does nothing */
- if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
- SCTP_INP_RUNLOCK(inp);
- return (0);
- }
- SCTP_INP_RUNLOCK(inp);
- if ((how == PRU_FLUSH_RD) || (how == PRU_FLUSH_RDWR)) {
- /* First make sure the sb will be happy, we don't
- * use these except maybe the count
- */
- SCTP_INP_WLOCK(inp);
- SCTP_INP_READ_LOCK(inp);
- inp->sctp_flags |= SCTP_PCB_FLAGS_SOCKET_CANT_READ;
- SCTP_INP_READ_UNLOCK(inp);
- SCTP_INP_WUNLOCK(inp);
- SOCK_LOCK(so);
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- KASSERT(!SOLISTENING(so),
- ("sctp_flush: called on listening socket %p", so));
- #endif
- SCTP_SB_CLEAR(so->so_rcv);
- SOCK_UNLOCK(so);
- }
- if ((how == PRU_FLUSH_WR) || (how == PRU_FLUSH_RDWR)) {
- /* First make sure the sb will be happy, we don't
- * use these except maybe the count
- */
- SOCK_LOCK(so);
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- KASSERT(!SOLISTENING(so),
- ("sctp_flush: called on listening socket %p", so));
- #endif
- SCTP_SB_CLEAR(so->so_snd);
- SOCK_UNLOCK(so);
- }
- return (0);
- }
- #endif
- int
- sctp_shutdown(struct socket *so)
- {
- struct sctp_inpcb *inp;
- inp = (struct sctp_inpcb *)so->so_pcb;
- if (inp == NULL) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- return (EINVAL);
- }
- SCTP_INP_RLOCK(inp);
- /* For UDP model this is a invalid call */
- if (!((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL))) {
- /* Restore the flags that the soshutdown took away. */
- #if (defined(__FreeBSD__) || defined(_WIN32)) && !defined(__Userspace__)
- SOCKBUF_LOCK(&so->so_rcv);
- so->so_rcv.sb_state &= ~SBS_CANTRCVMORE;
- SOCKBUF_UNLOCK(&so->so_rcv);
- #else
- SOCK_LOCK(so);
- so->so_state &= ~SS_CANTRCVMORE;
- SOCK_UNLOCK(so);
- #endif
- /* This proc will wakeup for read and do nothing (I hope) */
- SCTP_INP_RUNLOCK(inp);
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
- return (EOPNOTSUPP);
- } else {
- /*
- * Ok, if we reach here its the TCP model and it is either
- * a SHUT_WR or SHUT_RDWR.
- * This means we put the shutdown flag against it.
- */
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- struct epoch_tracker et;
- #endif
- struct sctp_tcb *stcb;
- struct sctp_association *asoc;
- struct sctp_nets *netp;
- if ((so->so_state &
- (SS_ISCONNECTED|SS_ISCONNECTING|SS_ISDISCONNECTING)) == 0) {
- SCTP_INP_RUNLOCK(inp);
- return (ENOTCONN);
- }
- socantsendmore(so);
- stcb = LIST_FIRST(&inp->sctp_asoc_list);
- if (stcb == NULL) {
- /*
- * Ok, we hit the case that the shutdown call was
- * made after an abort or something. Nothing to do
- * now.
- */
- SCTP_INP_RUNLOCK(inp);
- return (0);
- }
- SCTP_TCB_LOCK(stcb);
- asoc = &stcb->asoc;
- if (asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) {
- SCTP_TCB_UNLOCK(stcb);
- SCTP_INP_RUNLOCK(inp);
- return (0);
- }
- if ((SCTP_GET_STATE(stcb) != SCTP_STATE_COOKIE_WAIT) &&
- (SCTP_GET_STATE(stcb) != SCTP_STATE_COOKIE_ECHOED) &&
- (SCTP_GET_STATE(stcb) != SCTP_STATE_OPEN)) {
- /* If we are not in or before ESTABLISHED, there is
- * no protocol action required.
- */
- SCTP_TCB_UNLOCK(stcb);
- SCTP_INP_RUNLOCK(inp);
- return (0);
- }
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- NET_EPOCH_ENTER(et);
- #endif
- if (stcb->asoc.alternate) {
- netp = stcb->asoc.alternate;
- } else {
- netp = stcb->asoc.primary_destination;
- }
- if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) &&
- TAILQ_EMPTY(&asoc->send_queue) &&
- TAILQ_EMPTY(&asoc->sent_queue) &&
- (asoc->stream_queue_cnt == 0)) {
- if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete)(stcb, asoc)) {
- goto abort_anyway;
- }
- /* there is nothing queued to send, so I'm done... */
- SCTP_STAT_DECR_GAUGE32(sctps_currestab);
- SCTP_SET_STATE(stcb, SCTP_STATE_SHUTDOWN_SENT);
- sctp_stop_timers_for_shutdown(stcb);
- sctp_send_shutdown(stcb, netp);
- sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
- stcb->sctp_ep, stcb, netp);
- } else {
- /*
- * We still got (or just got) data to send, so set
- * SHUTDOWN_PENDING.
- */
- SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_SHUTDOWN_PENDING);
- if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete)(stcb, asoc)) {
- SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_PARTIAL_MSG_LEFT);
- }
- if (TAILQ_EMPTY(&asoc->send_queue) &&
- TAILQ_EMPTY(&asoc->sent_queue) &&
- (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) {
- struct mbuf *op_err;
- abort_anyway:
- op_err = sctp_generate_cause(SCTP_CAUSE_USER_INITIATED_ABT, "");
- stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ + SCTP_LOC_6;
- SCTP_INP_RUNLOCK(inp);
- sctp_abort_an_association(stcb->sctp_ep, stcb,
- op_err, false, SCTP_SO_LOCKED);
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- NET_EPOCH_EXIT(et);
- #endif
- return (0);
- }
- }
- sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, NULL);
- /* XXX: Why do this in the case where we have still data queued? */
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED);
- SCTP_TCB_UNLOCK(stcb);
- SCTP_INP_RUNLOCK(inp);
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- NET_EPOCH_EXIT(et);
- #endif
- return (0);
- }
- }
- /*
- * copies a "user" presentable address and removes embedded scope, etc.
- * returns 0 on success, 1 on error
- */
- static uint32_t
- sctp_fill_user_address(struct sockaddr *dst, struct sockaddr *src)
- {
- #ifdef INET6
- #if defined(SCTP_EMBEDDED_V6_SCOPE)
- struct sockaddr_in6 lsa6;
- src = (struct sockaddr *)sctp_recover_scope((struct sockaddr_in6 *)src,
- &lsa6);
- #endif
- #endif
- #ifdef HAVE_SA_LEN
- memcpy(dst, src, src->sa_len);
- #else
- switch (src->sa_family) {
- #ifdef INET
- case AF_INET:
- memcpy(dst, src, sizeof(struct sockaddr_in));
- break;
- #endif
- #ifdef INET6
- case AF_INET6:
- memcpy(dst, src, sizeof(struct sockaddr_in6));
- break;
- #endif
- #if defined(__Userspace__)
- case AF_CONN:
- memcpy(dst, src, sizeof(struct sockaddr_conn));
- break;
- #endif
- default:
- /* TSNH */
- break;
- }
- #endif
- return (0);
- }
- static size_t
- sctp_fill_up_addresses_vrf(struct sctp_inpcb *inp,
- struct sctp_tcb *stcb,
- size_t limit,
- struct sockaddr *addr,
- uint32_t vrf_id)
- {
- struct sctp_ifn *sctp_ifn;
- struct sctp_ifa *sctp_ifa;
- size_t actual;
- int loopback_scope;
- #if defined(INET)
- int ipv4_local_scope, ipv4_addr_legal;
- #endif
- #if defined(INET6)
- int local_scope, site_scope, ipv6_addr_legal;
- #endif
- #if defined(__Userspace__)
- int conn_addr_legal;
- #endif
- struct sctp_vrf *vrf;
- SCTP_IPI_ADDR_LOCK_ASSERT();
- actual = 0;
- if (limit == 0)
- return (actual);
- if (stcb) {
- /* Turn on all the appropriate scope */
- loopback_scope = stcb->asoc.scope.loopback_scope;
- #if defined(INET)
- ipv4_local_scope = stcb->asoc.scope.ipv4_local_scope;
- ipv4_addr_legal = stcb->asoc.scope.ipv4_addr_legal;
- #endif
- #if defined(INET6)
- local_scope = stcb->asoc.scope.local_scope;
- site_scope = stcb->asoc.scope.site_scope;
- ipv6_addr_legal = stcb->asoc.scope.ipv6_addr_legal;
- #endif
- #if defined(__Userspace__)
- conn_addr_legal = stcb->asoc.scope.conn_addr_legal;
- #endif
- } else {
- /* Use generic values for endpoints. */
- loopback_scope = 1;
- #if defined(INET)
- ipv4_local_scope = 1;
- #endif
- #if defined(INET6)
- local_scope = 1;
- site_scope = 1;
- #endif
- if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
- #if defined(INET6)
- ipv6_addr_legal = 1;
- #endif
- #if defined(INET)
- if (SCTP_IPV6_V6ONLY(inp)) {
- ipv4_addr_legal = 0;
- } else {
- ipv4_addr_legal = 1;
- }
- #endif
- #if defined(__Userspace__)
- conn_addr_legal = 0;
- #endif
- } else {
- #if defined(INET6)
- ipv6_addr_legal = 0;
- #endif
- #if defined(__Userspace__)
- if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_CONN) {
- conn_addr_legal = 1;
- #if defined(INET)
- ipv4_addr_legal = 0;
- #endif
- } else {
- conn_addr_legal = 0;
- #if defined(INET)
- ipv4_addr_legal = 1;
- #endif
- }
- #else
- #if defined(INET)
- ipv4_addr_legal = 1;
- #endif
- #endif
- }
- }
- vrf = sctp_find_vrf(vrf_id);
- if (vrf == NULL) {
- return (0);
- }
- if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
- LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
- if ((loopback_scope == 0) &&
- SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) {
- /* Skip loopback if loopback_scope not set */
- continue;
- }
- LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
- if (stcb) {
- /*
- * For the BOUND-ALL case, the list
- * associated with a TCB is Always
- * considered a reverse list.. i.e.
- * it lists addresses that are NOT
- * part of the association. If this
- * is one of those we must skip it.
- */
- if (sctp_is_addr_restricted(stcb,
- sctp_ifa)) {
- continue;
- }
- }
- switch (sctp_ifa->address.sa.sa_family) {
- #ifdef INET
- case AF_INET:
- if (ipv4_addr_legal) {
- struct sockaddr_in *sin;
- sin = &sctp_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 ((ipv4_local_scope == 0) &&
- (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) {
- continue;
- }
- #ifdef INET6
- if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) {
- if (actual + sizeof(struct sockaddr_in6) > limit) {
- return (actual);
- }
- in6_sin_2_v4mapsin6(sin, (struct sockaddr_in6 *)addr);
- ((struct sockaddr_in6 *)addr)->sin6_port = inp->sctp_lport;
- addr = (struct sockaddr *)((caddr_t)addr + sizeof(struct sockaddr_in6));
- actual += sizeof(struct sockaddr_in6);
- } else {
- #endif
- if (actual + sizeof(struct sockaddr_in) > limit) {
- return (actual);
- }
- memcpy(addr, sin, sizeof(struct sockaddr_in));
- ((struct sockaddr_in *)addr)->sin_port = inp->sctp_lport;
- addr = (struct sockaddr *)((caddr_t)addr + sizeof(struct sockaddr_in));
- actual += sizeof(struct sockaddr_in);
- #ifdef INET6
- }
- #endif
- } else {
- continue;
- }
- break;
- #endif
- #ifdef INET6
- case AF_INET6:
- if (ipv6_addr_legal) {
- struct sockaddr_in6 *sin6;
- #if defined(SCTP_EMBEDDED_V6_SCOPE) && !defined(SCTP_KAME)
- struct sockaddr_in6 lsa6;
- #endif
- 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(inp->ip_inp.inp.inp_cred,
- &sin6->sin6_addr) != 0) {
- continue;
- }
- #endif
- if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
- if (local_scope == 0)
- continue;
- #if defined(SCTP_EMBEDDED_V6_SCOPE)
- if (sin6->sin6_scope_id == 0) {
- #ifdef SCTP_KAME
- if (sa6_recoverscope(sin6) != 0)
- /*
- * bad link
- * local
- * address
- */
- continue;
- #else
- lsa6 = *sin6;
- if (in6_recoverscope(&lsa6,
- &lsa6.sin6_addr,
- NULL))
- /*
- * bad link
- * local
- * address
- */
- continue;
- sin6 = &lsa6;
- #endif /* SCTP_KAME */
- }
- #endif /* SCTP_EMBEDDED_V6_SCOPE */
- }
- if ((site_scope == 0) &&
- (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) {
- continue;
- }
- if (actual + sizeof(struct sockaddr_in6) > limit) {
- return (actual);
- }
- memcpy(addr, sin6, sizeof(struct sockaddr_in6));
- ((struct sockaddr_in6 *)addr)->sin6_port = inp->sctp_lport;
- addr = (struct sockaddr *)((caddr_t)addr + sizeof(struct sockaddr_in6));
- actual += sizeof(struct sockaddr_in6);
- } else {
- continue;
- }
- break;
- #endif
- #if defined(__Userspace__)
- case AF_CONN:
- if (conn_addr_legal) {
- if (actual + sizeof(struct sockaddr_conn) > limit) {
- return (actual);
- }
- memcpy(addr, &sctp_ifa->address.sconn, sizeof(struct sockaddr_conn));
- ((struct sockaddr_conn *)addr)->sconn_port = inp->sctp_lport;
- addr = (struct sockaddr *)((caddr_t)addr + sizeof(struct sockaddr_conn));
- actual += sizeof(struct sockaddr_conn);
- } else {
- continue;
- }
- #endif
- default:
- /* TSNH */
- break;
- }
- }
- }
- } else {
- struct sctp_laddr *laddr;
- size_t sa_len;
- LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
- if (stcb) {
- if (sctp_is_addr_restricted(stcb, laddr->ifa)) {
- continue;
- }
- }
- #ifdef HAVE_SA_LEN
- sa_len = laddr->ifa->address.sa.sa_len;
- #else
- switch (laddr->ifa->address.sa.sa_family) {
- #ifdef INET
- case AF_INET:
- sa_len = sizeof(struct sockaddr_in);
- break;
- #endif
- #ifdef INET6
- case AF_INET6:
- sa_len = sizeof(struct sockaddr_in6);
- break;
- #endif
- #if defined(__Userspace__)
- case AF_CONN:
- sa_len = sizeof(struct sockaddr_conn);
- break;
- #endif
- default:
- /* TSNH */
- sa_len = 0;
- break;
- }
- #endif
- if (actual + sa_len > limit) {
- return (actual);
- }
- if (sctp_fill_user_address(addr, &laddr->ifa->address.sa))
- continue;
- switch (laddr->ifa->address.sa.sa_family) {
- #ifdef INET
- case AF_INET:
- ((struct sockaddr_in *)addr)->sin_port = inp->sctp_lport;
- break;
- #endif
- #ifdef INET6
- case AF_INET6:
- ((struct sockaddr_in6 *)addr)->sin6_port = inp->sctp_lport;
- break;
- #endif
- #if defined(__Userspace__)
- case AF_CONN:
- ((struct sockaddr_conn *)addr)->sconn_port = inp->sctp_lport;
- break;
- #endif
- default:
- /* TSNH */
- break;
- }
- addr = (struct sockaddr *)((caddr_t)addr + sa_len);
- actual += sa_len;
- }
- }
- return (actual);
- }
- static size_t
- sctp_fill_up_addresses(struct sctp_inpcb *inp,
- struct sctp_tcb *stcb,
- size_t limit,
- struct sockaddr *addr)
- {
- size_t size;
- #ifdef SCTP_MVRF
- uint32_t id;
- #endif
- SCTP_IPI_ADDR_RLOCK();
- #ifdef SCTP_MVRF
- /*
- * FIX ME: ?? this WILL report duplicate addresses if they appear
- * in more than one VRF.
- */
- /* fill up addresses for all VRFs on the endpoint */
- size = 0;
- for (id = 0; (id < inp->num_vrfs) && (size < limit); id++) {
- size += sctp_fill_up_addresses_vrf(inp, stcb, limit, addr,
- inp->m_vrf_ids[id]);
- addr = (struct sockaddr *)((caddr_t)addr + size);
- }
- #else
- /* fill up addresses for the endpoint's default vrf */
- size = sctp_fill_up_addresses_vrf(inp, stcb, limit, addr,
- inp->def_vrf_id);
- #endif
- SCTP_IPI_ADDR_RUNLOCK();
- return (size);
- }
- static size_t
- sctp_max_size_addresses_vrf(struct sctp_inpcb *inp, uint32_t vrf_id)
- {
- struct sctp_vrf *vrf;
- size_t size;
- /*
- * In both sub-set bound an bound_all cases we return the size of
- * the maximum number of addresses that you could get. In reality
- * the sub-set bound may have an exclusion list for a given TCB or
- * in the bound-all case a TCB may NOT include the loopback or other
- * addresses as well.
- */
- SCTP_IPI_ADDR_LOCK_ASSERT();
- vrf = sctp_find_vrf(vrf_id);
- if (vrf == NULL) {
- return (0);
- }
- size = 0;
- if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
- struct sctp_ifn *sctp_ifn;
- struct sctp_ifa *sctp_ifa;
- LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
- LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
- /* Count them if they are the right type */
- switch (sctp_ifa->address.sa.sa_family) {
- #ifdef INET
- case AF_INET:
- #ifdef INET6
- if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4))
- size += sizeof(struct sockaddr_in6);
- else
- size += sizeof(struct sockaddr_in);
- #else
- size += sizeof(struct sockaddr_in);
- #endif
- break;
- #endif
- #ifdef INET6
- case AF_INET6:
- size += sizeof(struct sockaddr_in6);
- break;
- #endif
- #if defined(__Userspace__)
- case AF_CONN:
- size += sizeof(struct sockaddr_conn);
- break;
- #endif
- default:
- break;
- }
- }
- }
- } else {
- struct sctp_laddr *laddr;
- LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
- switch (laddr->ifa->address.sa.sa_family) {
- #ifdef INET
- case AF_INET:
- #ifdef INET6
- if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4))
- size += sizeof(struct sockaddr_in6);
- else
- size += sizeof(struct sockaddr_in);
- #else
- size += sizeof(struct sockaddr_in);
- #endif
- break;
- #endif
- #ifdef INET6
- case AF_INET6:
- size += sizeof(struct sockaddr_in6);
- break;
- #endif
- #if defined(__Userspace__)
- case AF_CONN:
- size += sizeof(struct sockaddr_conn);
- break;
- #endif
- default:
- break;
- }
- }
- }
- return (size);
- }
- static size_t
- sctp_max_size_addresses(struct sctp_inpcb *inp)
- {
- size_t size;
- #ifdef SCTP_MVRF
- int id;
- #endif
- SCTP_IPI_ADDR_RLOCK();
- #ifdef SCTP_MVRF
- /*
- * FIX ME: ?? this WILL count duplicate addresses if they appear
- * in more than one VRF.
- */
- /* Maximum size of all addresses for all VRFs on the endpoint */
- size = 0;
- for (id = 0; id < inp->num_vrfs; id++) {
- size += sctp_max_size_addresses_vrf(inp, inp->m_vrf_ids[id]);
- }
- #else
- /* Maximum size of all addresses for the endpoint's default VRF */
- size = sctp_max_size_addresses_vrf(inp, inp->def_vrf_id);
- #endif
- SCTP_IPI_ADDR_RUNLOCK();
- return (size);
- }
- static int
- sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval,
- size_t optsize, void *p, int delay)
- {
- int error;
- int creat_lock_on = 0;
- struct sctp_tcb *stcb = NULL;
- struct sockaddr *sa;
- unsigned int num_v6 = 0, num_v4 = 0, *totaddrp, totaddr;
- uint32_t vrf_id;
- sctp_assoc_t *a_id;
- SCTPDBG(SCTP_DEBUG_PCB1, "Connectx called\n");
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
- (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
- /* We are already connected AND the TCP model */
- SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE);
- return (EADDRINUSE);
- }
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) &&
- (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE))) {
- SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- return (EINVAL);
- }
- if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
- SCTP_INP_RLOCK(inp);
- stcb = LIST_FIRST(&inp->sctp_asoc_list);
- SCTP_INP_RUNLOCK(inp);
- }
- if (stcb) {
- SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
- return (EALREADY);
- }
- SCTP_INP_INCR_REF(inp);
- SCTP_ASOC_CREATE_LOCK(inp);
- creat_lock_on = 1;
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) {
- SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EFAULT);
- error = EFAULT;
- goto out_now;
- }
- totaddrp = (unsigned int *)optval;
- totaddr = *totaddrp;
- sa = (struct sockaddr *)(totaddrp + 1);
- error = sctp_connectx_helper_find(inp, sa, totaddr, &num_v4, &num_v6, (unsigned int)(optsize - sizeof(int)));
- if (error != 0) {
- /* Already have or am bring up an association */
- SCTP_ASOC_CREATE_UNLOCK(inp);
- creat_lock_on = 0;
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
- goto out_now;
- }
- #ifdef INET6
- if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) &&
- (num_v6 > 0)) {
- error = EINVAL;
- goto out_now;
- }
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
- (num_v4 > 0)) {
- if (SCTP_IPV6_V6ONLY(inp)) {
- /*
- * if IPV6_V6ONLY flag, ignore connections destined
- * to a v4 addr or v4-mapped addr
- */
- SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- goto out_now;
- }
- }
- #endif /* INET6 */
- if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) {
- /* Bind a ephemeral port */
- error = sctp_inpcb_bind(so, NULL, NULL, p);
- if (error) {
- goto out_now;
- }
- }
- /* FIX ME: do we want to pass in a vrf on the connect call? */
- vrf_id = inp->def_vrf_id;
- /* We are GOOD to go */
- stcb = sctp_aloc_assoc_connected(inp, sa, &error, 0, 0, vrf_id,
- inp->sctp_ep.pre_open_stream_count,
- inp->sctp_ep.port,
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- (struct thread *)p,
- #elif defined(_WIN32) && !defined(__Userspace__)
- (PKTHREAD)p,
- #else
- (struct proc *)p,
- #endif
- SCTP_INITIALIZE_AUTH_PARAMS);
- if (stcb == NULL) {
- /* Gak! no memory */
- goto out_now;
- }
- SCTP_SET_STATE(stcb, SCTP_STATE_COOKIE_WAIT);
- /* move to second address */
- switch (sa->sa_family) {
- #ifdef INET
- case AF_INET:
- sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in));
- break;
- #endif
- #ifdef INET6
- case AF_INET6:
- sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in6));
- break;
- #endif
- default:
- break;
- }
- error = 0;
- sctp_connectx_helper_add(stcb, sa, (totaddr-1), &error);
- /* Fill in the return id */
- if (error) {
- goto out_now;
- }
- a_id = (sctp_assoc_t *)optval;
- *a_id = sctp_get_associd(stcb);
- if (delay) {
- /* doing delayed connection */
- stcb->asoc.delayed_connection = 1;
- sctp_timer_start(SCTP_TIMER_TYPE_INIT, inp, stcb, stcb->asoc.primary_destination);
- } else {
- (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
- sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
- }
- SCTP_TCB_UNLOCK(stcb);
- out_now:
- if (creat_lock_on) {
- SCTP_ASOC_CREATE_UNLOCK(inp);
- }
- SCTP_INP_DECR_REF(inp);
- return (error);
- }
- #define SCTP_FIND_STCB(inp, stcb, assoc_id) { \
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||\
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { \
- SCTP_INP_RLOCK(inp); \
- stcb = LIST_FIRST(&inp->sctp_asoc_list); \
- if (stcb) { \
- SCTP_TCB_LOCK(stcb); \
- } \
- SCTP_INP_RUNLOCK(inp); \
- } else if (assoc_id > SCTP_ALL_ASSOC) { \
- stcb = sctp_findassociation_ep_asocid(inp, assoc_id, 1); \
- if (stcb == NULL) { \
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); \
- error = ENOENT; \
- break; \
- } \
- } else { \
- stcb = NULL; \
- } \
- }
- #define SCTP_CHECK_AND_CAST(destp, srcp, type, size) {\
- if (size < sizeof(type)) { \
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); \
- error = EINVAL; \
- break; \
- } else { \
- destp = (type *)srcp; \
- } \
- }
- #if defined(__Userspace__)
- int
- #else
- static int
- #endif
- sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
- void *p) {
- struct sctp_inpcb *inp = NULL;
- int error, val = 0;
- struct sctp_tcb *stcb = NULL;
- if (optval == NULL) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- return (EINVAL);
- }
- inp = (struct sctp_inpcb *)so->so_pcb;
- if (inp == NULL) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- return EINVAL;
- }
- error = 0;
- switch (optname) {
- case SCTP_NODELAY:
- case SCTP_AUTOCLOSE:
- case SCTP_EXPLICIT_EOR:
- case SCTP_AUTO_ASCONF:
- case SCTP_DISABLE_FRAGMENTS:
- case SCTP_I_WANT_MAPPED_V4_ADDR:
- case SCTP_USE_EXT_RCVINFO:
- SCTP_INP_RLOCK(inp);
- switch (optname) {
- case SCTP_DISABLE_FRAGMENTS:
- val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NO_FRAGMENT);
- break;
- case SCTP_I_WANT_MAPPED_V4_ADDR:
- val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4);
- break;
- case SCTP_AUTO_ASCONF:
- if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
- /* only valid for bound all sockets */
- val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTO_ASCONF);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- goto flags_out;
- }
- break;
- case SCTP_EXPLICIT_EOR:
- val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR);
- break;
- case SCTP_NODELAY:
- val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NODELAY);
- break;
- case SCTP_USE_EXT_RCVINFO:
- val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO);
- break;
- case SCTP_AUTOCLOSE:
- if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE))
- val = sctp_ticks_to_secs(inp->sctp_ep.auto_close_time);
- else
- val = 0;
- break;
- default:
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
- error = ENOPROTOOPT;
- } /* end switch (sopt->sopt_name) */
- if (*optsize < sizeof(val)) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- flags_out:
- SCTP_INP_RUNLOCK(inp);
- if (error == 0) {
- /* return the option value */
- *(int *)optval = val;
- *optsize = sizeof(val);
- }
- break;
- case SCTP_GET_PACKET_LOG:
- {
- #ifdef SCTP_PACKET_LOGGING
- uint8_t *target;
- int ret;
- SCTP_CHECK_AND_CAST(target, optval, uint8_t, *optsize);
- ret = sctp_copy_out_packet_log(target , (int)*optsize);
- *optsize = ret;
- #else
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
- error = EOPNOTSUPP;
- #endif
- break;
- }
- case SCTP_REUSE_PORT:
- {
- uint32_t *value;
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE)) {
- /* Can't do this for a 1-m socket */
- error = EINVAL;
- break;
- }
- SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
- *value = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE);
- *optsize = sizeof(uint32_t);
- break;
- }
- case SCTP_PARTIAL_DELIVERY_POINT:
- {
- uint32_t *value;
- SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
- *value = inp->partial_delivery_point;
- *optsize = sizeof(uint32_t);
- break;
- }
- case SCTP_FRAGMENT_INTERLEAVE:
- {
- uint32_t *value;
- SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
- if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE)) {
- if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS)) {
- *value = SCTP_FRAG_LEVEL_2;
- } else {
- *value = SCTP_FRAG_LEVEL_1;
- }
- } else {
- *value = SCTP_FRAG_LEVEL_0;
- }
- *optsize = sizeof(uint32_t);
- break;
- }
- case SCTP_INTERLEAVING_SUPPORTED:
- {
- struct sctp_assoc_value *av;
- SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
- SCTP_FIND_STCB(inp, stcb, av->assoc_id);
- if (stcb) {
- av->assoc_value = stcb->asoc.idata_supported;
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- (av->assoc_id == SCTP_FUTURE_ASSOC))) {
- SCTP_INP_RLOCK(inp);
- if (inp->idata_supported) {
- av->assoc_value = 1;
- } else {
- av->assoc_value = 0;
- }
- SCTP_INP_RUNLOCK(inp);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- }
- if (error == 0) {
- *optsize = sizeof(struct sctp_assoc_value);
- }
- break;
- }
- case SCTP_CMT_ON_OFF:
- {
- struct sctp_assoc_value *av;
- SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
- SCTP_FIND_STCB(inp, stcb, av->assoc_id);
- if (stcb) {
- av->assoc_value = stcb->asoc.sctp_cmt_on_off;
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- (av->assoc_id == SCTP_FUTURE_ASSOC))) {
- SCTP_INP_RLOCK(inp);
- av->assoc_value = inp->sctp_cmt_on_off;
- SCTP_INP_RUNLOCK(inp);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- }
- if (error == 0) {
- *optsize = sizeof(struct sctp_assoc_value);
- }
- break;
- }
- case SCTP_PLUGGABLE_CC:
- {
- struct sctp_assoc_value *av;
- SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
- SCTP_FIND_STCB(inp, stcb, av->assoc_id);
- if (stcb) {
- av->assoc_value = stcb->asoc.congestion_control_module;
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- (av->assoc_id == SCTP_FUTURE_ASSOC))) {
- SCTP_INP_RLOCK(inp);
- av->assoc_value = inp->sctp_ep.sctp_default_cc_module;
- SCTP_INP_RUNLOCK(inp);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- }
- if (error == 0) {
- *optsize = sizeof(struct sctp_assoc_value);
- }
- break;
- }
- case SCTP_CC_OPTION:
- {
- struct sctp_cc_option *cc_opt;
- SCTP_CHECK_AND_CAST(cc_opt, optval, struct sctp_cc_option, *optsize);
- SCTP_FIND_STCB(inp, stcb, cc_opt->aid_value.assoc_id);
- if (stcb == NULL) {
- error = EINVAL;
- } else {
- if (stcb->asoc.cc_functions.sctp_cwnd_socket_option == NULL) {
- error = ENOTSUP;
- } else {
- error = (*stcb->asoc.cc_functions.sctp_cwnd_socket_option)(stcb, 0, cc_opt);
- *optsize = sizeof(struct sctp_cc_option);
- }
- SCTP_TCB_UNLOCK(stcb);
- }
- break;
- }
- case SCTP_PLUGGABLE_SS:
- {
- struct sctp_assoc_value *av;
- SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
- SCTP_FIND_STCB(inp, stcb, av->assoc_id);
- if (stcb) {
- av->assoc_value = stcb->asoc.stream_scheduling_module;
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- (av->assoc_id == SCTP_FUTURE_ASSOC))) {
- SCTP_INP_RLOCK(inp);
- av->assoc_value = inp->sctp_ep.sctp_default_ss_module;
- SCTP_INP_RUNLOCK(inp);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- }
- if (error == 0) {
- *optsize = sizeof(struct sctp_assoc_value);
- }
- break;
- }
- case SCTP_SS_VALUE:
- {
- struct sctp_stream_value *av;
- SCTP_CHECK_AND_CAST(av, optval, struct sctp_stream_value, *optsize);
- SCTP_FIND_STCB(inp, stcb, av->assoc_id);
- if (stcb) {
- if ((av->stream_id >= stcb->asoc.streamoutcnt) ||
- (stcb->asoc.ss_functions.sctp_ss_get_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id],
- &av->stream_value) < 0)) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- } else {
- *optsize = sizeof(struct sctp_stream_value);
- }
- SCTP_TCB_UNLOCK(stcb);
- } else {
- /* Can't get stream value without association */
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- break;
- }
- case SCTP_GET_ADDR_LEN:
- {
- struct sctp_assoc_value *av;
- SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
- error = EINVAL;
- #ifdef INET
- if (av->assoc_value == AF_INET) {
- av->assoc_value = sizeof(struct sockaddr_in);
- error = 0;
- }
- #endif
- #ifdef INET6
- if (av->assoc_value == AF_INET6) {
- av->assoc_value = sizeof(struct sockaddr_in6);
- error = 0;
- }
- #endif
- #if defined(__Userspace__)
- if (av->assoc_value == AF_CONN) {
- av->assoc_value = sizeof(struct sockaddr_conn);
- error = 0;
- }
- #endif
- if (error) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
- } else {
- *optsize = sizeof(struct sctp_assoc_value);
- }
- break;
- }
- case SCTP_GET_ASSOC_NUMBER:
- {
- uint32_t *value, cnt;
- SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
- SCTP_INP_RLOCK(inp);
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
- /* Can't do this for a 1-1 socket */
- error = EINVAL;
- SCTP_INP_RUNLOCK(inp);
- break;
- }
- cnt = 0;
- LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
- cnt++;
- }
- SCTP_INP_RUNLOCK(inp);
- *value = cnt;
- *optsize = sizeof(uint32_t);
- break;
- }
- case SCTP_GET_ASSOC_ID_LIST:
- {
- struct sctp_assoc_ids *ids;
- uint32_t at;
- size_t limit;
- SCTP_CHECK_AND_CAST(ids, optval, struct sctp_assoc_ids, *optsize);
- SCTP_INP_RLOCK(inp);
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
- /* Can't do this for a 1-1 socket */
- error = EINVAL;
- SCTP_INP_RUNLOCK(inp);
- break;
- }
- at = 0;
- limit = (*optsize - sizeof(uint32_t)) / sizeof(sctp_assoc_t);
- LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
- if (at < limit) {
- ids->gaids_assoc_id[at++] = sctp_get_associd(stcb);
- if (at == 0) {
- error = EINVAL;
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
- break;
- }
- } else {
- error = EINVAL;
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
- break;
- }
- }
- SCTP_INP_RUNLOCK(inp);
- if (error == 0) {
- ids->gaids_number_of_ids = at;
- *optsize = ((at * sizeof(sctp_assoc_t)) + sizeof(uint32_t));
- }
- break;
- }
- case SCTP_CONTEXT:
- {
- struct sctp_assoc_value *av;
- SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
- SCTP_FIND_STCB(inp, stcb, av->assoc_id);
- if (stcb) {
- av->assoc_value = stcb->asoc.context;
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- (av->assoc_id == SCTP_FUTURE_ASSOC))) {
- SCTP_INP_RLOCK(inp);
- av->assoc_value = inp->sctp_context;
- SCTP_INP_RUNLOCK(inp);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- }
- if (error == 0) {
- *optsize = sizeof(struct sctp_assoc_value);
- }
- break;
- }
- case SCTP_VRF_ID:
- {
- uint32_t *default_vrfid;
- SCTP_CHECK_AND_CAST(default_vrfid, optval, uint32_t, *optsize);
- *default_vrfid = inp->def_vrf_id;
- *optsize = sizeof(uint32_t);
- break;
- }
- case SCTP_GET_ASOC_VRF:
- {
- struct sctp_assoc_value *id;
- SCTP_CHECK_AND_CAST(id, optval, struct sctp_assoc_value, *optsize);
- SCTP_FIND_STCB(inp, stcb, id->assoc_id);
- if (stcb == NULL) {
- error = EINVAL;
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
- } else {
- id->assoc_value = stcb->asoc.vrf_id;
- SCTP_TCB_UNLOCK(stcb);
- *optsize = sizeof(struct sctp_assoc_value);
- }
- break;
- }
- case SCTP_GET_VRF_IDS:
- {
- #ifdef SCTP_MVRF
- int siz_needed;
- uint32_t *vrf_ids;
- SCTP_CHECK_AND_CAST(vrf_ids, optval, uint32_t, *optsize);
- siz_needed = inp->num_vrfs * sizeof(uint32_t);
- if (*optsize < siz_needed) {
- error = EINVAL;
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
- } else {
- memcpy(vrf_ids, inp->m_vrf_ids, siz_needed);
- *optsize = siz_needed;
- }
- #else
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
- error = EOPNOTSUPP;
- #endif
- break;
- }
- case SCTP_GET_NONCE_VALUES:
- {
- struct sctp_get_nonce_values *gnv;
- SCTP_CHECK_AND_CAST(gnv, optval, struct sctp_get_nonce_values, *optsize);
- SCTP_FIND_STCB(inp, stcb, gnv->gn_assoc_id);
- if (stcb) {
- gnv->gn_peers_tag = stcb->asoc.peer_vtag;
- gnv->gn_local_tag = stcb->asoc.my_vtag;
- SCTP_TCB_UNLOCK(stcb);
- *optsize = sizeof(struct sctp_get_nonce_values);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
- error = ENOTCONN;
- }
- break;
- }
- case SCTP_DELAYED_SACK:
- {
- struct sctp_sack_info *sack;
- SCTP_CHECK_AND_CAST(sack, optval, struct sctp_sack_info, *optsize);
- SCTP_FIND_STCB(inp, stcb, sack->sack_assoc_id);
- if (stcb) {
- sack->sack_delay = stcb->asoc.delayed_ack;
- sack->sack_freq = stcb->asoc.sack_freq;
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- (sack->sack_assoc_id == SCTP_FUTURE_ASSOC))) {
- SCTP_INP_RLOCK(inp);
- sack->sack_delay = sctp_ticks_to_msecs(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]);
- sack->sack_freq = inp->sctp_ep.sctp_sack_freq;
- SCTP_INP_RUNLOCK(inp);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- }
- if (error == 0) {
- *optsize = sizeof(struct sctp_sack_info);
- }
- break;
- }
- case SCTP_GET_SNDBUF_USE:
- {
- struct sctp_sockstat *ss;
- SCTP_CHECK_AND_CAST(ss, optval, struct sctp_sockstat, *optsize);
- SCTP_FIND_STCB(inp, stcb, ss->ss_assoc_id);
- if (stcb) {
- ss->ss_total_sndbuf = stcb->asoc.total_output_queue_size;
- ss->ss_total_recv_buf = (stcb->asoc.size_on_reasm_queue +
- stcb->asoc.size_on_all_streams);
- SCTP_TCB_UNLOCK(stcb);
- *optsize = sizeof(struct sctp_sockstat);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
- error = ENOTCONN;
- }
- break;
- }
- case SCTP_MAX_BURST:
- {
- struct sctp_assoc_value *av;
- SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
- SCTP_FIND_STCB(inp, stcb, av->assoc_id);
- if (stcb) {
- av->assoc_value = stcb->asoc.max_burst;
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- (av->assoc_id == SCTP_FUTURE_ASSOC))) {
- SCTP_INP_RLOCK(inp);
- av->assoc_value = inp->sctp_ep.max_burst;
- SCTP_INP_RUNLOCK(inp);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- }
- if (error == 0) {
- *optsize = sizeof(struct sctp_assoc_value);
- }
- break;
- }
- case SCTP_MAXSEG:
- {
- struct sctp_assoc_value *av;
- SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
- SCTP_FIND_STCB(inp, stcb, av->assoc_id);
- if (stcb) {
- av->assoc_value = stcb->asoc.sctp_frag_point;
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- (av->assoc_id == SCTP_FUTURE_ASSOC))) {
- SCTP_INP_RLOCK(inp);
- av->assoc_value = inp->sctp_frag_point;
- SCTP_INP_RUNLOCK(inp);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- }
- if (error == 0) {
- *optsize = sizeof(struct sctp_assoc_value);
- }
- break;
- }
- case SCTP_GET_STAT_LOG:
- error = sctp_fill_stat_log(optval, optsize);
- break;
- case SCTP_EVENTS:
- {
- struct sctp_event_subscribe *events;
- SCTP_CHECK_AND_CAST(events, optval, struct sctp_event_subscribe, *optsize);
- memset(events, 0, sizeof(struct sctp_event_subscribe));
- SCTP_INP_RLOCK(inp);
- if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT))
- events->sctp_data_io_event = 1;
- if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT))
- events->sctp_association_event = 1;
- if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVPADDREVNT))
- events->sctp_address_event = 1;
- if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT))
- events->sctp_send_failure_event = 1;
- if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVPEERERR))
- events->sctp_peer_error_event = 1;
- if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT))
- events->sctp_shutdown_event = 1;
- if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PDAPIEVNT))
- events->sctp_partial_delivery_event = 1;
- if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT))
- events->sctp_adaptation_layer_event = 1;
- if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTHEVNT))
- events->sctp_authentication_event = 1;
- if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_DRYEVNT))
- events->sctp_sender_dry_event = 1;
- if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT))
- events->sctp_stream_reset_event = 1;
- SCTP_INP_RUNLOCK(inp);
- *optsize = sizeof(struct sctp_event_subscribe);
- break;
- }
- case SCTP_ADAPTATION_LAYER:
- {
- uint32_t *value;
- SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
- SCTP_INP_RLOCK(inp);
- *value = inp->sctp_ep.adaptation_layer_indicator;
- SCTP_INP_RUNLOCK(inp);
- *optsize = sizeof(uint32_t);
- break;
- }
- case SCTP_SET_INITIAL_DBG_SEQ:
- {
- uint32_t *value;
- SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
- SCTP_INP_RLOCK(inp);
- *value = inp->sctp_ep.initial_sequence_debug;
- SCTP_INP_RUNLOCK(inp);
- *optsize = sizeof(uint32_t);
- break;
- }
- case SCTP_GET_LOCAL_ADDR_SIZE:
- {
- uint32_t *value;
- SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
- SCTP_INP_RLOCK(inp);
- *value = (uint32_t)sctp_max_size_addresses(inp);
- SCTP_INP_RUNLOCK(inp);
- *optsize = sizeof(uint32_t);
- break;
- }
- case SCTP_GET_REMOTE_ADDR_SIZE:
- {
- uint32_t *value;
- struct sctp_nets *net;
- size_t size;
- SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
- /* FIXME MT: change to sctp_assoc_value? */
- SCTP_FIND_STCB(inp, stcb, (sctp_assoc_t)*value);
- if (stcb != NULL) {
- size = 0;
- /* Count the sizes */
- TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
- switch (net->ro._l_addr.sa.sa_family) {
- #ifdef INET
- case AF_INET:
- #ifdef INET6
- if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) {
- size += sizeof(struct sockaddr_in6);
- } else {
- size += sizeof(struct sockaddr_in);
- }
- #else
- size += sizeof(struct sockaddr_in);
- #endif
- break;
- #endif
- #ifdef INET6
- case AF_INET6:
- size += sizeof(struct sockaddr_in6);
- break;
- #endif
- #if defined(__Userspace__)
- case AF_CONN:
- size += sizeof(struct sockaddr_conn);
- break;
- #endif
- default:
- break;
- }
- }
- SCTP_TCB_UNLOCK(stcb);
- *value = (uint32_t)size;
- *optsize = sizeof(uint32_t);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- ((sctp_assoc_t)*value <= SCTP_ALL_ASSOC)) {
- error = EINVAL;
- } else {
- error = ENOENT;
- }
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
- }
- break;
- }
- case SCTP_GET_PEER_ADDRESSES:
- /*
- * Get the address information, an array is passed in to
- * fill up we pack it.
- */
- {
- size_t cpsz, left;
- struct sockaddr *addr;
- struct sctp_nets *net;
- struct sctp_getaddresses *saddr;
- SCTP_CHECK_AND_CAST(saddr, optval, struct sctp_getaddresses, *optsize);
- SCTP_FIND_STCB(inp, stcb, saddr->sget_assoc_id);
- if (stcb != NULL) {
- left = *optsize - offsetof(struct sctp_getaddresses, addr);
- *optsize = offsetof(struct sctp_getaddresses, addr);
- addr = &saddr->addr[0].sa;
- TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
- switch (net->ro._l_addr.sa.sa_family) {
- #ifdef INET
- case AF_INET:
- #ifdef INET6
- if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) {
- cpsz = sizeof(struct sockaddr_in6);
- } else {
- cpsz = sizeof(struct sockaddr_in);
- }
- #else
- cpsz = sizeof(struct sockaddr_in);
- #endif
- break;
- #endif
- #ifdef INET6
- case AF_INET6:
- cpsz = sizeof(struct sockaddr_in6);
- break;
- #endif
- #if defined(__Userspace__)
- case AF_CONN:
- cpsz = sizeof(struct sockaddr_conn);
- break;
- #endif
- default:
- cpsz = 0;
- break;
- }
- if (cpsz == 0) {
- break;
- }
- if (left < cpsz) {
- /* not enough room. */
- break;
- }
- #if defined(INET) && defined(INET6)
- if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) &&
- (net->ro._l_addr.sa.sa_family == AF_INET)) {
- /* Must map the address */
- in6_sin_2_v4mapsin6(&net->ro._l_addr.sin,
- (struct sockaddr_in6 *)addr);
- } else {
- memcpy(addr, &net->ro._l_addr, cpsz);
- }
- #else
- memcpy(addr, &net->ro._l_addr, cpsz);
- #endif
- ((struct sockaddr_in *)addr)->sin_port = stcb->rport;
- addr = (struct sockaddr *)((caddr_t)addr + cpsz);
- left -= cpsz;
- *optsize += cpsz;
- }
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- (saddr->sget_assoc_id <= SCTP_ALL_ASSOC)) {
- error = EINVAL;
- } else {
- error = ENOENT;
- }
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
- }
- break;
- }
- case SCTP_GET_LOCAL_ADDRESSES:
- {
- size_t limit, actual;
- struct sctp_getaddresses *saddr;
- SCTP_CHECK_AND_CAST(saddr, optval, struct sctp_getaddresses, *optsize);
- SCTP_FIND_STCB(inp, stcb, saddr->sget_assoc_id);
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- ((saddr->sget_assoc_id == SCTP_CURRENT_ASSOC) ||
- (saddr->sget_assoc_id == SCTP_ALL_ASSOC))) {
- error = EINVAL;
- } else {
- limit = *optsize - offsetof(struct sctp_getaddresses, addr);
- actual = sctp_fill_up_addresses(inp, stcb, limit, &saddr->addr[0].sa);
- *optsize = offsetof(struct sctp_getaddresses, addr) + actual;
- }
- if (stcb != NULL) {
- SCTP_TCB_UNLOCK(stcb);
- }
- break;
- }
- case SCTP_PEER_ADDR_PARAMS:
- {
- struct sctp_paddrparams *paddrp;
- struct sctp_nets *net;
- struct sockaddr *addr;
- #if defined(INET) && defined(INET6)
- struct sockaddr_in sin_store;
- #endif
- SCTP_CHECK_AND_CAST(paddrp, optval, struct sctp_paddrparams, *optsize);
- SCTP_FIND_STCB(inp, stcb, paddrp->spp_assoc_id);
- #if defined(INET) && defined(INET6)
- if (paddrp->spp_address.ss_family == AF_INET6) {
- struct sockaddr_in6 *sin6;
- sin6 = (struct sockaddr_in6 *)&paddrp->spp_address;
- if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
- in6_sin6_2_sin(&sin_store, sin6);
- addr = (struct sockaddr *)&sin_store;
- } else {
- addr = (struct sockaddr *)&paddrp->spp_address;
- }
- } else {
- addr = (struct sockaddr *)&paddrp->spp_address;
- }
- #else
- addr = (struct sockaddr *)&paddrp->spp_address;
- #endif
- if (stcb != NULL) {
- net = sctp_findnet(stcb, addr);
- } else {
- /* We increment here since sctp_findassociation_ep_addr() wil
- * do a decrement if it finds the stcb as long as the locked
- * tcb (last argument) is NOT a TCB.. aka NULL.
- */
- net = NULL;
- SCTP_INP_INCR_REF(inp);
- stcb = sctp_findassociation_ep_addr(&inp, addr, &net, NULL, NULL);
- if (stcb == NULL) {
- SCTP_INP_DECR_REF(inp);
- }
- }
- if ((stcb != NULL) && (net == NULL)) {
- #ifdef INET
- if (addr->sa_family == AF_INET) {
- struct sockaddr_in *sin;
- sin = (struct sockaddr_in *)addr;
- if (sin->sin_addr.s_addr != INADDR_ANY) {
- error = EINVAL;
- SCTP_TCB_UNLOCK(stcb);
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
- break;
- }
- } else
- #endif
- #ifdef INET6
- if (addr->sa_family == AF_INET6) {
- struct sockaddr_in6 *sin6;
- sin6 = (struct sockaddr_in6 *)addr;
- if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
- error = EINVAL;
- SCTP_TCB_UNLOCK(stcb);
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
- break;
- }
- } else
- #endif
- #if defined(__Userspace__)
- if (addr->sa_family == AF_CONN) {
- struct sockaddr_conn *sconn;
- sconn = (struct sockaddr_conn *)addr;
- if (sconn->sconn_addr != NULL) {
- error = EINVAL;
- SCTP_TCB_UNLOCK(stcb);
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
- break;
- }
- } else
- #endif
- {
- error = EAFNOSUPPORT;
- SCTP_TCB_UNLOCK(stcb);
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
- break;
- }
- }
- if (stcb != NULL) {
- /* Applies to the specific association */
- paddrp->spp_flags = 0;
- if (net != NULL) {
- paddrp->spp_hbinterval = net->heart_beat_delay;
- paddrp->spp_pathmaxrxt = net->failure_threshold;
- paddrp->spp_pathmtu = net->mtu;
- switch (net->ro._l_addr.sa.sa_family) {
- #ifdef INET
- case AF_INET:
- paddrp->spp_pathmtu -= SCTP_MIN_V4_OVERHEAD;
- break;
- #endif
- #ifdef INET6
- case AF_INET6:
- paddrp->spp_pathmtu -= SCTP_MIN_OVERHEAD;
- break;
- #endif
- #if defined(__Userspace__)
- case AF_CONN:
- paddrp->spp_pathmtu -= sizeof(struct sctphdr);
- break;
- #endif
- default:
- break;
- }
- /* get flags for HB */
- if (net->dest_state & SCTP_ADDR_NOHB) {
- paddrp->spp_flags |= SPP_HB_DISABLE;
- } else {
- paddrp->spp_flags |= SPP_HB_ENABLE;
- }
- /* get flags for PMTU */
- if (net->dest_state & SCTP_ADDR_NO_PMTUD) {
- paddrp->spp_flags |= SPP_PMTUD_DISABLE;
- } else {
- paddrp->spp_flags |= SPP_PMTUD_ENABLE;
- }
- if (net->dscp & 0x01) {
- paddrp->spp_dscp = net->dscp & 0xfc;
- paddrp->spp_flags |= SPP_DSCP;
- }
- #ifdef INET6
- if ((net->ro._l_addr.sa.sa_family == AF_INET6) &&
- (net->flowlabel & 0x80000000)) {
- paddrp->spp_ipv6_flowlabel = net->flowlabel & 0x000fffff;
- paddrp->spp_flags |= SPP_IPV6_FLOWLABEL;
- }
- #endif
- } else {
- /*
- * No destination so return default
- * value
- */
- paddrp->spp_pathmaxrxt = stcb->asoc.def_net_failure;
- paddrp->spp_pathmtu = stcb->asoc.default_mtu;
- if (stcb->asoc.default_dscp & 0x01) {
- paddrp->spp_dscp = stcb->asoc.default_dscp & 0xfc;
- paddrp->spp_flags |= SPP_DSCP;
- }
- #ifdef INET6
- if (stcb->asoc.default_flowlabel & 0x80000000) {
- paddrp->spp_ipv6_flowlabel = stcb->asoc.default_flowlabel & 0x000fffff;
- paddrp->spp_flags |= SPP_IPV6_FLOWLABEL;
- }
- #endif
- /* default settings should be these */
- if (sctp_stcb_is_feature_on(inp, stcb, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) {
- paddrp->spp_flags |= SPP_HB_DISABLE;
- } else {
- paddrp->spp_flags |= SPP_HB_ENABLE;
- }
- if (sctp_stcb_is_feature_on(inp, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD)) {
- paddrp->spp_flags |= SPP_PMTUD_DISABLE;
- } else {
- paddrp->spp_flags |= SPP_PMTUD_ENABLE;
- }
- paddrp->spp_hbinterval = stcb->asoc.heart_beat_delay;
- }
- paddrp->spp_assoc_id = sctp_get_associd(stcb);
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- (paddrp->spp_assoc_id == SCTP_FUTURE_ASSOC))) {
- /* Use endpoint defaults */
- SCTP_INP_RLOCK(inp);
- paddrp->spp_pathmaxrxt = inp->sctp_ep.def_net_failure;
- paddrp->spp_hbinterval = sctp_ticks_to_msecs(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT]);
- paddrp->spp_assoc_id = SCTP_FUTURE_ASSOC;
- /* get inp's default */
- if (inp->sctp_ep.default_dscp & 0x01) {
- paddrp->spp_dscp = inp->sctp_ep.default_dscp & 0xfc;
- paddrp->spp_flags |= SPP_DSCP;
- }
- #ifdef INET6
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) &&
- (inp->sctp_ep.default_flowlabel & 0x80000000)) {
- paddrp->spp_ipv6_flowlabel = inp->sctp_ep.default_flowlabel & 0x000fffff;
- paddrp->spp_flags |= SPP_IPV6_FLOWLABEL;
- }
- #endif
- paddrp->spp_pathmtu = inp->sctp_ep.default_mtu;
- if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) {
- paddrp->spp_flags |= SPP_HB_ENABLE;
- } else {
- paddrp->spp_flags |= SPP_HB_DISABLE;
- }
- if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD)) {
- paddrp->spp_flags |= SPP_PMTUD_ENABLE;
- } else {
- paddrp->spp_flags |= SPP_PMTUD_DISABLE;
- }
- SCTP_INP_RUNLOCK(inp);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- }
- if (error == 0) {
- *optsize = sizeof(struct sctp_paddrparams);
- }
- break;
- }
- case SCTP_GET_PEER_ADDR_INFO:
- {
- struct sctp_paddrinfo *paddri;
- struct sctp_nets *net;
- struct sockaddr *addr;
- #if defined(INET) && defined(INET6)
- struct sockaddr_in sin_store;
- #endif
- SCTP_CHECK_AND_CAST(paddri, optval, struct sctp_paddrinfo, *optsize);
- SCTP_FIND_STCB(inp, stcb, paddri->spinfo_assoc_id);
- #if defined(INET) && defined(INET6)
- if (paddri->spinfo_address.ss_family == AF_INET6) {
- struct sockaddr_in6 *sin6;
- sin6 = (struct sockaddr_in6 *)&paddri->spinfo_address;
- if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
- in6_sin6_2_sin(&sin_store, sin6);
- addr = (struct sockaddr *)&sin_store;
- } else {
- addr = (struct sockaddr *)&paddri->spinfo_address;
- }
- } else {
- addr = (struct sockaddr *)&paddri->spinfo_address;
- }
- #else
- addr = (struct sockaddr *)&paddri->spinfo_address;
- #endif
- if (stcb != NULL) {
- net = sctp_findnet(stcb, addr);
- } else {
- /* We increment here since sctp_findassociation_ep_addr() wil
- * do a decrement if it finds the stcb as long as the locked
- * tcb (last argument) is NOT a TCB.. aka NULL.
- */
- net = NULL;
- SCTP_INP_INCR_REF(inp);
- stcb = sctp_findassociation_ep_addr(&inp, addr, &net, NULL, NULL);
- if (stcb == NULL) {
- SCTP_INP_DECR_REF(inp);
- }
- }
- if ((stcb != NULL) && (net != NULL)) {
- if (net->dest_state & SCTP_ADDR_UNCONFIRMED) {
- /* It's unconfirmed */
- paddri->spinfo_state = SCTP_UNCONFIRMED;
- } else if (net->dest_state & SCTP_ADDR_REACHABLE) {
- /* It's active */
- paddri->spinfo_state = SCTP_ACTIVE;
- } else {
- /* It's inactive */
- paddri->spinfo_state = SCTP_INACTIVE;
- }
- paddri->spinfo_cwnd = net->cwnd;
- paddri->spinfo_srtt = net->lastsa >> SCTP_RTT_SHIFT;
- paddri->spinfo_rto = net->RTO;
- paddri->spinfo_assoc_id = sctp_get_associd(stcb);
- paddri->spinfo_mtu = net->mtu;
- switch (addr->sa_family) {
- #if defined(INET)
- case AF_INET:
- paddri->spinfo_mtu -= SCTP_MIN_V4_OVERHEAD;
- break;
- #endif
- #if defined(INET6)
- case AF_INET6:
- paddri->spinfo_mtu -= SCTP_MIN_OVERHEAD;
- break;
- #endif
- #if defined(__Userspace__)
- case AF_CONN:
- paddri->spinfo_mtu -= sizeof(struct sctphdr);
- break;
- #endif
- default:
- break;
- }
- SCTP_TCB_UNLOCK(stcb);
- *optsize = sizeof(struct sctp_paddrinfo);
- } else {
- if (stcb != NULL) {
- SCTP_TCB_UNLOCK(stcb);
- }
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
- error = ENOENT;
- }
- break;
- }
- case SCTP_PCB_STATUS:
- {
- struct sctp_pcbinfo *spcb;
- SCTP_CHECK_AND_CAST(spcb, optval, struct sctp_pcbinfo, *optsize);
- sctp_fill_pcbinfo(spcb);
- *optsize = sizeof(struct sctp_pcbinfo);
- break;
- }
- case SCTP_STATUS:
- {
- struct sctp_nets *net;
- struct sctp_status *sstat;
- SCTP_CHECK_AND_CAST(sstat, optval, struct sctp_status, *optsize);
- SCTP_FIND_STCB(inp, stcb, sstat->sstat_assoc_id);
- if (stcb == NULL) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- break;
- }
- sstat->sstat_state = sctp_map_assoc_state(stcb->asoc.state);
- sstat->sstat_assoc_id = sctp_get_associd(stcb);
- sstat->sstat_rwnd = stcb->asoc.peers_rwnd;
- sstat->sstat_unackdata = stcb->asoc.sent_queue_cnt;
- /*
- * We can't include chunks that have been passed to
- * the socket layer. Only things in queue.
- */
- sstat->sstat_penddata = (stcb->asoc.cnt_on_reasm_queue +
- stcb->asoc.cnt_on_all_streams);
- sstat->sstat_instrms = stcb->asoc.streamincnt;
- sstat->sstat_outstrms = stcb->asoc.streamoutcnt;
- sstat->sstat_fragmentation_point = sctp_get_frag_point(stcb);
- net = stcb->asoc.primary_destination;
- if (net != NULL) {
- #ifdef HAVE_SA_LEN
- memcpy(&sstat->sstat_primary.spinfo_address,
- &net->ro._l_addr,
- ((struct sockaddr *)(&net->ro._l_addr))->sa_len);
- #else
- switch (stcb->asoc.primary_destination->ro._l_addr.sa.sa_family) {
- #if defined(INET)
- case AF_INET:
- memcpy(&sstat->sstat_primary.spinfo_address,
- &net->ro._l_addr,
- sizeof(struct sockaddr_in));
- break;
- #endif
- #if defined(INET6)
- case AF_INET6:
- memcpy(&sstat->sstat_primary.spinfo_address,
- &net->ro._l_addr,
- sizeof(struct sockaddr_in6));
- break;
- #endif
- #if defined(__Userspace__)
- case AF_CONN:
- memcpy(&sstat->sstat_primary.spinfo_address,
- &net->ro._l_addr,
- sizeof(struct sockaddr_conn));
- break;
- #endif
- default:
- break;
- }
- #endif
- ((struct sockaddr_in *)&sstat->sstat_primary.spinfo_address)->sin_port = stcb->rport;
- /*
- * Again the user can get info from sctp_constants.h
- * for what the state of the network is.
- */
- if (net->dest_state & SCTP_ADDR_UNCONFIRMED) {
- /* It's unconfirmed */
- sstat->sstat_primary.spinfo_state = SCTP_UNCONFIRMED;
- } else if (net->dest_state & SCTP_ADDR_REACHABLE) {
- /* It's active */
- sstat->sstat_primary.spinfo_state = SCTP_ACTIVE;
- } else {
- /* It's inactive */
- sstat->sstat_primary.spinfo_state = SCTP_INACTIVE;
- }
- sstat->sstat_primary.spinfo_cwnd = net->cwnd;
- sstat->sstat_primary.spinfo_srtt = net->lastsa >> SCTP_RTT_SHIFT;
- sstat->sstat_primary.spinfo_rto = net->RTO;
- sstat->sstat_primary.spinfo_mtu = net->mtu;
- switch (stcb->asoc.primary_destination->ro._l_addr.sa.sa_family) {
- #if defined(INET)
- case AF_INET:
- sstat->sstat_primary.spinfo_mtu -= SCTP_MIN_V4_OVERHEAD;
- break;
- #endif
- #if defined(INET6)
- case AF_INET6:
- sstat->sstat_primary.spinfo_mtu -= SCTP_MIN_OVERHEAD;
- break;
- #endif
- #if defined(__Userspace__)
- case AF_CONN:
- sstat->sstat_primary.spinfo_mtu -= sizeof(struct sctphdr);
- break;
- #endif
- default:
- break;
- }
- } else {
- memset(&sstat->sstat_primary, 0, sizeof(struct sctp_paddrinfo));
- }
- sstat->sstat_primary.spinfo_assoc_id = sctp_get_associd(stcb);
- SCTP_TCB_UNLOCK(stcb);
- *optsize = sizeof(struct sctp_status);
- break;
- }
- case SCTP_RTOINFO:
- {
- struct sctp_rtoinfo *srto;
- SCTP_CHECK_AND_CAST(srto, optval, struct sctp_rtoinfo, *optsize);
- SCTP_FIND_STCB(inp, stcb, srto->srto_assoc_id);
- if (stcb) {
- srto->srto_initial = stcb->asoc.initial_rto;
- srto->srto_max = stcb->asoc.maxrto;
- srto->srto_min = stcb->asoc.minrto;
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- (srto->srto_assoc_id == SCTP_FUTURE_ASSOC))) {
- SCTP_INP_RLOCK(inp);
- srto->srto_initial = inp->sctp_ep.initial_rto;
- srto->srto_max = inp->sctp_ep.sctp_maxrto;
- srto->srto_min = inp->sctp_ep.sctp_minrto;
- SCTP_INP_RUNLOCK(inp);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- }
- if (error == 0) {
- *optsize = sizeof(struct sctp_rtoinfo);
- }
- break;
- }
- case SCTP_TIMEOUTS:
- {
- struct sctp_timeouts *stimo;
- SCTP_CHECK_AND_CAST(stimo, optval, struct sctp_timeouts, *optsize);
- SCTP_FIND_STCB(inp, stcb, stimo->stimo_assoc_id);
- if (stcb) {
- stimo->stimo_init= stcb->asoc.timoinit;
- stimo->stimo_data= stcb->asoc.timodata;
- stimo->stimo_sack= stcb->asoc.timosack;
- stimo->stimo_shutdown= stcb->asoc.timoshutdown;
- stimo->stimo_heartbeat= stcb->asoc.timoheartbeat;
- stimo->stimo_cookie= stcb->asoc.timocookie;
- stimo->stimo_shutdownack= stcb->asoc.timoshutdownack;
- SCTP_TCB_UNLOCK(stcb);
- *optsize = sizeof(struct sctp_timeouts);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- break;
- }
- case SCTP_ASSOCINFO:
- {
- struct sctp_assocparams *sasoc;
- SCTP_CHECK_AND_CAST(sasoc, optval, struct sctp_assocparams, *optsize);
- SCTP_FIND_STCB(inp, stcb, sasoc->sasoc_assoc_id);
- if (stcb) {
- sasoc->sasoc_cookie_life = sctp_ticks_to_msecs(stcb->asoc.cookie_life);
- sasoc->sasoc_asocmaxrxt = stcb->asoc.max_send_times;
- sasoc->sasoc_number_peer_destinations = stcb->asoc.numnets;
- sasoc->sasoc_peer_rwnd = stcb->asoc.peers_rwnd;
- sasoc->sasoc_local_rwnd = stcb->asoc.my_rwnd;
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- (sasoc->sasoc_assoc_id == SCTP_FUTURE_ASSOC))) {
- SCTP_INP_RLOCK(inp);
- sasoc->sasoc_cookie_life = sctp_ticks_to_msecs(inp->sctp_ep.def_cookie_life);
- sasoc->sasoc_asocmaxrxt = inp->sctp_ep.max_send_times;
- sasoc->sasoc_number_peer_destinations = 0;
- sasoc->sasoc_peer_rwnd = 0;
- sasoc->sasoc_local_rwnd = (uint32_t)sbspace(&inp->sctp_socket->so_rcv);
- SCTP_INP_RUNLOCK(inp);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- }
- if (error == 0) {
- *optsize = sizeof(struct sctp_assocparams);
- }
- break;
- }
- case SCTP_DEFAULT_SEND_PARAM:
- {
- struct sctp_sndrcvinfo *s_info;
- SCTP_CHECK_AND_CAST(s_info, optval, struct sctp_sndrcvinfo, *optsize);
- SCTP_FIND_STCB(inp, stcb, s_info->sinfo_assoc_id);
- if (stcb) {
- memcpy(s_info, &stcb->asoc.def_send, sizeof(stcb->asoc.def_send));
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- (s_info->sinfo_assoc_id == SCTP_FUTURE_ASSOC))) {
- SCTP_INP_RLOCK(inp);
- memcpy(s_info, &inp->def_send, sizeof(inp->def_send));
- SCTP_INP_RUNLOCK(inp);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- }
- if (error == 0) {
- *optsize = sizeof(struct sctp_sndrcvinfo);
- }
- break;
- }
- case SCTP_INITMSG:
- {
- struct sctp_initmsg *sinit;
- SCTP_CHECK_AND_CAST(sinit, optval, struct sctp_initmsg, *optsize);
- SCTP_INP_RLOCK(inp);
- sinit->sinit_num_ostreams = inp->sctp_ep.pre_open_stream_count;
- sinit->sinit_max_instreams = inp->sctp_ep.max_open_streams_intome;
- sinit->sinit_max_attempts = inp->sctp_ep.max_init_times;
- sinit->sinit_max_init_timeo = inp->sctp_ep.initial_init_rto_max;
- SCTP_INP_RUNLOCK(inp);
- *optsize = sizeof(struct sctp_initmsg);
- break;
- }
- case SCTP_PRIMARY_ADDR:
- /* we allow a "get" operation on this */
- {
- struct sctp_setprim *ssp;
- SCTP_CHECK_AND_CAST(ssp, optval, struct sctp_setprim, *optsize);
- SCTP_FIND_STCB(inp, stcb, ssp->ssp_assoc_id);
- if (stcb) {
- union sctp_sockstore *addr;
- addr = &stcb->asoc.primary_destination->ro._l_addr;
- switch (addr->sa.sa_family) {
- #ifdef INET
- case AF_INET:
- #ifdef INET6
- if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) {
- in6_sin_2_v4mapsin6(&addr->sin,
- (struct sockaddr_in6 *)&ssp->ssp_addr);
- } else {
- memcpy(&ssp->ssp_addr, &addr->sin, sizeof(struct sockaddr_in));
- }
- #else
- memcpy(&ssp->ssp_addr, &addr->sin, sizeof(struct sockaddr_in));
- #endif
- break;
- #endif
- #ifdef INET6
- case AF_INET6:
- memcpy(&ssp->ssp_addr, &addr->sin6, sizeof(struct sockaddr_in6));
- break;
- #endif
- #if defined(__Userspace__)
- case AF_CONN:
- memcpy(&ssp->ssp_addr, &addr->sconn, sizeof(struct sockaddr_conn));
- break;
- #endif
- default:
- break;
- }
- SCTP_TCB_UNLOCK(stcb);
- *optsize = sizeof(struct sctp_setprim);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- break;
- }
- case SCTP_HMAC_IDENT:
- {
- struct sctp_hmacalgo *shmac;
- sctp_hmaclist_t *hmaclist;
- size_t size;
- int i;
- SCTP_CHECK_AND_CAST(shmac, optval, struct sctp_hmacalgo, *optsize);
- SCTP_INP_RLOCK(inp);
- hmaclist = inp->sctp_ep.local_hmacs;
- if (hmaclist == NULL) {
- /* no HMACs to return */
- *optsize = sizeof(*shmac);
- SCTP_INP_RUNLOCK(inp);
- break;
- }
- /* is there room for all of the hmac ids? */
- size = sizeof(*shmac) + (hmaclist->num_algo *
- sizeof(shmac->shmac_idents[0]));
- if (*optsize < size) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- SCTP_INP_RUNLOCK(inp);
- break;
- }
- /* copy in the list */
- shmac->shmac_number_of_idents = hmaclist->num_algo;
- for (i = 0; i < hmaclist->num_algo; i++) {
- shmac->shmac_idents[i] = hmaclist->hmac[i];
- }
- SCTP_INP_RUNLOCK(inp);
- *optsize = size;
- break;
- }
- case SCTP_AUTH_ACTIVE_KEY:
- {
- struct sctp_authkeyid *scact;
- SCTP_CHECK_AND_CAST(scact, optval, struct sctp_authkeyid, *optsize);
- SCTP_FIND_STCB(inp, stcb, scact->scact_assoc_id);
- if (stcb) {
- /* get the active key on the assoc */
- scact->scact_keynumber = stcb->asoc.authinfo.active_keyid;
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- (scact->scact_assoc_id == SCTP_FUTURE_ASSOC))) {
- /* get the endpoint active key */
- SCTP_INP_RLOCK(inp);
- scact->scact_keynumber = inp->sctp_ep.default_keyid;
- SCTP_INP_RUNLOCK(inp);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- }
- if (error == 0) {
- *optsize = sizeof(struct sctp_authkeyid);
- }
- break;
- }
- case SCTP_LOCAL_AUTH_CHUNKS:
- {
- struct sctp_authchunks *sac;
- sctp_auth_chklist_t *chklist = NULL;
- size_t size = 0;
- SCTP_CHECK_AND_CAST(sac, optval, struct sctp_authchunks, *optsize);
- SCTP_FIND_STCB(inp, stcb, sac->gauth_assoc_id);
- if (stcb) {
- /* get off the assoc */
- chklist = stcb->asoc.local_auth_chunks;
- /* is there enough space? */
- size = sctp_auth_get_chklist_size(chklist);
- if (*optsize < (sizeof(struct sctp_authchunks) + size)) {
- error = EINVAL;
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
- } else {
- /* copy in the chunks */
- (void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks);
- sac->gauth_number_of_chunks = (uint32_t)size;
- *optsize = sizeof(struct sctp_authchunks) + size;
- }
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- (sac->gauth_assoc_id == SCTP_FUTURE_ASSOC))) {
- /* get off the endpoint */
- SCTP_INP_RLOCK(inp);
- chklist = inp->sctp_ep.local_auth_chunks;
- /* is there enough space? */
- size = sctp_auth_get_chklist_size(chklist);
- if (*optsize < (sizeof(struct sctp_authchunks) + size)) {
- error = EINVAL;
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
- } else {
- /* copy in the chunks */
- (void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks);
- sac->gauth_number_of_chunks = (uint32_t)size;
- *optsize = sizeof(struct sctp_authchunks) + size;
- }
- SCTP_INP_RUNLOCK(inp);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- }
- break;
- }
- case SCTP_PEER_AUTH_CHUNKS:
- {
- struct sctp_authchunks *sac;
- sctp_auth_chklist_t *chklist = NULL;
- size_t size = 0;
- SCTP_CHECK_AND_CAST(sac, optval, struct sctp_authchunks, *optsize);
- SCTP_FIND_STCB(inp, stcb, sac->gauth_assoc_id);
- if (stcb) {
- /* get off the assoc */
- chklist = stcb->asoc.peer_auth_chunks;
- /* is there enough space? */
- size = sctp_auth_get_chklist_size(chklist);
- if (*optsize < (sizeof(struct sctp_authchunks) + size)) {
- error = EINVAL;
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
- } else {
- /* copy in the chunks */
- (void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks);
- sac->gauth_number_of_chunks = (uint32_t)size;
- *optsize = sizeof(struct sctp_authchunks) + size;
- }
- SCTP_TCB_UNLOCK(stcb);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
- error = ENOENT;
- }
- break;
- }
- #if defined(HAVE_SCTP_PEELOFF_SOCKOPT)
- case SCTP_PEELOFF:
- {
- struct sctp_peeloff_opt *peeloff;
- SCTP_CHECK_AND_CAST(peeloff, optval, struct sctp_peeloff_opt, *optsize);
- /* do the peeloff */
- error = sctp_peeloff_option(p, peeloff);
- if (error == 0) {
- *optsize = sizeof(struct sctp_peeloff_opt);
- }
- }
- break;
- #endif /* HAVE_SCTP_PEELOFF_SOCKOPT */
- case SCTP_EVENT:
- {
- struct sctp_event *event;
- uint32_t event_type;
- SCTP_CHECK_AND_CAST(event, optval, struct sctp_event, *optsize);
- SCTP_FIND_STCB(inp, stcb, event->se_assoc_id);
- switch (event->se_type) {
- case SCTP_ASSOC_CHANGE:
- event_type = SCTP_PCB_FLAGS_RECVASSOCEVNT;
- break;
- case SCTP_PEER_ADDR_CHANGE:
- event_type = SCTP_PCB_FLAGS_RECVPADDREVNT;
- break;
- case SCTP_REMOTE_ERROR:
- event_type = SCTP_PCB_FLAGS_RECVPEERERR;
- break;
- case SCTP_SEND_FAILED:
- event_type = SCTP_PCB_FLAGS_RECVSENDFAILEVNT;
- break;
- case SCTP_SHUTDOWN_EVENT:
- event_type = SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT;
- break;
- case SCTP_ADAPTATION_INDICATION:
- event_type = SCTP_PCB_FLAGS_ADAPTATIONEVNT;
- break;
- case SCTP_PARTIAL_DELIVERY_EVENT:
- event_type = SCTP_PCB_FLAGS_PDAPIEVNT;
- break;
- case SCTP_AUTHENTICATION_EVENT:
- event_type = SCTP_PCB_FLAGS_AUTHEVNT;
- break;
- case SCTP_STREAM_RESET_EVENT:
- event_type = SCTP_PCB_FLAGS_STREAM_RESETEVNT;
- break;
- case SCTP_SENDER_DRY_EVENT:
- event_type = SCTP_PCB_FLAGS_DRYEVNT;
- break;
- case SCTP_NOTIFICATIONS_STOPPED_EVENT:
- event_type = 0;
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTSUP);
- error = ENOTSUP;
- break;
- case SCTP_ASSOC_RESET_EVENT:
- event_type = SCTP_PCB_FLAGS_ASSOC_RESETEVNT;
- break;
- case SCTP_STREAM_CHANGE_EVENT:
- event_type = SCTP_PCB_FLAGS_STREAM_CHANGEEVNT;
- break;
- case SCTP_SEND_FAILED_EVENT:
- event_type = SCTP_PCB_FLAGS_RECVNSENDFAILEVNT;
- break;
- default:
- event_type = 0;
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- break;
- }
- if (event_type > 0) {
- if (stcb) {
- event->se_on = sctp_stcb_is_feature_on(inp, stcb, event_type);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- (event->se_assoc_id == SCTP_FUTURE_ASSOC))) {
- SCTP_INP_RLOCK(inp);
- event->se_on = sctp_is_feature_on(inp, event_type);
- SCTP_INP_RUNLOCK(inp);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- }
- }
- if (stcb != NULL) {
- SCTP_TCB_UNLOCK(stcb);
- }
- if (error == 0) {
- *optsize = sizeof(struct sctp_event);
- }
- break;
- }
- case SCTP_RECVRCVINFO:
- if (*optsize < sizeof(int)) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- } else {
- SCTP_INP_RLOCK(inp);
- *(int *)optval = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO);
- SCTP_INP_RUNLOCK(inp);
- *optsize = sizeof(int);
- }
- break;
- case SCTP_RECVNXTINFO:
- if (*optsize < sizeof(int)) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- } else {
- SCTP_INP_RLOCK(inp);
- *(int *)optval = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO);
- SCTP_INP_RUNLOCK(inp);
- *optsize = sizeof(int);
- }
- break;
- case SCTP_DEFAULT_SNDINFO:
- {
- struct sctp_sndinfo *info;
- SCTP_CHECK_AND_CAST(info, optval, struct sctp_sndinfo, *optsize);
- SCTP_FIND_STCB(inp, stcb, info->snd_assoc_id);
- if (stcb) {
- info->snd_sid = stcb->asoc.def_send.sinfo_stream;
- info->snd_flags = stcb->asoc.def_send.sinfo_flags;
- info->snd_flags &= 0xfff0;
- info->snd_ppid = stcb->asoc.def_send.sinfo_ppid;
- info->snd_context = stcb->asoc.def_send.sinfo_context;
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- (info->snd_assoc_id == SCTP_FUTURE_ASSOC))) {
- SCTP_INP_RLOCK(inp);
- info->snd_sid = inp->def_send.sinfo_stream;
- info->snd_flags = inp->def_send.sinfo_flags;
- info->snd_flags &= 0xfff0;
- info->snd_ppid = inp->def_send.sinfo_ppid;
- info->snd_context = inp->def_send.sinfo_context;
- SCTP_INP_RUNLOCK(inp);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- }
- if (error == 0) {
- *optsize = sizeof(struct sctp_sndinfo);
- }
- break;
- }
- case SCTP_DEFAULT_PRINFO:
- {
- struct sctp_default_prinfo *info;
- SCTP_CHECK_AND_CAST(info, optval, struct sctp_default_prinfo, *optsize);
- SCTP_FIND_STCB(inp, stcb, info->pr_assoc_id);
- if (stcb) {
- info->pr_policy = PR_SCTP_POLICY(stcb->asoc.def_send.sinfo_flags);
- info->pr_value = stcb->asoc.def_send.sinfo_timetolive;
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- (info->pr_assoc_id == SCTP_FUTURE_ASSOC))) {
- SCTP_INP_RLOCK(inp);
- info->pr_policy = PR_SCTP_POLICY(inp->def_send.sinfo_flags);
- info->pr_value = inp->def_send.sinfo_timetolive;
- SCTP_INP_RUNLOCK(inp);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- }
- if (error == 0) {
- *optsize = sizeof(struct sctp_default_prinfo);
- }
- break;
- }
- case SCTP_PEER_ADDR_THLDS:
- {
- struct sctp_paddrthlds *thlds;
- struct sctp_nets *net;
- struct sockaddr *addr;
- #if defined(INET) && defined(INET6)
- struct sockaddr_in sin_store;
- #endif
- SCTP_CHECK_AND_CAST(thlds, optval, struct sctp_paddrthlds, *optsize);
- SCTP_FIND_STCB(inp, stcb, thlds->spt_assoc_id);
- #if defined(INET) && defined(INET6)
- if (thlds->spt_address.ss_family == AF_INET6) {
- struct sockaddr_in6 *sin6;
- sin6 = (struct sockaddr_in6 *)&thlds->spt_address;
- if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
- in6_sin6_2_sin(&sin_store, sin6);
- addr = (struct sockaddr *)&sin_store;
- } else {
- addr = (struct sockaddr *)&thlds->spt_address;
- }
- } else {
- addr = (struct sockaddr *)&thlds->spt_address;
- }
- #else
- addr = (struct sockaddr *)&thlds->spt_address;
- #endif
- if (stcb != NULL) {
- net = sctp_findnet(stcb, addr);
- } else {
- /* We increment here since sctp_findassociation_ep_addr() wil
- * do a decrement if it finds the stcb as long as the locked
- * tcb (last argument) is NOT a TCB.. aka NULL.
- */
- net = NULL;
- SCTP_INP_INCR_REF(inp);
- stcb = sctp_findassociation_ep_addr(&inp, addr, &net, NULL, NULL);
- if (stcb == NULL) {
- SCTP_INP_DECR_REF(inp);
- }
- }
- if ((stcb != NULL) && (net == NULL)) {
- #ifdef INET
- if (addr->sa_family == AF_INET) {
- struct sockaddr_in *sin;
- sin = (struct sockaddr_in *)addr;
- if (sin->sin_addr.s_addr != INADDR_ANY) {
- error = EINVAL;
- SCTP_TCB_UNLOCK(stcb);
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
- break;
- }
- } else
- #endif
- #ifdef INET6
- if (addr->sa_family == AF_INET6) {
- struct sockaddr_in6 *sin6;
- sin6 = (struct sockaddr_in6 *)addr;
- if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
- error = EINVAL;
- SCTP_TCB_UNLOCK(stcb);
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
- break;
- }
- } else
- #endif
- #if defined(__Userspace__)
- if (addr->sa_family == AF_CONN) {
- struct sockaddr_conn *sconn;
- sconn = (struct sockaddr_conn *)addr;
- if (sconn->sconn_addr != NULL) {
- error = EINVAL;
- SCTP_TCB_UNLOCK(stcb);
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
- break;
- }
- } else
- #endif
- {
- error = EAFNOSUPPORT;
- SCTP_TCB_UNLOCK(stcb);
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
- break;
- }
- }
- if (stcb != NULL) {
- if (net != NULL) {
- thlds->spt_pathmaxrxt = net->failure_threshold;
- thlds->spt_pathpfthld = net->pf_threshold;
- thlds->spt_pathcpthld = 0xffff;
- } else {
- thlds->spt_pathmaxrxt = stcb->asoc.def_net_failure;
- thlds->spt_pathpfthld = stcb->asoc.def_net_pf_threshold;
- thlds->spt_pathcpthld = 0xffff;
- }
- thlds->spt_assoc_id = sctp_get_associd(stcb);
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- (thlds->spt_assoc_id == SCTP_FUTURE_ASSOC))) {
- /* Use endpoint defaults */
- SCTP_INP_RLOCK(inp);
- thlds->spt_pathmaxrxt = inp->sctp_ep.def_net_failure;
- thlds->spt_pathpfthld = inp->sctp_ep.def_net_pf_threshold;
- thlds->spt_pathcpthld = 0xffff;
- SCTP_INP_RUNLOCK(inp);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- }
- if (error == 0) {
- *optsize = sizeof(struct sctp_paddrthlds);
- }
- break;
- }
- case SCTP_REMOTE_UDP_ENCAPS_PORT:
- {
- struct sctp_udpencaps *encaps;
- struct sctp_nets *net;
- struct sockaddr *addr;
- #if defined(INET) && defined(INET6)
- struct sockaddr_in sin_store;
- #endif
- SCTP_CHECK_AND_CAST(encaps, optval, struct sctp_udpencaps, *optsize);
- SCTP_FIND_STCB(inp, stcb, encaps->sue_assoc_id);
- #if defined(INET) && defined(INET6)
- if (encaps->sue_address.ss_family == AF_INET6) {
- struct sockaddr_in6 *sin6;
- sin6 = (struct sockaddr_in6 *)&encaps->sue_address;
- if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
- in6_sin6_2_sin(&sin_store, sin6);
- addr = (struct sockaddr *)&sin_store;
- } else {
- addr = (struct sockaddr *)&encaps->sue_address;
- }
- } else {
- addr = (struct sockaddr *)&encaps->sue_address;
- }
- #else
- addr = (struct sockaddr *)&encaps->sue_address;
- #endif
- if (stcb) {
- net = sctp_findnet(stcb, addr);
- } else {
- /* We increment here since sctp_findassociation_ep_addr() wil
- * do a decrement if it finds the stcb as long as the locked
- * tcb (last argument) is NOT a TCB.. aka NULL.
- */
- net = NULL;
- SCTP_INP_INCR_REF(inp);
- stcb = sctp_findassociation_ep_addr(&inp, addr, &net, NULL, NULL);
- if (stcb == NULL) {
- SCTP_INP_DECR_REF(inp);
- }
- }
- if ((stcb != NULL) && (net == NULL)) {
- #ifdef INET
- if (addr->sa_family == AF_INET) {
- struct sockaddr_in *sin;
- sin = (struct sockaddr_in *)addr;
- if (sin->sin_addr.s_addr != INADDR_ANY) {
- error = EINVAL;
- SCTP_TCB_UNLOCK(stcb);
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
- break;
- }
- } else
- #endif
- #ifdef INET6
- if (addr->sa_family == AF_INET6) {
- struct sockaddr_in6 *sin6;
- sin6 = (struct sockaddr_in6 *)addr;
- if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
- error = EINVAL;
- SCTP_TCB_UNLOCK(stcb);
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
- break;
- }
- } else
- #endif
- #if defined(__Userspace__)
- if (addr->sa_family == AF_CONN) {
- struct sockaddr_conn *sconn;
- sconn = (struct sockaddr_conn *)addr;
- if (sconn->sconn_addr != NULL) {
- error = EINVAL;
- SCTP_TCB_UNLOCK(stcb);
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
- break;
- }
- } else
- #endif
- {
- error = EAFNOSUPPORT;
- SCTP_TCB_UNLOCK(stcb);
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
- break;
- }
- }
- if (stcb != NULL) {
- if (net) {
- encaps->sue_port = net->port;
- } else {
- encaps->sue_port = stcb->asoc.port;
- }
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- (encaps->sue_assoc_id == SCTP_FUTURE_ASSOC))) {
- SCTP_INP_RLOCK(inp);
- encaps->sue_port = inp->sctp_ep.port;
- SCTP_INP_RUNLOCK(inp);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- }
- if (error == 0) {
- *optsize = sizeof(struct sctp_udpencaps);
- }
- break;
- }
- case SCTP_ECN_SUPPORTED:
- {
- struct sctp_assoc_value *av;
- SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
- SCTP_FIND_STCB(inp, stcb, av->assoc_id);
- if (stcb) {
- av->assoc_value = stcb->asoc.ecn_supported;
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- (av->assoc_id == SCTP_FUTURE_ASSOC))) {
- SCTP_INP_RLOCK(inp);
- av->assoc_value = inp->ecn_supported;
- SCTP_INP_RUNLOCK(inp);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- }
- if (error == 0) {
- *optsize = sizeof(struct sctp_assoc_value);
- }
- break;
- }
- case SCTP_PR_SUPPORTED:
- {
- struct sctp_assoc_value *av;
- SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
- SCTP_FIND_STCB(inp, stcb, av->assoc_id);
- if (stcb) {
- av->assoc_value = stcb->asoc.prsctp_supported;
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- (av->assoc_id == SCTP_FUTURE_ASSOC))) {
- SCTP_INP_RLOCK(inp);
- av->assoc_value = inp->prsctp_supported;
- SCTP_INP_RUNLOCK(inp);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- }
- if (error == 0) {
- *optsize = sizeof(struct sctp_assoc_value);
- }
- break;
- }
- case SCTP_AUTH_SUPPORTED:
- {
- struct sctp_assoc_value *av;
- SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
- SCTP_FIND_STCB(inp, stcb, av->assoc_id);
- if (stcb) {
- av->assoc_value = stcb->asoc.auth_supported;
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- (av->assoc_id == SCTP_FUTURE_ASSOC))) {
- SCTP_INP_RLOCK(inp);
- av->assoc_value = inp->auth_supported;
- SCTP_INP_RUNLOCK(inp);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- }
- if (error == 0) {
- *optsize = sizeof(struct sctp_assoc_value);
- }
- break;
- }
- case SCTP_ASCONF_SUPPORTED:
- {
- struct sctp_assoc_value *av;
- SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
- SCTP_FIND_STCB(inp, stcb, av->assoc_id);
- if (stcb) {
- av->assoc_value = stcb->asoc.asconf_supported;
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- (av->assoc_id == SCTP_FUTURE_ASSOC))) {
- SCTP_INP_RLOCK(inp);
- av->assoc_value = inp->asconf_supported;
- SCTP_INP_RUNLOCK(inp);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- }
- if (error == 0) {
- *optsize = sizeof(struct sctp_assoc_value);
- }
- break;
- }
- case SCTP_RECONFIG_SUPPORTED:
- {
- struct sctp_assoc_value *av;
- SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
- SCTP_FIND_STCB(inp, stcb, av->assoc_id);
- if (stcb) {
- av->assoc_value = stcb->asoc.reconfig_supported;
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- (av->assoc_id == SCTP_FUTURE_ASSOC))) {
- SCTP_INP_RLOCK(inp);
- av->assoc_value = inp->reconfig_supported;
- SCTP_INP_RUNLOCK(inp);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- }
- if (error == 0) {
- *optsize = sizeof(struct sctp_assoc_value);
- }
- break;
- }
- case SCTP_NRSACK_SUPPORTED:
- {
- struct sctp_assoc_value *av;
- SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
- SCTP_FIND_STCB(inp, stcb, av->assoc_id);
- if (stcb) {
- av->assoc_value = stcb->asoc.nrsack_supported;
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- (av->assoc_id == SCTP_FUTURE_ASSOC))) {
- SCTP_INP_RLOCK(inp);
- av->assoc_value = inp->nrsack_supported;
- SCTP_INP_RUNLOCK(inp);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- }
- if (error == 0) {
- *optsize = sizeof(struct sctp_assoc_value);
- }
- break;
- }
- case SCTP_PKTDROP_SUPPORTED:
- {
- struct sctp_assoc_value *av;
- SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
- SCTP_FIND_STCB(inp, stcb, av->assoc_id);
- if (stcb) {
- av->assoc_value = stcb->asoc.pktdrop_supported;
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- (av->assoc_id == SCTP_FUTURE_ASSOC))) {
- SCTP_INP_RLOCK(inp);
- av->assoc_value = inp->pktdrop_supported;
- SCTP_INP_RUNLOCK(inp);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- }
- if (error == 0) {
- *optsize = sizeof(struct sctp_assoc_value);
- }
- break;
- }
- case SCTP_ENABLE_STREAM_RESET:
- {
- struct sctp_assoc_value *av;
- SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
- SCTP_FIND_STCB(inp, stcb, av->assoc_id);
- if (stcb) {
- av->assoc_value = (uint32_t)stcb->asoc.local_strreset_support;
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- (av->assoc_id == SCTP_FUTURE_ASSOC))) {
- SCTP_INP_RLOCK(inp);
- av->assoc_value = (uint32_t)inp->local_strreset_support;
- SCTP_INP_RUNLOCK(inp);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- }
- if (error == 0) {
- *optsize = sizeof(struct sctp_assoc_value);
- }
- break;
- }
- case SCTP_PR_STREAM_STATUS:
- {
- struct sctp_prstatus *sprstat;
- uint16_t sid;
- uint16_t policy;
- SCTP_CHECK_AND_CAST(sprstat, optval, struct sctp_prstatus, *optsize);
- SCTP_FIND_STCB(inp, stcb, sprstat->sprstat_assoc_id);
- sid = sprstat->sprstat_sid;
- policy = sprstat->sprstat_policy;
- #if defined(SCTP_DETAILED_STR_STATS)
- if ((stcb != NULL) &&
- (sid < stcb->asoc.streamoutcnt) &&
- (policy != SCTP_PR_SCTP_NONE) &&
- ((policy <= SCTP_PR_SCTP_MAX) ||
- (policy == SCTP_PR_SCTP_ALL))) {
- if (policy == SCTP_PR_SCTP_ALL) {
- sprstat->sprstat_abandoned_unsent = stcb->asoc.strmout[sid].abandoned_unsent[0];
- sprstat->sprstat_abandoned_sent = stcb->asoc.strmout[sid].abandoned_sent[0];
- } else {
- sprstat->sprstat_abandoned_unsent = stcb->asoc.strmout[sid].abandoned_unsent[policy];
- sprstat->sprstat_abandoned_sent = stcb->asoc.strmout[sid].abandoned_sent[policy];
- }
- #else
- if ((stcb != NULL) &&
- (sid < stcb->asoc.streamoutcnt) &&
- (policy == SCTP_PR_SCTP_ALL)) {
- sprstat->sprstat_abandoned_unsent = stcb->asoc.strmout[sid].abandoned_unsent[0];
- sprstat->sprstat_abandoned_sent = stcb->asoc.strmout[sid].abandoned_sent[0];
- #endif
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- if (stcb != NULL) {
- SCTP_TCB_UNLOCK(stcb);
- }
- if (error == 0) {
- *optsize = sizeof(struct sctp_prstatus);
- }
- break;
- }
- case SCTP_PR_ASSOC_STATUS:
- {
- struct sctp_prstatus *sprstat;
- uint16_t policy;
- SCTP_CHECK_AND_CAST(sprstat, optval, struct sctp_prstatus, *optsize);
- SCTP_FIND_STCB(inp, stcb, sprstat->sprstat_assoc_id);
- policy = sprstat->sprstat_policy;
- if ((stcb != NULL) &&
- (policy != SCTP_PR_SCTP_NONE) &&
- ((policy <= SCTP_PR_SCTP_MAX) ||
- (policy == SCTP_PR_SCTP_ALL))) {
- if (policy == SCTP_PR_SCTP_ALL) {
- sprstat->sprstat_abandoned_unsent = stcb->asoc.abandoned_unsent[0];
- sprstat->sprstat_abandoned_sent = stcb->asoc.abandoned_sent[0];
- } else {
- sprstat->sprstat_abandoned_unsent = stcb->asoc.abandoned_unsent[policy];
- sprstat->sprstat_abandoned_sent = stcb->asoc.abandoned_sent[policy];
- }
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- if (stcb != NULL) {
- SCTP_TCB_UNLOCK(stcb);
- }
- if (error == 0) {
- *optsize = sizeof(struct sctp_prstatus);
- }
- break;
- }
- case SCTP_MAX_CWND:
- {
- struct sctp_assoc_value *av;
- SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
- SCTP_FIND_STCB(inp, stcb, av->assoc_id);
- if (stcb) {
- av->assoc_value = stcb->asoc.max_cwnd;
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- (av->assoc_id == SCTP_FUTURE_ASSOC))) {
- SCTP_INP_RLOCK(inp);
- av->assoc_value = inp->max_cwnd;
- SCTP_INP_RUNLOCK(inp);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- }
- if (error == 0) {
- *optsize = sizeof(struct sctp_assoc_value);
- }
- break;
- }
- default:
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
- error = ENOPROTOOPT;
- break;
- } /* end switch (sopt->sopt_name) */
- if (error) {
- *optsize = 0;
- }
- return (error);
- }
- #if defined(__Userspace__)
- int
- #else
- static int
- #endif
- sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
- void *p)
- {
- int error, set_opt;
- uint32_t *mopt;
- struct sctp_tcb *stcb = NULL;
- struct sctp_inpcb *inp = NULL;
- uint32_t vrf_id;
- if (optval == NULL) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- return (EINVAL);
- }
- inp = (struct sctp_inpcb *)so->so_pcb;
- if (inp == NULL) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- return (EINVAL);
- }
- vrf_id = inp->def_vrf_id;
- error = 0;
- switch (optname) {
- case SCTP_NODELAY:
- case SCTP_AUTOCLOSE:
- case SCTP_AUTO_ASCONF:
- case SCTP_EXPLICIT_EOR:
- case SCTP_DISABLE_FRAGMENTS:
- case SCTP_USE_EXT_RCVINFO:
- case SCTP_I_WANT_MAPPED_V4_ADDR:
- /* copy in the option value */
- SCTP_CHECK_AND_CAST(mopt, optval, uint32_t, optsize);
- set_opt = 0;
- if (error)
- break;
- switch (optname) {
- case SCTP_DISABLE_FRAGMENTS:
- set_opt = SCTP_PCB_FLAGS_NO_FRAGMENT;
- break;
- case SCTP_AUTO_ASCONF:
- /*
- * NOTE: we don't really support this flag
- */
- if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
- /* only valid for bound all sockets */
- if ((SCTP_BASE_SYSCTL(sctp_auto_asconf) == 0) &&
- (*mopt != 0)) {
- /* forbidden by admin */
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EPERM);
- return (EPERM);
- }
- set_opt = SCTP_PCB_FLAGS_AUTO_ASCONF;
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- return (EINVAL);
- }
- break;
- case SCTP_EXPLICIT_EOR:
- set_opt = SCTP_PCB_FLAGS_EXPLICIT_EOR;
- break;
- case SCTP_USE_EXT_RCVINFO:
- set_opt = SCTP_PCB_FLAGS_EXT_RCVINFO;
- break;
- case SCTP_I_WANT_MAPPED_V4_ADDR:
- if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
- set_opt = SCTP_PCB_FLAGS_NEEDS_MAPPED_V4;
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- return (EINVAL);
- }
- break;
- case SCTP_NODELAY:
- set_opt = SCTP_PCB_FLAGS_NODELAY;
- break;
- case SCTP_AUTOCLOSE:
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- return (EINVAL);
- }
- set_opt = SCTP_PCB_FLAGS_AUTOCLOSE;
- /*
- * The value is in ticks. Note this does not effect
- * old associations, only new ones.
- */
- inp->sctp_ep.auto_close_time = sctp_secs_to_ticks(*mopt);
- break;
- }
- SCTP_INP_WLOCK(inp);
- if (*mopt != 0) {
- sctp_feature_on(inp, set_opt);
- } else {
- sctp_feature_off(inp, set_opt);
- }
- SCTP_INP_WUNLOCK(inp);
- break;
- case SCTP_REUSE_PORT:
- {
- SCTP_CHECK_AND_CAST(mopt, optval, uint32_t, optsize);
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 0) {
- /* Can't set it after we are bound */
- error = EINVAL;
- break;
- }
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE)) {
- /* Can't do this for a 1-m socket */
- error = EINVAL;
- break;
- }
- if (optval)
- sctp_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE);
- else
- sctp_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE);
- break;
- }
- case SCTP_PARTIAL_DELIVERY_POINT:
- {
- uint32_t *value;
- SCTP_CHECK_AND_CAST(value, optval, uint32_t, optsize);
- if (*value > SCTP_SB_LIMIT_RCV(so)) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- break;
- }
- inp->partial_delivery_point = *value;
- break;
- }
- case SCTP_FRAGMENT_INTERLEAVE:
- /* not yet until we re-write sctp_recvmsg() */
- {
- uint32_t *level;
- SCTP_CHECK_AND_CAST(level, optval, uint32_t, optsize);
- if (*level == SCTP_FRAG_LEVEL_2) {
- sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE);
- sctp_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS);
- } else if (*level == SCTP_FRAG_LEVEL_1) {
- sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE);
- sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS);
- } else if (*level == SCTP_FRAG_LEVEL_0) {
- sctp_feature_off(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE);
- sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- break;
- }
- case SCTP_INTERLEAVING_SUPPORTED:
- {
- struct sctp_assoc_value *av;
- SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
- SCTP_FIND_STCB(inp, stcb, av->assoc_id);
- if (stcb) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- (av->assoc_id == SCTP_FUTURE_ASSOC))) {
- SCTP_INP_WLOCK(inp);
- if (av->assoc_value == 0) {
- inp->idata_supported = 0;
- } else {
- if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE)) &&
- (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS))) {
- inp->idata_supported = 1;
- } else {
- /* Must have Frag interleave and stream interleave on */
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- }
- SCTP_INP_WUNLOCK(inp);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- }
- break;
- }
- case SCTP_CMT_ON_OFF:
- if (SCTP_BASE_SYSCTL(sctp_cmt_on_off)) {
- struct sctp_assoc_value *av;
- SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
- if (av->assoc_value > SCTP_CMT_MAX) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- break;
- }
- SCTP_FIND_STCB(inp, stcb, av->assoc_id);
- if (stcb) {
- stcb->asoc.sctp_cmt_on_off = av->assoc_value;
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- ((av->assoc_id == SCTP_FUTURE_ASSOC) ||
- (av->assoc_id == SCTP_ALL_ASSOC)))) {
- SCTP_INP_WLOCK(inp);
- inp->sctp_cmt_on_off = av->assoc_value;
- SCTP_INP_WUNLOCK(inp);
- }
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
- (av->assoc_id == SCTP_ALL_ASSOC))) {
- SCTP_INP_RLOCK(inp);
- LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
- SCTP_TCB_LOCK(stcb);
- stcb->asoc.sctp_cmt_on_off = av->assoc_value;
- SCTP_TCB_UNLOCK(stcb);
- }
- SCTP_INP_RUNLOCK(inp);
- }
- }
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
- error = ENOPROTOOPT;
- }
- break;
- case SCTP_PLUGGABLE_CC:
- {
- struct sctp_assoc_value *av;
- struct sctp_nets *net;
- SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
- if ((av->assoc_value != SCTP_CC_RFC2581) &&
- (av->assoc_value != SCTP_CC_HSTCP) &&
- (av->assoc_value != SCTP_CC_HTCP) &&
- (av->assoc_value != SCTP_CC_RTCC)) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- break;
- }
- SCTP_FIND_STCB(inp, stcb, av->assoc_id);
- if (stcb) {
- stcb->asoc.cc_functions = sctp_cc_functions[av->assoc_value];
- stcb->asoc.congestion_control_module = av->assoc_value;
- if (stcb->asoc.cc_functions.sctp_set_initial_cc_param != NULL) {
- TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
- stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net);
- }
- }
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- ((av->assoc_id == SCTP_FUTURE_ASSOC) ||
- (av->assoc_id == SCTP_ALL_ASSOC)))) {
- SCTP_INP_WLOCK(inp);
- inp->sctp_ep.sctp_default_cc_module = av->assoc_value;
- SCTP_INP_WUNLOCK(inp);
- }
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
- (av->assoc_id == SCTP_ALL_ASSOC))) {
- SCTP_INP_RLOCK(inp);
- LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
- SCTP_TCB_LOCK(stcb);
- stcb->asoc.cc_functions = sctp_cc_functions[av->assoc_value];
- stcb->asoc.congestion_control_module = av->assoc_value;
- if (stcb->asoc.cc_functions.sctp_set_initial_cc_param != NULL) {
- TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
- stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net);
- }
- }
- SCTP_TCB_UNLOCK(stcb);
- }
- SCTP_INP_RUNLOCK(inp);
- }
- }
- break;
- }
- case SCTP_CC_OPTION:
- {
- struct sctp_cc_option *cc_opt;
- SCTP_CHECK_AND_CAST(cc_opt, optval, struct sctp_cc_option, optsize);
- SCTP_FIND_STCB(inp, stcb, cc_opt->aid_value.assoc_id);
- if (stcb == NULL) {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- (cc_opt->aid_value.assoc_id == SCTP_CURRENT_ASSOC)) {
- SCTP_INP_RLOCK(inp);
- LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
- SCTP_TCB_LOCK(stcb);
- if (stcb->asoc.cc_functions.sctp_cwnd_socket_option) {
- (*stcb->asoc.cc_functions.sctp_cwnd_socket_option)(stcb, 1, cc_opt);
- }
- SCTP_TCB_UNLOCK(stcb);
- }
- SCTP_INP_RUNLOCK(inp);
- } else {
- error = EINVAL;
- }
- } else {
- if (stcb->asoc.cc_functions.sctp_cwnd_socket_option == NULL) {
- error = ENOTSUP;
- } else {
- error = (*stcb->asoc.cc_functions.sctp_cwnd_socket_option)(stcb, 1,
- cc_opt);
- }
- SCTP_TCB_UNLOCK(stcb);
- }
- break;
- }
- case SCTP_PLUGGABLE_SS:
- {
- struct sctp_assoc_value *av;
- SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
- if ((av->assoc_value != SCTP_SS_DEFAULT) &&
- (av->assoc_value != SCTP_SS_ROUND_ROBIN) &&
- (av->assoc_value != SCTP_SS_ROUND_ROBIN_PACKET) &&
- (av->assoc_value != SCTP_SS_PRIORITY) &&
- (av->assoc_value != SCTP_SS_FAIR_BANDWITH) &&
- (av->assoc_value != SCTP_SS_FIRST_COME)) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- break;
- }
- SCTP_FIND_STCB(inp, stcb, av->assoc_id);
- if (stcb) {
- stcb->asoc.ss_functions.sctp_ss_clear(stcb, &stcb->asoc, true);
- stcb->asoc.ss_functions = sctp_ss_functions[av->assoc_value];
- stcb->asoc.stream_scheduling_module = av->assoc_value;
- stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc);
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- ((av->assoc_id == SCTP_FUTURE_ASSOC) ||
- (av->assoc_id == SCTP_ALL_ASSOC)))) {
- SCTP_INP_WLOCK(inp);
- inp->sctp_ep.sctp_default_ss_module = av->assoc_value;
- SCTP_INP_WUNLOCK(inp);
- }
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
- (av->assoc_id == SCTP_ALL_ASSOC))) {
- SCTP_INP_RLOCK(inp);
- LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
- SCTP_TCB_LOCK(stcb);
- stcb->asoc.ss_functions.sctp_ss_clear(stcb, &stcb->asoc, true);
- stcb->asoc.ss_functions = sctp_ss_functions[av->assoc_value];
- stcb->asoc.stream_scheduling_module = av->assoc_value;
- stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc);
- SCTP_TCB_UNLOCK(stcb);
- }
- SCTP_INP_RUNLOCK(inp);
- }
- }
- break;
- }
- case SCTP_SS_VALUE:
- {
- struct sctp_stream_value *av;
- SCTP_CHECK_AND_CAST(av, optval, struct sctp_stream_value, optsize);
- SCTP_FIND_STCB(inp, stcb, av->assoc_id);
- if (stcb) {
- if ((av->stream_id >= stcb->asoc.streamoutcnt) ||
- (stcb->asoc.ss_functions.sctp_ss_set_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id],
- av->stream_value) < 0)) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- (av->assoc_id == SCTP_CURRENT_ASSOC)) {
- SCTP_INP_RLOCK(inp);
- LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
- SCTP_TCB_LOCK(stcb);
- if (av->stream_id < stcb->asoc.streamoutcnt) {
- stcb->asoc.ss_functions.sctp_ss_set_value(stcb,
- &stcb->asoc,
- &stcb->asoc.strmout[av->stream_id],
- av->stream_value);
- }
- SCTP_TCB_UNLOCK(stcb);
- }
- SCTP_INP_RUNLOCK(inp);
- } else {
- /* Can't set stream value without association */
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- }
- break;
- }
- case SCTP_CLR_STAT_LOG:
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
- error = EOPNOTSUPP;
- break;
- case SCTP_CONTEXT:
- {
- struct sctp_assoc_value *av;
- SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
- SCTP_FIND_STCB(inp, stcb, av->assoc_id);
- if (stcb) {
- stcb->asoc.context = av->assoc_value;
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- ((av->assoc_id == SCTP_FUTURE_ASSOC) ||
- (av->assoc_id == SCTP_ALL_ASSOC)))) {
- SCTP_INP_WLOCK(inp);
- inp->sctp_context = av->assoc_value;
- SCTP_INP_WUNLOCK(inp);
- }
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
- (av->assoc_id == SCTP_ALL_ASSOC))) {
- SCTP_INP_RLOCK(inp);
- LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
- SCTP_TCB_LOCK(stcb);
- stcb->asoc.context = av->assoc_value;
- SCTP_TCB_UNLOCK(stcb);
- }
- SCTP_INP_RUNLOCK(inp);
- }
- }
- break;
- }
- case SCTP_VRF_ID:
- {
- uint32_t *default_vrfid;
- #ifdef SCTP_MVRF
- int i;
- #endif
- SCTP_CHECK_AND_CAST(default_vrfid, optval, uint32_t, optsize);
- if (*default_vrfid > SCTP_MAX_VRF_ID) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- break;
- }
- #ifdef SCTP_MVRF
- for (i = 0; i < inp->num_vrfs; i++) {
- /* The VRF must be in the VRF list */
- if (*default_vrfid == inp->m_vrf_ids[i]) {
- SCTP_INP_WLOCK(inp);
- inp->def_vrf_id = *default_vrfid;
- SCTP_INP_WUNLOCK(inp);
- goto sctp_done;
- }
- }
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- #else
- inp->def_vrf_id = *default_vrfid;
- #endif
- #ifdef SCTP_MVRF
- sctp_done:
- #endif
- break;
- }
- case SCTP_DEL_VRF_ID:
- {
- #ifdef SCTP_MVRF
- uint32_t *del_vrfid;
- int i, fnd = 0;
- SCTP_CHECK_AND_CAST(del_vrfid, optval, uint32_t, optsize);
- if (*del_vrfid > SCTP_MAX_VRF_ID) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- break;
- }
- if (inp->num_vrfs == 1) {
- /* Can't delete last one */
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- break;
- }
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 0) {
- /* Can't add more once you are bound */
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- break;
- }
- SCTP_INP_WLOCK(inp);
- for (i = 0; i < inp->num_vrfs; i++) {
- if (*del_vrfid == inp->m_vrf_ids[i]) {
- fnd = 1;
- break;
- }
- }
- if (!fnd) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- break;
- }
- if (i != (inp->num_vrfs - 1)) {
- /* Take bottom one and move to this slot */
- inp->m_vrf_ids[i] = inp->m_vrf_ids[(inp->num_vrfs-1)];
- }
- if (*del_vrfid == inp->def_vrf_id) {
- /* Take the first one as the new default */
- inp->def_vrf_id = inp->m_vrf_ids[0];
- }
- /* Drop the number by one killing last one */
- inp->num_vrfs--;
- #else
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
- error = EOPNOTSUPP;
- #endif
- break;
- }
- case SCTP_ADD_VRF_ID:
- {
- #ifdef SCTP_MVRF
- uint32_t *add_vrfid;
- int i;
- SCTP_CHECK_AND_CAST(add_vrfid, optval, uint32_t, optsize);
- if (*add_vrfid > SCTP_MAX_VRF_ID) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- break;
- }
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 0) {
- /* Can't add more once you are bound */
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- break;
- }
- SCTP_INP_WLOCK(inp);
- /* Verify its not already here */
- for (i = 0; i < inp->num_vrfs; i++) {
- if (*add_vrfid == inp->m_vrf_ids[i]) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
- error = EALREADY;
- SCTP_INP_WUNLOCK(inp);
- break;
- }
- }
- if ((inp->num_vrfs + 1) > inp->vrf_size) {
- /* need to grow array */
- uint32_t *tarray;
- SCTP_MALLOC(tarray, uint32_t *,
- (sizeof(uint32_t) * (inp->vrf_size + SCTP_DEFAULT_VRF_SIZE)),
- SCTP_M_MVRF);
- if (tarray == NULL) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
- error = ENOMEM;
- SCTP_INP_WUNLOCK(inp);
- break;
- }
- memcpy(tarray, inp->m_vrf_ids, (sizeof(uint32_t) * inp->vrf_size));
- SCTP_FREE(inp->m_vrf_ids, SCTP_M_MVRF);
- inp->m_vrf_ids = tarray;
- inp->vrf_size += SCTP_DEFAULT_VRF_SIZE;
- }
- inp->m_vrf_ids[inp->num_vrfs] = *add_vrfid;
- inp->num_vrfs++;
- SCTP_INP_WUNLOCK(inp);
- #else
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
- error = EOPNOTSUPP;
- #endif
- break;
- }
- case SCTP_DELAYED_SACK:
- {
- struct sctp_sack_info *sack;
- SCTP_CHECK_AND_CAST(sack, optval, struct sctp_sack_info, optsize);
- SCTP_FIND_STCB(inp, stcb, sack->sack_assoc_id);
- if (sack->sack_delay) {
- if (sack->sack_delay > SCTP_MAX_SACK_DELAY) {
- error = EINVAL;
- if (stcb != NULL) {
- SCTP_TCB_UNLOCK(stcb);
- }
- break;
- }
- }
- if (stcb) {
- if (sack->sack_delay) {
- stcb->asoc.delayed_ack = sack->sack_delay;
- }
- if (sack->sack_freq) {
- stcb->asoc.sack_freq = sack->sack_freq;
- }
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- ((sack->sack_assoc_id == SCTP_FUTURE_ASSOC) ||
- (sack->sack_assoc_id == SCTP_ALL_ASSOC)))) {
- SCTP_INP_WLOCK(inp);
- if (sack->sack_delay) {
- inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV] = sctp_msecs_to_ticks(sack->sack_delay);
- }
- if (sack->sack_freq) {
- inp->sctp_ep.sctp_sack_freq = sack->sack_freq;
- }
- SCTP_INP_WUNLOCK(inp);
- }
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- ((sack->sack_assoc_id == SCTP_CURRENT_ASSOC) ||
- (sack->sack_assoc_id == SCTP_ALL_ASSOC))) {
- SCTP_INP_RLOCK(inp);
- LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
- SCTP_TCB_LOCK(stcb);
- if (sack->sack_delay) {
- stcb->asoc.delayed_ack = sack->sack_delay;
- }
- if (sack->sack_freq) {
- stcb->asoc.sack_freq = sack->sack_freq;
- }
- SCTP_TCB_UNLOCK(stcb);
- }
- SCTP_INP_RUNLOCK(inp);
- }
- }
- break;
- }
- case SCTP_AUTH_CHUNK:
- {
- struct sctp_authchunk *sauth;
- SCTP_CHECK_AND_CAST(sauth, optval, struct sctp_authchunk, optsize);
- SCTP_INP_WLOCK(inp);
- if (sctp_auth_add_chunk(sauth->sauth_chunk, inp->sctp_ep.local_auth_chunks)) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- } else {
- inp->auth_supported = 1;
- }
- SCTP_INP_WUNLOCK(inp);
- break;
- }
- case SCTP_AUTH_KEY:
- {
- struct sctp_authkey *sca;
- struct sctp_keyhead *shared_keys;
- sctp_sharedkey_t *shared_key;
- sctp_key_t *key = NULL;
- size_t size;
- SCTP_CHECK_AND_CAST(sca, optval, struct sctp_authkey, optsize);
- if (sca->sca_keylength == 0) {
- size = optsize - sizeof(struct sctp_authkey);
- } else {
- if (sca->sca_keylength + sizeof(struct sctp_authkey) <= optsize) {
- size = sca->sca_keylength;
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- break;
- }
- }
- SCTP_FIND_STCB(inp, stcb, sca->sca_assoc_id);
- if (stcb) {
- shared_keys = &stcb->asoc.shared_keys;
- /* clear the cached keys for this key id */
- sctp_clear_cachedkeys(stcb, sca->sca_keynumber);
- /*
- * create the new shared key and
- * insert/replace it
- */
- if (size > 0) {
- key = sctp_set_key(sca->sca_key, (uint32_t) size);
- if (key == NULL) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
- error = ENOMEM;
- SCTP_TCB_UNLOCK(stcb);
- break;
- }
- }
- shared_key = sctp_alloc_sharedkey();
- if (shared_key == NULL) {
- sctp_free_key(key);
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
- error = ENOMEM;
- SCTP_TCB_UNLOCK(stcb);
- break;
- }
- shared_key->key = key;
- shared_key->keyid = sca->sca_keynumber;
- error = sctp_insert_sharedkey(shared_keys, shared_key);
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- ((sca->sca_assoc_id == SCTP_FUTURE_ASSOC) ||
- (sca->sca_assoc_id == SCTP_ALL_ASSOC)))) {
- SCTP_INP_WLOCK(inp);
- shared_keys = &inp->sctp_ep.shared_keys;
- /*
- * clear the cached keys on all assocs for
- * this key id
- */
- sctp_clear_cachedkeys_ep(inp, sca->sca_keynumber);
- /*
- * create the new shared key and
- * insert/replace it
- */
- if (size > 0) {
- key = sctp_set_key(sca->sca_key, (uint32_t) size);
- if (key == NULL) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
- error = ENOMEM;
- SCTP_INP_WUNLOCK(inp);
- break;
- }
- }
- shared_key = sctp_alloc_sharedkey();
- if (shared_key == NULL) {
- sctp_free_key(key);
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
- error = ENOMEM;
- SCTP_INP_WUNLOCK(inp);
- break;
- }
- shared_key->key = key;
- shared_key->keyid = sca->sca_keynumber;
- error = sctp_insert_sharedkey(shared_keys, shared_key);
- SCTP_INP_WUNLOCK(inp);
- }
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- ((sca->sca_assoc_id == SCTP_CURRENT_ASSOC) ||
- (sca->sca_assoc_id == SCTP_ALL_ASSOC))) {
- SCTP_INP_RLOCK(inp);
- LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
- SCTP_TCB_LOCK(stcb);
- shared_keys = &stcb->asoc.shared_keys;
- /* clear the cached keys for this key id */
- sctp_clear_cachedkeys(stcb, sca->sca_keynumber);
- /*
- * create the new shared key and
- * insert/replace it
- */
- if (size > 0) {
- key = sctp_set_key(sca->sca_key, (uint32_t) size);
- if (key == NULL) {
- SCTP_TCB_UNLOCK(stcb);
- continue;
- }
- }
- shared_key = sctp_alloc_sharedkey();
- if (shared_key == NULL) {
- sctp_free_key(key);
- SCTP_TCB_UNLOCK(stcb);
- continue;
- }
- shared_key->key = key;
- shared_key->keyid = sca->sca_keynumber;
- error = sctp_insert_sharedkey(shared_keys, shared_key);
- SCTP_TCB_UNLOCK(stcb);
- }
- SCTP_INP_RUNLOCK(inp);
- }
- }
- break;
- }
- case SCTP_HMAC_IDENT:
- {
- struct sctp_hmacalgo *shmac;
- sctp_hmaclist_t *hmaclist;
- uint16_t hmacid;
- uint32_t i;
- SCTP_CHECK_AND_CAST(shmac, optval, struct sctp_hmacalgo, optsize);
- if ((optsize < sizeof(struct sctp_hmacalgo) + shmac->shmac_number_of_idents * sizeof(uint16_t)) ||
- (shmac->shmac_number_of_idents > 0xffff)) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- break;
- }
- hmaclist = sctp_alloc_hmaclist((uint16_t)shmac->shmac_number_of_idents);
- if (hmaclist == NULL) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
- error = ENOMEM;
- break;
- }
- for (i = 0; i < shmac->shmac_number_of_idents; i++) {
- hmacid = shmac->shmac_idents[i];
- if (sctp_auth_add_hmacid(hmaclist, hmacid)) {
- /* invalid HMACs were found */;
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- sctp_free_hmaclist(hmaclist);
- goto sctp_set_hmac_done;
- }
- }
- for (i = 0; i < hmaclist->num_algo; i++) {
- if (hmaclist->hmac[i] == SCTP_AUTH_HMAC_ID_SHA1) {
- /* already in list */
- break;
- }
- }
- if (i == hmaclist->num_algo) {
- /* not found in list */
- sctp_free_hmaclist(hmaclist);
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- break;
- }
- /* set it on the endpoint */
- SCTP_INP_WLOCK(inp);
- if (inp->sctp_ep.local_hmacs)
- sctp_free_hmaclist(inp->sctp_ep.local_hmacs);
- inp->sctp_ep.local_hmacs = hmaclist;
- SCTP_INP_WUNLOCK(inp);
- sctp_set_hmac_done:
- break;
- }
- case SCTP_AUTH_ACTIVE_KEY:
- {
- struct sctp_authkeyid *scact;
- SCTP_CHECK_AND_CAST(scact, optval, struct sctp_authkeyid, optsize);
- SCTP_FIND_STCB(inp, stcb, scact->scact_assoc_id);
- /* set the active key on the right place */
- if (stcb) {
- /* set the active key on the assoc */
- if (sctp_auth_setactivekey(stcb,
- scact->scact_keynumber)) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL,
- SCTP_FROM_SCTP_USRREQ,
- EINVAL);
- error = EINVAL;
- }
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- ((scact->scact_assoc_id == SCTP_FUTURE_ASSOC) ||
- (scact->scact_assoc_id == SCTP_ALL_ASSOC)))) {
- SCTP_INP_WLOCK(inp);
- if (sctp_auth_setactivekey_ep(inp, scact->scact_keynumber)) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- SCTP_INP_WUNLOCK(inp);
- }
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- ((scact->scact_assoc_id == SCTP_CURRENT_ASSOC) ||
- (scact->scact_assoc_id == SCTP_ALL_ASSOC))) {
- SCTP_INP_RLOCK(inp);
- LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
- SCTP_TCB_LOCK(stcb);
- sctp_auth_setactivekey(stcb, scact->scact_keynumber);
- SCTP_TCB_UNLOCK(stcb);
- }
- SCTP_INP_RUNLOCK(inp);
- }
- }
- break;
- }
- case SCTP_AUTH_DELETE_KEY:
- {
- struct sctp_authkeyid *scdel;
- SCTP_CHECK_AND_CAST(scdel, optval, struct sctp_authkeyid, optsize);
- SCTP_FIND_STCB(inp, stcb, scdel->scact_assoc_id);
- /* delete the key from the right place */
- if (stcb) {
- if (sctp_delete_sharedkey(stcb, scdel->scact_keynumber)) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- ((scdel->scact_assoc_id == SCTP_FUTURE_ASSOC) ||
- (scdel->scact_assoc_id == SCTP_ALL_ASSOC)))) {
- SCTP_INP_WLOCK(inp);
- if (sctp_delete_sharedkey_ep(inp, scdel->scact_keynumber)) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- SCTP_INP_WUNLOCK(inp);
- }
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- ((scdel->scact_assoc_id == SCTP_CURRENT_ASSOC) ||
- (scdel->scact_assoc_id == SCTP_ALL_ASSOC))) {
- SCTP_INP_RLOCK(inp);
- LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
- SCTP_TCB_LOCK(stcb);
- sctp_delete_sharedkey(stcb, scdel->scact_keynumber);
- SCTP_TCB_UNLOCK(stcb);
- }
- SCTP_INP_RUNLOCK(inp);
- }
- }
- break;
- }
- case SCTP_AUTH_DEACTIVATE_KEY:
- {
- struct sctp_authkeyid *keyid;
- SCTP_CHECK_AND_CAST(keyid, optval, struct sctp_authkeyid, optsize);
- SCTP_FIND_STCB(inp, stcb, keyid->scact_assoc_id);
- /* deactivate the key from the right place */
- if (stcb) {
- if (sctp_deact_sharedkey(stcb, keyid->scact_keynumber)) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- ((keyid->scact_assoc_id == SCTP_FUTURE_ASSOC) ||
- (keyid->scact_assoc_id == SCTP_ALL_ASSOC)))) {
- SCTP_INP_WLOCK(inp);
- if (sctp_deact_sharedkey_ep(inp, keyid->scact_keynumber)) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- SCTP_INP_WUNLOCK(inp);
- }
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- ((keyid->scact_assoc_id == SCTP_CURRENT_ASSOC) ||
- (keyid->scact_assoc_id == SCTP_ALL_ASSOC))) {
- SCTP_INP_RLOCK(inp);
- LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
- SCTP_TCB_LOCK(stcb);
- sctp_deact_sharedkey(stcb, keyid->scact_keynumber);
- SCTP_TCB_UNLOCK(stcb);
- }
- SCTP_INP_RUNLOCK(inp);
- }
- }
- break;
- }
- case SCTP_ENABLE_STREAM_RESET:
- {
- struct sctp_assoc_value *av;
- SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
- if (av->assoc_value & (~SCTP_ENABLE_VALUE_MASK)) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- break;
- }
- SCTP_FIND_STCB(inp, stcb, av->assoc_id);
- if (stcb) {
- stcb->asoc.local_strreset_support = (uint8_t)av->assoc_value;
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- ((av->assoc_id == SCTP_FUTURE_ASSOC) ||
- (av->assoc_id == SCTP_ALL_ASSOC)))) {
- SCTP_INP_WLOCK(inp);
- inp->local_strreset_support = (uint8_t)av->assoc_value;
- SCTP_INP_WUNLOCK(inp);
- }
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
- (av->assoc_id == SCTP_ALL_ASSOC))) {
- SCTP_INP_RLOCK(inp);
- LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
- SCTP_TCB_LOCK(stcb);
- stcb->asoc.local_strreset_support = (uint8_t)av->assoc_value;
- SCTP_TCB_UNLOCK(stcb);
- }
- SCTP_INP_RUNLOCK(inp);
- }
- }
- break;
- }
- case SCTP_RESET_STREAMS:
- {
- struct sctp_reset_streams *strrst;
- int i, send_out = 0;
- int send_in = 0;
- SCTP_CHECK_AND_CAST(strrst, optval, struct sctp_reset_streams, optsize);
- SCTP_FIND_STCB(inp, stcb, strrst->srs_assoc_id);
- if (stcb == NULL) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
- error = ENOENT;
- break;
- }
- if (stcb->asoc.reconfig_supported == 0) {
- /*
- * Peer does not support the chunk type.
- */
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
- error = EOPNOTSUPP;
- SCTP_TCB_UNLOCK(stcb);
- break;
- }
- if (SCTP_GET_STATE(stcb) != SCTP_STATE_OPEN) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- SCTP_TCB_UNLOCK(stcb);
- break;
- }
- if (sizeof(struct sctp_reset_streams) +
- strrst->srs_number_streams * sizeof(uint16_t) > optsize) {
- error = EINVAL;
- SCTP_TCB_UNLOCK(stcb);
- break;
- }
- if (strrst->srs_flags & SCTP_STREAM_RESET_INCOMING) {
- send_in = 1;
- if (stcb->asoc.stream_reset_outstanding) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
- error = EALREADY;
- SCTP_TCB_UNLOCK(stcb);
- break;
- }
- }
- if (strrst->srs_flags & SCTP_STREAM_RESET_OUTGOING) {
- send_out = 1;
- }
- if ((strrst->srs_number_streams > SCTP_MAX_STREAMS_AT_ONCE_RESET) && send_in) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
- error = ENOMEM;
- SCTP_TCB_UNLOCK(stcb);
- break;
- }
- if ((send_in == 0) && (send_out == 0)) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- SCTP_TCB_UNLOCK(stcb);
- break;
- }
- for (i = 0; i < strrst->srs_number_streams; i++) {
- if ((send_in) &&
- (strrst->srs_stream_list[i] >= stcb->asoc.streamincnt)) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- break;
- }
- if ((send_out) &&
- (strrst->srs_stream_list[i] >= stcb->asoc.streamoutcnt)) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- break;
- }
- }
- if (error) {
- SCTP_TCB_UNLOCK(stcb);
- break;
- }
- if (send_out) {
- int cnt;
- uint16_t strm;
- if (strrst->srs_number_streams) {
- for (i = 0, cnt = 0; i < strrst->srs_number_streams; i++) {
- strm = strrst->srs_stream_list[i];
- if (stcb->asoc.strmout[strm].state == SCTP_STREAM_OPEN) {
- stcb->asoc.strmout[strm].state = SCTP_STREAM_RESET_PENDING;
- cnt++;
- }
- }
- } else {
- /* Its all */
- for (i = 0, cnt = 0; i < stcb->asoc.streamoutcnt; i++) {
- if (stcb->asoc.strmout[i].state == SCTP_STREAM_OPEN) {
- stcb->asoc.strmout[i].state = SCTP_STREAM_RESET_PENDING;
- cnt++;
- }
- }
- }
- }
- if (send_in) {
- error = sctp_send_str_reset_req(stcb, strrst->srs_number_streams,
- strrst->srs_stream_list,
- send_in, 0, 0, 0, 0, 0);
- } else {
- error = sctp_send_stream_reset_out_if_possible(stcb, SCTP_SO_LOCKED);
- }
- if (error == 0) {
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED);
- } else {
- /*
- * For outgoing streams don't report any problems in
- * sending the request to the application.
- * XXX: Double check resetting incoming streams.
- */
- error = 0;
- }
- SCTP_TCB_UNLOCK(stcb);
- break;
- }
- case SCTP_ADD_STREAMS:
- {
- struct sctp_add_streams *stradd;
- uint8_t addstream = 0;
- uint16_t add_o_strmcnt = 0;
- uint16_t add_i_strmcnt = 0;
- SCTP_CHECK_AND_CAST(stradd, optval, struct sctp_add_streams, optsize);
- SCTP_FIND_STCB(inp, stcb, stradd->sas_assoc_id);
- if (stcb == NULL) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
- error = ENOENT;
- break;
- }
- if (stcb->asoc.reconfig_supported == 0) {
- /*
- * Peer does not support the chunk type.
- */
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
- error = EOPNOTSUPP;
- SCTP_TCB_UNLOCK(stcb);
- break;
- }
- if (SCTP_GET_STATE(stcb) != SCTP_STATE_OPEN) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- SCTP_TCB_UNLOCK(stcb);
- break;
- }
- if (stcb->asoc.stream_reset_outstanding) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
- error = EALREADY;
- SCTP_TCB_UNLOCK(stcb);
- break;
- }
- if ((stradd->sas_outstrms == 0) &&
- (stradd->sas_instrms == 0)) {
- error = EINVAL;
- goto skip_stuff;
- }
- if (stradd->sas_outstrms) {
- addstream = 1;
- /* We allocate here */
- add_o_strmcnt = stradd->sas_outstrms;
- if ((((int)add_o_strmcnt) + ((int)stcb->asoc.streamoutcnt)) > 0x0000ffff) {
- /* You can't have more than 64k */
- error = EINVAL;
- goto skip_stuff;
- }
- }
- if (stradd->sas_instrms) {
- int cnt;
- addstream |= 2;
- /* We allocate inside sctp_send_str_reset_req() */
- add_i_strmcnt = stradd->sas_instrms;
- cnt = add_i_strmcnt;
- cnt += stcb->asoc.streamincnt;
- if (cnt > 0x0000ffff) {
- /* You can't have more than 64k */
- error = EINVAL;
- goto skip_stuff;
- }
- if (cnt > (int)stcb->asoc.max_inbound_streams) {
- /* More than you are allowed */
- error = EINVAL;
- goto skip_stuff;
- }
- }
- error = sctp_send_str_reset_req(stcb, 0, NULL, 0, 0, addstream, add_o_strmcnt, add_i_strmcnt, 0);
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED);
- skip_stuff:
- SCTP_TCB_UNLOCK(stcb);
- break;
- }
- case SCTP_RESET_ASSOC:
- {
- int i;
- uint32_t *value;
- SCTP_CHECK_AND_CAST(value, optval, uint32_t, optsize);
- SCTP_FIND_STCB(inp, stcb, (sctp_assoc_t) *value);
- if (stcb == NULL) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
- error = ENOENT;
- break;
- }
- if (stcb->asoc.reconfig_supported == 0) {
- /*
- * Peer does not support the chunk type.
- */
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
- error = EOPNOTSUPP;
- SCTP_TCB_UNLOCK(stcb);
- break;
- }
- if (SCTP_GET_STATE(stcb) != SCTP_STATE_OPEN) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- SCTP_TCB_UNLOCK(stcb);
- break;
- }
- if (stcb->asoc.stream_reset_outstanding) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
- error = EALREADY;
- SCTP_TCB_UNLOCK(stcb);
- break;
- }
- /* Is there any data pending in the send or sent queues? */
- if (!TAILQ_EMPTY(&stcb->asoc.send_queue) ||
- !TAILQ_EMPTY(&stcb->asoc.sent_queue)) {
- busy_out:
- error = EBUSY;
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
- SCTP_TCB_UNLOCK(stcb);
- break;
- }
- /* Do any streams have data queued? */
- for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
- if (!TAILQ_EMPTY(&stcb->asoc.strmout[i].outqueue)) {
- goto busy_out;
- }
- }
- error = sctp_send_str_reset_req(stcb, 0, NULL, 0, 1, 0, 0, 0, 0);
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED);
- SCTP_TCB_UNLOCK(stcb);
- break;
- }
- case SCTP_CONNECT_X:
- if (optsize < (sizeof(int) + sizeof(struct sockaddr_in))) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- break;
- }
- error = sctp_do_connect_x(so, inp, optval, optsize, p, 0);
- break;
- case SCTP_CONNECT_X_DELAYED:
- if (optsize < (sizeof(int) + sizeof(struct sockaddr_in))) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- break;
- }
- error = sctp_do_connect_x(so, inp, optval, optsize, p, 1);
- break;
- case SCTP_CONNECT_X_COMPLETE:
- {
- struct sockaddr *sa;
- /* FIXME MT: check correct? */
- SCTP_CHECK_AND_CAST(sa, optval, struct sockaddr, optsize);
- /* find tcb */
- if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
- SCTP_INP_RLOCK(inp);
- stcb = LIST_FIRST(&inp->sctp_asoc_list);
- if (stcb) {
- SCTP_TCB_LOCK(stcb);
- }
- SCTP_INP_RUNLOCK(inp);
- } else {
- /* We increment here since sctp_findassociation_ep_addr() wil
- * do a decrement if it finds the stcb as long as the locked
- * tcb (last argument) is NOT a TCB.. aka NULL.
- */
- SCTP_INP_INCR_REF(inp);
- stcb = sctp_findassociation_ep_addr(&inp, sa, NULL, NULL, NULL);
- if (stcb == NULL) {
- SCTP_INP_DECR_REF(inp);
- }
- }
- if (stcb == NULL) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
- error = ENOENT;
- break;
- }
- if (stcb->asoc.delayed_connection == 1) {
- stcb->asoc.delayed_connection = 0;
- (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
- sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb,
- stcb->asoc.primary_destination,
- SCTP_FROM_SCTP_USRREQ + SCTP_LOC_8);
- sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
- } else {
- /*
- * already expired or did not use delayed
- * connectx
- */
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
- error = EALREADY;
- }
- SCTP_TCB_UNLOCK(stcb);
- break;
- }
- case SCTP_MAX_BURST:
- {
- struct sctp_assoc_value *av;
- SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
- SCTP_FIND_STCB(inp, stcb, av->assoc_id);
- if (stcb) {
- stcb->asoc.max_burst = av->assoc_value;
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- ((av->assoc_id == SCTP_FUTURE_ASSOC) ||
- (av->assoc_id == SCTP_ALL_ASSOC)))) {
- SCTP_INP_WLOCK(inp);
- inp->sctp_ep.max_burst = av->assoc_value;
- SCTP_INP_WUNLOCK(inp);
- }
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
- (av->assoc_id == SCTP_ALL_ASSOC))) {
- SCTP_INP_RLOCK(inp);
- LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
- SCTP_TCB_LOCK(stcb);
- stcb->asoc.max_burst = av->assoc_value;
- SCTP_TCB_UNLOCK(stcb);
- }
- SCTP_INP_RUNLOCK(inp);
- }
- }
- break;
- }
- case SCTP_MAXSEG:
- {
- struct sctp_assoc_value *av;
- SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
- SCTP_FIND_STCB(inp, stcb, av->assoc_id);
- if (stcb) {
- stcb->asoc.sctp_frag_point = av->assoc_value;
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- (av->assoc_id == SCTP_FUTURE_ASSOC))) {
- SCTP_INP_WLOCK(inp);
- inp->sctp_frag_point = av->assoc_value;
- SCTP_INP_WUNLOCK(inp);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- }
- break;
- }
- case SCTP_EVENTS:
- {
- struct sctp_event_subscribe *events;
- SCTP_CHECK_AND_CAST(events, optval, struct sctp_event_subscribe, optsize);
- SCTP_INP_WLOCK(inp);
- if (events->sctp_data_io_event) {
- sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT);
- } else {
- sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT);
- }
- if (events->sctp_association_event) {
- sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT);
- } else {
- sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT);
- }
- if (events->sctp_address_event) {
- sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVPADDREVNT);
- } else {
- sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVPADDREVNT);
- }
- if (events->sctp_send_failure_event) {
- sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT);
- } else {
- sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT);
- }
- if (events->sctp_peer_error_event) {
- sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVPEERERR);
- } else {
- sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVPEERERR);
- }
- if (events->sctp_shutdown_event) {
- sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT);
- } else {
- sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT);
- }
- if (events->sctp_partial_delivery_event) {
- sctp_feature_on(inp, SCTP_PCB_FLAGS_PDAPIEVNT);
- } else {
- sctp_feature_off(inp, SCTP_PCB_FLAGS_PDAPIEVNT);
- }
- if (events->sctp_adaptation_layer_event) {
- sctp_feature_on(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT);
- } else {
- sctp_feature_off(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT);
- }
- if (events->sctp_authentication_event) {
- sctp_feature_on(inp, SCTP_PCB_FLAGS_AUTHEVNT);
- } else {
- sctp_feature_off(inp, SCTP_PCB_FLAGS_AUTHEVNT);
- }
- if (events->sctp_sender_dry_event) {
- sctp_feature_on(inp, SCTP_PCB_FLAGS_DRYEVNT);
- } else {
- sctp_feature_off(inp, SCTP_PCB_FLAGS_DRYEVNT);
- }
- if (events->sctp_stream_reset_event) {
- sctp_feature_on(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT);
- } else {
- sctp_feature_off(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT);
- }
- LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
- SCTP_TCB_LOCK(stcb);
- if (events->sctp_association_event) {
- sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVASSOCEVNT);
- } else {
- sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVASSOCEVNT);
- }
- if (events->sctp_address_event) {
- sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVPADDREVNT);
- } else {
- sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVPADDREVNT);
- }
- if (events->sctp_send_failure_event) {
- sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT);
- } else {
- sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT);
- }
- if (events->sctp_peer_error_event) {
- sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVPEERERR);
- } else {
- sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVPEERERR);
- }
- if (events->sctp_shutdown_event) {
- sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT);
- } else {
- sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT);
- }
- if (events->sctp_partial_delivery_event) {
- sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_PDAPIEVNT);
- } else {
- sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_PDAPIEVNT);
- }
- if (events->sctp_adaptation_layer_event) {
- sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_ADAPTATIONEVNT);
- } else {
- sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_ADAPTATIONEVNT);
- }
- if (events->sctp_authentication_event) {
- sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_AUTHEVNT);
- } else {
- sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_AUTHEVNT);
- }
- if (events->sctp_sender_dry_event) {
- sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_DRYEVNT);
- } else {
- sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_DRYEVNT);
- }
- if (events->sctp_stream_reset_event) {
- sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_STREAM_RESETEVNT);
- } else {
- sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_STREAM_RESETEVNT);
- }
- SCTP_TCB_UNLOCK(stcb);
- }
- /* Send up the sender dry event only for 1-to-1 style sockets. */
- if (events->sctp_sender_dry_event) {
- if (((inp->sctp_flags & (SCTP_PCB_FLAGS_TCPTYPE | SCTP_PCB_FLAGS_IN_TCPPOOL)) != 0) &&
- !SCTP_IS_LISTENING(inp)) {
- stcb = LIST_FIRST(&inp->sctp_asoc_list);
- if (stcb != NULL) {
- SCTP_TCB_LOCK(stcb);
- if (TAILQ_EMPTY(&stcb->asoc.send_queue) &&
- TAILQ_EMPTY(&stcb->asoc.sent_queue) &&
- (stcb->asoc.stream_queue_cnt == 0)) {
- sctp_ulp_notify(SCTP_NOTIFY_SENDER_DRY, stcb, 0, NULL, SCTP_SO_LOCKED);
- }
- SCTP_TCB_UNLOCK(stcb);
- }
- }
- }
- SCTP_INP_WUNLOCK(inp);
- break;
- }
- case SCTP_ADAPTATION_LAYER:
- {
- struct sctp_setadaptation *adap_bits;
- SCTP_CHECK_AND_CAST(adap_bits, optval, struct sctp_setadaptation, optsize);
- SCTP_INP_WLOCK(inp);
- inp->sctp_ep.adaptation_layer_indicator = adap_bits->ssb_adaptation_ind;
- inp->sctp_ep.adaptation_layer_indicator_provided = 1;
- SCTP_INP_WUNLOCK(inp);
- break;
- }
- #ifdef SCTP_DEBUG
- case SCTP_SET_INITIAL_DBG_SEQ:
- {
- uint32_t *vvv;
- SCTP_CHECK_AND_CAST(vvv, optval, uint32_t, optsize);
- SCTP_INP_WLOCK(inp);
- inp->sctp_ep.initial_sequence_debug = *vvv;
- SCTP_INP_WUNLOCK(inp);
- break;
- }
- #endif
- case SCTP_DEFAULT_SEND_PARAM:
- {
- struct sctp_sndrcvinfo *s_info;
- SCTP_CHECK_AND_CAST(s_info, optval, struct sctp_sndrcvinfo, optsize);
- SCTP_FIND_STCB(inp, stcb, s_info->sinfo_assoc_id);
- if (stcb) {
- if (s_info->sinfo_stream < stcb->asoc.streamoutcnt) {
- memcpy(&stcb->asoc.def_send, s_info, min(optsize, sizeof(stcb->asoc.def_send)));
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- ((s_info->sinfo_assoc_id == SCTP_FUTURE_ASSOC) ||
- (s_info->sinfo_assoc_id == SCTP_ALL_ASSOC)))) {
- SCTP_INP_WLOCK(inp);
- memcpy(&inp->def_send, s_info, min(optsize, sizeof(inp->def_send)));
- SCTP_INP_WUNLOCK(inp);
- }
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- ((s_info->sinfo_assoc_id == SCTP_CURRENT_ASSOC) ||
- (s_info->sinfo_assoc_id == SCTP_ALL_ASSOC))) {
- SCTP_INP_RLOCK(inp);
- LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
- SCTP_TCB_LOCK(stcb);
- if (s_info->sinfo_stream < stcb->asoc.streamoutcnt) {
- memcpy(&stcb->asoc.def_send, s_info, min(optsize, sizeof(stcb->asoc.def_send)));
- }
- SCTP_TCB_UNLOCK(stcb);
- }
- SCTP_INP_RUNLOCK(inp);
- }
- }
- break;
- }
- case SCTP_PEER_ADDR_PARAMS:
- {
- struct sctp_paddrparams *paddrp;
- struct sctp_nets *net;
- struct sockaddr *addr;
- #if defined(INET) && defined(INET6)
- struct sockaddr_in sin_store;
- #endif
- SCTP_CHECK_AND_CAST(paddrp, optval, struct sctp_paddrparams, optsize);
- SCTP_FIND_STCB(inp, stcb, paddrp->spp_assoc_id);
- #if defined(INET) && defined(INET6)
- if (paddrp->spp_address.ss_family == AF_INET6) {
- struct sockaddr_in6 *sin6;
- sin6 = (struct sockaddr_in6 *)&paddrp->spp_address;
- if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
- in6_sin6_2_sin(&sin_store, sin6);
- addr = (struct sockaddr *)&sin_store;
- } else {
- addr = (struct sockaddr *)&paddrp->spp_address;
- }
- } else {
- addr = (struct sockaddr *)&paddrp->spp_address;
- }
- #else
- addr = (struct sockaddr *)&paddrp->spp_address;
- #endif
- if (stcb != NULL) {
- net = sctp_findnet(stcb, addr);
- } else {
- /* We increment here since sctp_findassociation_ep_addr() wil
- * do a decrement if it finds the stcb as long as the locked
- * tcb (last argument) is NOT a TCB.. aka NULL.
- */
- net = NULL;
- SCTP_INP_INCR_REF(inp);
- stcb = sctp_findassociation_ep_addr(&inp, addr,
- &net, NULL, NULL);
- if (stcb == NULL) {
- SCTP_INP_DECR_REF(inp);
- }
- }
- if ((stcb != NULL) && (net == NULL)) {
- #ifdef INET
- if (addr->sa_family == AF_INET) {
- struct sockaddr_in *sin;
- sin = (struct sockaddr_in *)addr;
- if (sin->sin_addr.s_addr != INADDR_ANY) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- SCTP_TCB_UNLOCK(stcb);
- error = EINVAL;
- break;
- }
- } else
- #endif
- #ifdef INET6
- if (addr->sa_family == AF_INET6) {
- struct sockaddr_in6 *sin6;
- sin6 = (struct sockaddr_in6 *)addr;
- if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- SCTP_TCB_UNLOCK(stcb);
- error = EINVAL;
- break;
- }
- } else
- #endif
- #if defined(__Userspace__)
- if (addr->sa_family == AF_CONN) {
- struct sockaddr_conn *sconn;
- sconn = (struct sockaddr_conn *)addr;
- if (sconn->sconn_addr != NULL) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- SCTP_TCB_UNLOCK(stcb);
- error = EINVAL;
- break;
- }
- } else
- #endif
- {
- error = EAFNOSUPPORT;
- SCTP_TCB_UNLOCK(stcb);
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
- break;
- }
- }
- /* sanity checks */
- if ((paddrp->spp_flags & SPP_HB_ENABLE) && (paddrp->spp_flags & SPP_HB_DISABLE)) {
- if (stcb)
- SCTP_TCB_UNLOCK(stcb);
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- return (EINVAL);
- }
- if ((paddrp->spp_flags & SPP_PMTUD_ENABLE) && (paddrp->spp_flags & SPP_PMTUD_DISABLE)) {
- if (stcb)
- SCTP_TCB_UNLOCK(stcb);
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- return (EINVAL);
- }
- if ((paddrp->spp_flags & SPP_PMTUD_DISABLE) &&
- (paddrp->spp_pathmtu > 0) &&
- ((paddrp->spp_pathmtu < SCTP_SMALLEST_PMTU) ||
- (paddrp->spp_pathmtu > SCTP_LARGEST_PMTU))) {
- if (stcb)
- SCTP_TCB_UNLOCK(stcb);
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- return (EINVAL);
- }
- if (stcb != NULL) {
- /************************TCB SPECIFIC SET ******************/
- if (net != NULL) {
- /************************NET SPECIFIC SET ******************/
- if (paddrp->spp_flags & SPP_HB_DISABLE) {
- if (((net->dest_state & SCTP_ADDR_UNCONFIRMED) == 0) &&
- ((net->dest_state & SCTP_ADDR_NOHB) == 0)) {
- sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net,
- SCTP_FROM_SCTP_USRREQ + SCTP_LOC_9);
- }
- net->dest_state |= SCTP_ADDR_NOHB;
- }
- if (paddrp->spp_flags & SPP_HB_ENABLE) {
- if (paddrp->spp_hbinterval) {
- net->heart_beat_delay = paddrp->spp_hbinterval;
- } else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) {
- net->heart_beat_delay = 0;
- }
- sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net,
- SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10);
- sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
- net->dest_state &= ~SCTP_ADDR_NOHB;
- }
- if (paddrp->spp_flags & SPP_HB_DEMAND) {
- if (SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) {
- sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SOCKOPT, SCTP_SO_LOCKED);
- sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
- }
- }
- if (paddrp->spp_flags & SPP_PMTUD_DISABLE) {
- if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
- sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
- SCTP_FROM_SCTP_USRREQ + SCTP_LOC_11);
- }
- net->dest_state |= SCTP_ADDR_NO_PMTUD;
- if (paddrp->spp_pathmtu > 0) {
- net->mtu = paddrp->spp_pathmtu;
- switch (net->ro._l_addr.sa.sa_family) {
- #ifdef INET
- case AF_INET:
- net->mtu += SCTP_MIN_V4_OVERHEAD;
- break;
- #endif
- #ifdef INET6
- case AF_INET6:
- net->mtu += SCTP_MIN_OVERHEAD;
- break;
- #endif
- #if defined(__Userspace__)
- case AF_CONN:
- net->mtu += sizeof(struct sctphdr);
- break;
- #endif
- default:
- break;
- }
- if (net->mtu < stcb->asoc.smallest_mtu) {
- sctp_pathmtu_adjustment(stcb, net->mtu, true);
- }
- }
- }
- if (paddrp->spp_flags & SPP_PMTUD_ENABLE) {
- if (!SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
- sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
- }
- net->dest_state &= ~SCTP_ADDR_NO_PMTUD;
- }
- if (paddrp->spp_pathmaxrxt > 0) {
- if (net->dest_state & SCTP_ADDR_PF) {
- if (net->error_count > paddrp->spp_pathmaxrxt) {
- net->dest_state &= ~SCTP_ADDR_PF;
- }
- } else {
- if ((net->error_count <= paddrp->spp_pathmaxrxt) &&
- (net->error_count > net->pf_threshold)) {
- net->dest_state |= SCTP_ADDR_PF;
- sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
- sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT,
- stcb->sctp_ep, stcb, net,
- SCTP_FROM_SCTP_USRREQ + SCTP_LOC_12);
- sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
- }
- }
- if (net->dest_state & SCTP_ADDR_REACHABLE) {
- if (net->error_count > paddrp->spp_pathmaxrxt) {
- net->dest_state &= ~SCTP_ADDR_REACHABLE;
- sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED);
- }
- } else {
- if (net->error_count <= paddrp->spp_pathmaxrxt) {
- net->dest_state |= SCTP_ADDR_REACHABLE;
- sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED);
- }
- }
- net->failure_threshold = paddrp->spp_pathmaxrxt;
- }
- if (paddrp->spp_flags & SPP_DSCP) {
- net->dscp = paddrp->spp_dscp & 0xfc;
- net->dscp |= 0x01;
- }
- #ifdef INET6
- if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) {
- if (net->ro._l_addr.sa.sa_family == AF_INET6) {
- net->flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff;
- net->flowlabel |= 0x80000000;
- }
- }
- #endif
- } else {
- /************************ASSOC ONLY -- NO NET SPECIFIC SET ******************/
- if (paddrp->spp_pathmaxrxt > 0) {
- stcb->asoc.def_net_failure = paddrp->spp_pathmaxrxt;
- TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
- if (net->dest_state & SCTP_ADDR_PF) {
- if (net->error_count > paddrp->spp_pathmaxrxt) {
- net->dest_state &= ~SCTP_ADDR_PF;
- }
- } else {
- if ((net->error_count <= paddrp->spp_pathmaxrxt) &&
- (net->error_count > net->pf_threshold)) {
- net->dest_state |= SCTP_ADDR_PF;
- sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
- sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT,
- stcb->sctp_ep, stcb, net,
- SCTP_FROM_SCTP_USRREQ + SCTP_LOC_13);
- sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
- }
- }
- if (net->dest_state & SCTP_ADDR_REACHABLE) {
- if (net->error_count > paddrp->spp_pathmaxrxt) {
- net->dest_state &= ~SCTP_ADDR_REACHABLE;
- sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED);
- }
- } else {
- if (net->error_count <= paddrp->spp_pathmaxrxt) {
- net->dest_state |= SCTP_ADDR_REACHABLE;
- sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED);
- }
- }
- net->failure_threshold = paddrp->spp_pathmaxrxt;
- }
- }
- if (paddrp->spp_flags & SPP_HB_ENABLE) {
- if (paddrp->spp_hbinterval != 0) {
- stcb->asoc.heart_beat_delay = paddrp->spp_hbinterval;
- } else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) {
- stcb->asoc.heart_beat_delay = 0;
- }
- /* Turn back on the timer */
- TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
- if (paddrp->spp_hbinterval != 0) {
- net->heart_beat_delay = paddrp->spp_hbinterval;
- } else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) {
- net->heart_beat_delay = 0;
- }
- if (net->dest_state & SCTP_ADDR_NOHB) {
- net->dest_state &= ~SCTP_ADDR_NOHB;
- }
- sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net,
- SCTP_FROM_SCTP_USRREQ + SCTP_LOC_14);
- sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
- }
- sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
- }
- if (paddrp->spp_flags & SPP_HB_DISABLE) {
- TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
- if ((net->dest_state & SCTP_ADDR_NOHB) == 0) {
- net->dest_state |= SCTP_ADDR_NOHB;
- if ((net->dest_state & SCTP_ADDR_UNCONFIRMED) == 0) {
- sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT,
- inp, stcb, net,
- SCTP_FROM_SCTP_USRREQ + SCTP_LOC_15);
- }
- }
- }
- sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
- }
- if (paddrp->spp_flags & SPP_PMTUD_DISABLE) {
- TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
- if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
- sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
- SCTP_FROM_SCTP_USRREQ + SCTP_LOC_16);
- }
- net->dest_state |= SCTP_ADDR_NO_PMTUD;
- if (paddrp->spp_pathmtu > 0) {
- net->mtu = paddrp->spp_pathmtu;
- switch (net->ro._l_addr.sa.sa_family) {
- #ifdef INET
- case AF_INET:
- net->mtu += SCTP_MIN_V4_OVERHEAD;
- break;
- #endif
- #ifdef INET6
- case AF_INET6:
- net->mtu += SCTP_MIN_OVERHEAD;
- break;
- #endif
- #if defined(__Userspace__)
- case AF_CONN:
- net->mtu += sizeof(struct sctphdr);
- break;
- #endif
- default:
- break;
- }
- if (net->mtu < stcb->asoc.smallest_mtu) {
- sctp_pathmtu_adjustment(stcb, net->mtu, true);
- }
- }
- }
- if (paddrp->spp_pathmtu > 0) {
- stcb->asoc.default_mtu = paddrp->spp_pathmtu;
- }
- sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD);
- }
- if (paddrp->spp_flags & SPP_PMTUD_ENABLE) {
- TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
- if (!SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) {
- sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
- }
- net->dest_state &= ~SCTP_ADDR_NO_PMTUD;
- }
- stcb->asoc.default_mtu = 0;
- sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD);
- }
- if (paddrp->spp_flags & SPP_DSCP) {
- TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
- net->dscp = paddrp->spp_dscp & 0xfc;
- net->dscp |= 0x01;
- }
- stcb->asoc.default_dscp = paddrp->spp_dscp & 0xfc;
- stcb->asoc.default_dscp |= 0x01;
- }
- #ifdef INET6
- if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) {
- TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
- if (net->ro._l_addr.sa.sa_family == AF_INET6) {
- net->flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff;
- net->flowlabel |= 0x80000000;
- }
- }
- stcb->asoc.default_flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff;
- stcb->asoc.default_flowlabel |= 0x80000000;
- }
- #endif
- }
- SCTP_TCB_UNLOCK(stcb);
- } else {
- /************************NO TCB, SET TO default stuff ******************/
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- (paddrp->spp_assoc_id == SCTP_FUTURE_ASSOC))) {
- SCTP_INP_WLOCK(inp);
- /*
- * For the TOS/FLOWLABEL stuff you set it
- * with the options on the socket
- */
- if (paddrp->spp_pathmaxrxt > 0) {
- inp->sctp_ep.def_net_failure = paddrp->spp_pathmaxrxt;
- }
- if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO)
- inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = 0;
- else if (paddrp->spp_hbinterval != 0) {
- if (paddrp->spp_hbinterval > SCTP_MAX_HB_INTERVAL)
- paddrp->spp_hbinterval= SCTP_MAX_HB_INTERVAL;
- inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = sctp_msecs_to_ticks(paddrp->spp_hbinterval);
- }
- if (paddrp->spp_flags & SPP_HB_ENABLE) {
- if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) {
- inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = 0;
- } else if (paddrp->spp_hbinterval) {
- inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = sctp_msecs_to_ticks(paddrp->spp_hbinterval);
- }
- sctp_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
- } else if (paddrp->spp_flags & SPP_HB_DISABLE) {
- sctp_feature_on(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
- }
- if (paddrp->spp_flags & SPP_PMTUD_ENABLE) {
- inp->sctp_ep.default_mtu = 0;
- sctp_feature_off(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD);
- } else if (paddrp->spp_flags & SPP_PMTUD_DISABLE) {
- if (paddrp->spp_pathmtu > 0) {
- inp->sctp_ep.default_mtu = paddrp->spp_pathmtu;
- }
- sctp_feature_on(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD);
- }
- if (paddrp->spp_flags & SPP_DSCP) {
- inp->sctp_ep.default_dscp = paddrp->spp_dscp & 0xfc;
- inp->sctp_ep.default_dscp |= 0x01;
- }
- #ifdef INET6
- if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) {
- if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
- inp->sctp_ep.default_flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff;
- inp->sctp_ep.default_flowlabel |= 0x80000000;
- }
- }
- #endif
- SCTP_INP_WUNLOCK(inp);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- }
- break;
- }
- case SCTP_RTOINFO:
- {
- struct sctp_rtoinfo *srto;
- uint32_t new_init, new_min, new_max;
- SCTP_CHECK_AND_CAST(srto, optval, struct sctp_rtoinfo, optsize);
- SCTP_FIND_STCB(inp, stcb, srto->srto_assoc_id);
- if (stcb) {
- if (srto->srto_initial)
- new_init = srto->srto_initial;
- else
- new_init = stcb->asoc.initial_rto;
- if (srto->srto_max)
- new_max = srto->srto_max;
- else
- new_max = stcb->asoc.maxrto;
- if (srto->srto_min)
- new_min = srto->srto_min;
- else
- new_min = stcb->asoc.minrto;
- if ((new_min <= new_init) && (new_init <= new_max)) {
- stcb->asoc.initial_rto = new_init;
- stcb->asoc.maxrto = new_max;
- stcb->asoc.minrto = new_min;
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- (srto->srto_assoc_id == SCTP_FUTURE_ASSOC))) {
- SCTP_INP_WLOCK(inp);
- if (srto->srto_initial)
- new_init = srto->srto_initial;
- else
- new_init = inp->sctp_ep.initial_rto;
- if (srto->srto_max)
- new_max = srto->srto_max;
- else
- new_max = inp->sctp_ep.sctp_maxrto;
- if (srto->srto_min)
- new_min = srto->srto_min;
- else
- new_min = inp->sctp_ep.sctp_minrto;
- if ((new_min <= new_init) && (new_init <= new_max)) {
- inp->sctp_ep.initial_rto = new_init;
- inp->sctp_ep.sctp_maxrto = new_max;
- inp->sctp_ep.sctp_minrto = new_min;
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- SCTP_INP_WUNLOCK(inp);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- }
- break;
- }
- case SCTP_ASSOCINFO:
- {
- struct sctp_assocparams *sasoc;
- SCTP_CHECK_AND_CAST(sasoc, optval, struct sctp_assocparams, optsize);
- SCTP_FIND_STCB(inp, stcb, sasoc->sasoc_assoc_id);
- if (sasoc->sasoc_cookie_life > 0) {
- /* boundary check the cookie life */
- if (sasoc->sasoc_cookie_life < SCTP_MIN_COOKIE_LIFE) {
- sasoc->sasoc_cookie_life = SCTP_MIN_COOKIE_LIFE;
- }
- if (sasoc->sasoc_cookie_life > SCTP_MAX_COOKIE_LIFE) {
- sasoc->sasoc_cookie_life = SCTP_MAX_COOKIE_LIFE;
- }
- }
- if (stcb) {
- if (sasoc->sasoc_asocmaxrxt > 0) {
- stcb->asoc.max_send_times = sasoc->sasoc_asocmaxrxt;
- }
- if (sasoc->sasoc_cookie_life > 0) {
- stcb->asoc.cookie_life = sctp_msecs_to_ticks(sasoc->sasoc_cookie_life);
- }
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- (sasoc->sasoc_assoc_id == SCTP_FUTURE_ASSOC))) {
- SCTP_INP_WLOCK(inp);
- if (sasoc->sasoc_asocmaxrxt > 0) {
- inp->sctp_ep.max_send_times = sasoc->sasoc_asocmaxrxt;
- }
- if (sasoc->sasoc_cookie_life > 0) {
- inp->sctp_ep.def_cookie_life = sctp_msecs_to_ticks(sasoc->sasoc_cookie_life);
- }
- SCTP_INP_WUNLOCK(inp);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- }
- break;
- }
- case SCTP_INITMSG:
- {
- struct sctp_initmsg *sinit;
- SCTP_CHECK_AND_CAST(sinit, optval, struct sctp_initmsg, optsize);
- SCTP_INP_WLOCK(inp);
- if (sinit->sinit_num_ostreams)
- inp->sctp_ep.pre_open_stream_count = sinit->sinit_num_ostreams;
- if (sinit->sinit_max_instreams)
- inp->sctp_ep.max_open_streams_intome = sinit->sinit_max_instreams;
- if (sinit->sinit_max_attempts)
- inp->sctp_ep.max_init_times = sinit->sinit_max_attempts;
- if (sinit->sinit_max_init_timeo)
- inp->sctp_ep.initial_init_rto_max = sinit->sinit_max_init_timeo;
- SCTP_INP_WUNLOCK(inp);
- break;
- }
- case SCTP_PRIMARY_ADDR:
- {
- struct sctp_setprim *spa;
- struct sctp_nets *net;
- struct sockaddr *addr;
- #if defined(INET) && defined(INET6)
- struct sockaddr_in sin_store;
- #endif
- SCTP_CHECK_AND_CAST(spa, optval, struct sctp_setprim, optsize);
- SCTP_FIND_STCB(inp, stcb, spa->ssp_assoc_id);
- #if defined(INET) && defined(INET6)
- if (spa->ssp_addr.ss_family == AF_INET6) {
- struct sockaddr_in6 *sin6;
- sin6 = (struct sockaddr_in6 *)&spa->ssp_addr;
- if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
- in6_sin6_2_sin(&sin_store, sin6);
- addr = (struct sockaddr *)&sin_store;
- } else {
- addr = (struct sockaddr *)&spa->ssp_addr;
- }
- } else {
- addr = (struct sockaddr *)&spa->ssp_addr;
- }
- #else
- addr = (struct sockaddr *)&spa->ssp_addr;
- #endif
- if (stcb != NULL) {
- net = sctp_findnet(stcb, addr);
- } else {
- /* We increment here since sctp_findassociation_ep_addr() wil
- * do a decrement if it finds the stcb as long as the locked
- * tcb (last argument) is NOT a TCB.. aka NULL.
- */
- net = NULL;
- SCTP_INP_INCR_REF(inp);
- stcb = sctp_findassociation_ep_addr(&inp, addr,
- &net, NULL, NULL);
- if (stcb == NULL) {
- SCTP_INP_DECR_REF(inp);
- }
- }
- if ((stcb != NULL) && (net != NULL)) {
- if (net != stcb->asoc.primary_destination) {
- if ((net->dest_state & SCTP_ADDR_UNCONFIRMED) == 0) {
- /* Ok we need to set it */
- if (sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net) == 0) {
- if ((stcb->asoc.alternate) &&
- ((net->dest_state & SCTP_ADDR_PF) == 0) &&
- (net->dest_state & SCTP_ADDR_REACHABLE)) {
- sctp_free_remote_addr(stcb->asoc.alternate);
- stcb->asoc.alternate = NULL;
- }
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- }
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- if (stcb != NULL) {
- SCTP_TCB_UNLOCK(stcb);
- }
- break;
- }
- case SCTP_SET_DYNAMIC_PRIMARY:
- {
- union sctp_sockstore *ss;
- #ifdef SCTP_MVRF
- int i, fnd = 0;
- #endif
- #if !defined(_WIN32) && !defined(__Userspace__)
- #if defined(__APPLE__)
- struct proc *proc;
- #endif
- #if defined(__FreeBSD__)
- error = priv_check(curthread,
- PRIV_NETINET_RESERVEDPORT);
- #elif defined(__APPLE__)
- proc = (struct proc *)p;
- if (p) {
- error = suser(proc->p_ucred, &proc->p_acflag);
- } else {
- break;
- }
- #else
- error = suser(p, 0);
- #endif
- if (error)
- break;
- #endif
- SCTP_CHECK_AND_CAST(ss, optval, union sctp_sockstore, optsize);
- /* SUPER USER CHECK? */
- #ifdef SCTP_MVRF
- for (i = 0; i < inp->num_vrfs; i++) {
- if (vrf_id == inp->m_vrf_ids[i]) {
- fnd = 1;
- break;
- }
- }
- if (!fnd) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- break;
- }
- #endif
- error = sctp_dynamic_set_primary(&ss->sa, vrf_id);
- break;
- }
- case SCTP_SET_PEER_PRIMARY_ADDR:
- {
- struct sctp_setpeerprim *sspp;
- struct sockaddr *addr;
- #if defined(INET) && defined(INET6)
- struct sockaddr_in sin_store;
- #endif
- SCTP_CHECK_AND_CAST(sspp, optval, struct sctp_setpeerprim, optsize);
- SCTP_FIND_STCB(inp, stcb, sspp->sspp_assoc_id);
- if (stcb != NULL) {
- struct sctp_ifa *ifa;
- #if defined(INET) && defined(INET6)
- if (sspp->sspp_addr.ss_family == AF_INET6) {
- struct sockaddr_in6 *sin6;
- sin6 = (struct sockaddr_in6 *)&sspp->sspp_addr;
- if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
- in6_sin6_2_sin(&sin_store, sin6);
- addr = (struct sockaddr *)&sin_store;
- } else {
- addr = (struct sockaddr *)&sspp->sspp_addr;
- }
- } else {
- addr = (struct sockaddr *)&sspp->sspp_addr;
- }
- #else
- addr = (struct sockaddr *)&sspp->sspp_addr;
- #endif
- ifa = sctp_find_ifa_by_addr(addr, stcb->asoc.vrf_id, SCTP_ADDR_NOT_LOCKED);
- if (ifa == NULL) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- goto out_of_it;
- }
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) {
- /* Must validate the ifa found is in our ep */
- struct sctp_laddr *laddr;
- int found = 0;
- LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
- if (laddr->ifa == NULL) {
- SCTPDBG(SCTP_DEBUG_OUTPUT1, "%s: NULL ifa\n",
- __func__);
- continue;
- }
- if ((sctp_is_addr_restricted(stcb, laddr->ifa)) &&
- (!sctp_is_addr_pending(stcb, laddr->ifa))) {
- continue;
- }
- if (laddr->ifa == ifa) {
- found = 1;
- break;
- }
- }
- if (!found) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- goto out_of_it;
- }
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- } else {
- switch (addr->sa_family) {
- #ifdef INET
- case AF_INET:
- {
- struct sockaddr_in *sin;
- sin = (struct sockaddr_in *)addr;
- if (prison_check_ip4(inp->ip_inp.inp.inp_cred,
- &sin->sin_addr) != 0) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- goto out_of_it;
- }
- break;
- }
- #endif
- #ifdef INET6
- case AF_INET6:
- {
- struct sockaddr_in6 *sin6;
- sin6 = (struct sockaddr_in6 *)addr;
- if (prison_check_ip6(inp->ip_inp.inp.inp_cred,
- &sin6->sin6_addr) != 0) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- goto out_of_it;
- }
- break;
- }
- #endif
- default:
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- goto out_of_it;
- }
- #endif
- }
- if (sctp_set_primary_ip_address_sa(stcb, addr) != 0) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SOCKOPT, SCTP_SO_LOCKED);
- out_of_it:
- SCTP_TCB_UNLOCK(stcb);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- break;
- }
- case SCTP_BINDX_ADD_ADDR:
- {
- struct sockaddr *sa;
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- struct thread *td;
- td = (struct thread *)p;
- #endif
- SCTP_CHECK_AND_CAST(sa, optval, struct sockaddr, optsize);
- #ifdef INET
- if (sa->sa_family == AF_INET) {
- if (optsize < sizeof(struct sockaddr_in)) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- break;
- }
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- if (td != NULL &&
- (error = prison_local_ip4(td->td_ucred, &(((struct sockaddr_in *)sa)->sin_addr)))) {
- SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error);
- break;
- }
- #endif
- } else
- #endif
- #ifdef INET6
- if (sa->sa_family == AF_INET6) {
- if (optsize < sizeof(struct sockaddr_in6)) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- break;
- }
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- if (td != NULL &&
- (error = prison_local_ip6(td->td_ucred,
- &(((struct sockaddr_in6 *)sa)->sin6_addr),
- (SCTP_IPV6_V6ONLY(inp) != 0))) != 0) {
- SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error);
- break;
- }
- #endif
- } else
- #endif
- {
- error = EAFNOSUPPORT;
- break;
- }
- sctp_bindx_add_address(so, inp, sa, vrf_id, &error, p);
- break;
- }
- case SCTP_BINDX_REM_ADDR:
- {
- struct sockaddr *sa;
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- struct thread *td;
- td = (struct thread *)p;
- #endif
- SCTP_CHECK_AND_CAST(sa, optval, struct sockaddr, optsize);
- #ifdef INET
- if (sa->sa_family == AF_INET) {
- if (optsize < sizeof(struct sockaddr_in)) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- break;
- }
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- if (td != NULL &&
- (error = prison_local_ip4(td->td_ucred, &(((struct sockaddr_in *)sa)->sin_addr)))) {
- SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error);
- break;
- }
- #endif
- } else
- #endif
- #ifdef INET6
- if (sa->sa_family == AF_INET6) {
- if (optsize < sizeof(struct sockaddr_in6)) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- break;
- }
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- if (td != NULL &&
- (error = prison_local_ip6(td->td_ucred,
- &(((struct sockaddr_in6 *)sa)->sin6_addr),
- (SCTP_IPV6_V6ONLY(inp) != 0))) != 0) {
- SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error);
- break;
- }
- #endif
- } else
- #endif
- {
- error = EAFNOSUPPORT;
- break;
- }
- sctp_bindx_delete_address(inp, sa, vrf_id, &error);
- break;
- }
- #if defined(__APPLE__) && !defined(__Userspace__)
- case SCTP_LISTEN_FIX:
- /* only applies to one-to-many sockets */
- if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
- /* make sure the ACCEPTCONN flag is OFF */
- so->so_options &= ~SO_ACCEPTCONN;
- } else {
- /* otherwise, not allowed */
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- break;
- #endif
- case SCTP_EVENT:
- {
- struct sctp_event *event;
- uint32_t event_type;
- SCTP_CHECK_AND_CAST(event, optval, struct sctp_event, optsize);
- SCTP_FIND_STCB(inp, stcb, event->se_assoc_id);
- switch (event->se_type) {
- case SCTP_ASSOC_CHANGE:
- event_type = SCTP_PCB_FLAGS_RECVASSOCEVNT;
- break;
- case SCTP_PEER_ADDR_CHANGE:
- event_type = SCTP_PCB_FLAGS_RECVPADDREVNT;
- break;
- case SCTP_REMOTE_ERROR:
- event_type = SCTP_PCB_FLAGS_RECVPEERERR;
- break;
- case SCTP_SEND_FAILED:
- event_type = SCTP_PCB_FLAGS_RECVSENDFAILEVNT;
- break;
- case SCTP_SHUTDOWN_EVENT:
- event_type = SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT;
- break;
- case SCTP_ADAPTATION_INDICATION:
- event_type = SCTP_PCB_FLAGS_ADAPTATIONEVNT;
- break;
- case SCTP_PARTIAL_DELIVERY_EVENT:
- event_type = SCTP_PCB_FLAGS_PDAPIEVNT;
- break;
- case SCTP_AUTHENTICATION_EVENT:
- event_type = SCTP_PCB_FLAGS_AUTHEVNT;
- break;
- case SCTP_STREAM_RESET_EVENT:
- event_type = SCTP_PCB_FLAGS_STREAM_RESETEVNT;
- break;
- case SCTP_SENDER_DRY_EVENT:
- event_type = SCTP_PCB_FLAGS_DRYEVNT;
- break;
- case SCTP_NOTIFICATIONS_STOPPED_EVENT:
- event_type = 0;
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTSUP);
- error = ENOTSUP;
- break;
- case SCTP_ASSOC_RESET_EVENT:
- event_type = SCTP_PCB_FLAGS_ASSOC_RESETEVNT;
- break;
- case SCTP_STREAM_CHANGE_EVENT:
- event_type = SCTP_PCB_FLAGS_STREAM_CHANGEEVNT;
- break;
- case SCTP_SEND_FAILED_EVENT:
- event_type = SCTP_PCB_FLAGS_RECVNSENDFAILEVNT;
- break;
- default:
- event_type = 0;
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- break;
- }
- if (event_type > 0) {
- if (stcb) {
- if (event->se_on) {
- sctp_stcb_feature_on(inp, stcb, event_type);
- if (event_type == SCTP_PCB_FLAGS_DRYEVNT) {
- if (TAILQ_EMPTY(&stcb->asoc.send_queue) &&
- TAILQ_EMPTY(&stcb->asoc.sent_queue) &&
- (stcb->asoc.stream_queue_cnt == 0)) {
- sctp_ulp_notify(SCTP_NOTIFY_SENDER_DRY, stcb, 0, NULL, SCTP_SO_LOCKED);
- }
- }
- } else {
- sctp_stcb_feature_off(inp, stcb, event_type);
- }
- SCTP_TCB_UNLOCK(stcb);
- } else {
- /*
- * We don't want to send up a storm of events,
- * so return an error for sender dry events
- */
- if ((event_type == SCTP_PCB_FLAGS_DRYEVNT) &&
- (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- ((event->se_assoc_id == SCTP_ALL_ASSOC) ||
- (event->se_assoc_id == SCTP_CURRENT_ASSOC))) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTSUP);
- error = ENOTSUP;
- break;
- }
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- ((event->se_assoc_id == SCTP_FUTURE_ASSOC) ||
- (event->se_assoc_id == SCTP_ALL_ASSOC)))) {
- SCTP_INP_WLOCK(inp);
- if (event->se_on) {
- sctp_feature_on(inp, event_type);
- } else {
- sctp_feature_off(inp, event_type);
- }
- SCTP_INP_WUNLOCK(inp);
- }
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- ((event->se_assoc_id == SCTP_CURRENT_ASSOC) ||
- (event->se_assoc_id == SCTP_ALL_ASSOC))) {
- SCTP_INP_RLOCK(inp);
- LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
- SCTP_TCB_LOCK(stcb);
- if (event->se_on) {
- sctp_stcb_feature_on(inp, stcb, event_type);
- } else {
- sctp_stcb_feature_off(inp, stcb, event_type);
- }
- SCTP_TCB_UNLOCK(stcb);
- }
- SCTP_INP_RUNLOCK(inp);
- }
- }
- } else {
- if (stcb) {
- SCTP_TCB_UNLOCK(stcb);
- }
- }
- break;
- }
- case SCTP_RECVRCVINFO:
- {
- int *onoff;
- SCTP_CHECK_AND_CAST(onoff, optval, int, optsize);
- SCTP_INP_WLOCK(inp);
- if (*onoff != 0) {
- sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO);
- } else {
- sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVRCVINFO);
- }
- SCTP_INP_WUNLOCK(inp);
- break;
- }
- case SCTP_RECVNXTINFO:
- {
- int *onoff;
- SCTP_CHECK_AND_CAST(onoff, optval, int, optsize);
- SCTP_INP_WLOCK(inp);
- if (*onoff != 0) {
- sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO);
- } else {
- sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVNXTINFO);
- }
- SCTP_INP_WUNLOCK(inp);
- break;
- }
- case SCTP_DEFAULT_SNDINFO:
- {
- struct sctp_sndinfo *info;
- uint16_t policy;
- SCTP_CHECK_AND_CAST(info, optval, struct sctp_sndinfo, optsize);
- SCTP_FIND_STCB(inp, stcb, info->snd_assoc_id);
- if (stcb) {
- if (info->snd_sid < stcb->asoc.streamoutcnt) {
- stcb->asoc.def_send.sinfo_stream = info->snd_sid;
- policy = PR_SCTP_POLICY(stcb->asoc.def_send.sinfo_flags);
- stcb->asoc.def_send.sinfo_flags = info->snd_flags;
- stcb->asoc.def_send.sinfo_flags |= policy;
- stcb->asoc.def_send.sinfo_ppid = info->snd_ppid;
- stcb->asoc.def_send.sinfo_context = info->snd_context;
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- ((info->snd_assoc_id == SCTP_FUTURE_ASSOC) ||
- (info->snd_assoc_id == SCTP_ALL_ASSOC)))) {
- SCTP_INP_WLOCK(inp);
- inp->def_send.sinfo_stream = info->snd_sid;
- policy = PR_SCTP_POLICY(inp->def_send.sinfo_flags);
- inp->def_send.sinfo_flags = info->snd_flags;
- inp->def_send.sinfo_flags |= policy;
- inp->def_send.sinfo_ppid = info->snd_ppid;
- inp->def_send.sinfo_context = info->snd_context;
- SCTP_INP_WUNLOCK(inp);
- }
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- ((info->snd_assoc_id == SCTP_CURRENT_ASSOC) ||
- (info->snd_assoc_id == SCTP_ALL_ASSOC))) {
- SCTP_INP_RLOCK(inp);
- LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
- SCTP_TCB_LOCK(stcb);
- if (info->snd_sid < stcb->asoc.streamoutcnt) {
- stcb->asoc.def_send.sinfo_stream = info->snd_sid;
- policy = PR_SCTP_POLICY(stcb->asoc.def_send.sinfo_flags);
- stcb->asoc.def_send.sinfo_flags = info->snd_flags;
- stcb->asoc.def_send.sinfo_flags |= policy;
- stcb->asoc.def_send.sinfo_ppid = info->snd_ppid;
- stcb->asoc.def_send.sinfo_context = info->snd_context;
- }
- SCTP_TCB_UNLOCK(stcb);
- }
- SCTP_INP_RUNLOCK(inp);
- }
- }
- break;
- }
- case SCTP_DEFAULT_PRINFO:
- {
- struct sctp_default_prinfo *info;
- SCTP_CHECK_AND_CAST(info, optval, struct sctp_default_prinfo, optsize);
- SCTP_FIND_STCB(inp, stcb, info->pr_assoc_id);
- if (info->pr_policy > SCTP_PR_SCTP_MAX) {
- if (stcb) {
- SCTP_TCB_UNLOCK(stcb);
- }
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- break;
- }
- if (stcb) {
- stcb->asoc.def_send.sinfo_flags &= 0xfff0;
- stcb->asoc.def_send.sinfo_flags |= info->pr_policy;
- stcb->asoc.def_send.sinfo_timetolive = info->pr_value;
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- ((info->pr_assoc_id == SCTP_FUTURE_ASSOC) ||
- (info->pr_assoc_id == SCTP_ALL_ASSOC)))) {
- SCTP_INP_WLOCK(inp);
- inp->def_send.sinfo_flags &= 0xfff0;
- inp->def_send.sinfo_flags |= info->pr_policy;
- inp->def_send.sinfo_timetolive = info->pr_value;
- SCTP_INP_WUNLOCK(inp);
- }
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- ((info->pr_assoc_id == SCTP_CURRENT_ASSOC) ||
- (info->pr_assoc_id == SCTP_ALL_ASSOC))) {
- SCTP_INP_RLOCK(inp);
- LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
- SCTP_TCB_LOCK(stcb);
- stcb->asoc.def_send.sinfo_flags &= 0xfff0;
- stcb->asoc.def_send.sinfo_flags |= info->pr_policy;
- stcb->asoc.def_send.sinfo_timetolive = info->pr_value;
- SCTP_TCB_UNLOCK(stcb);
- }
- SCTP_INP_RUNLOCK(inp);
- }
- }
- break;
- }
- case SCTP_PEER_ADDR_THLDS:
- /* Applies to the specific association */
- {
- struct sctp_paddrthlds *thlds;
- struct sctp_nets *net;
- struct sockaddr *addr;
- #if defined(INET) && defined(INET6)
- struct sockaddr_in sin_store;
- #endif
- SCTP_CHECK_AND_CAST(thlds, optval, struct sctp_paddrthlds, optsize);
- SCTP_FIND_STCB(inp, stcb, thlds->spt_assoc_id);
- #if defined(INET) && defined(INET6)
- if (thlds->spt_address.ss_family == AF_INET6) {
- struct sockaddr_in6 *sin6;
- sin6 = (struct sockaddr_in6 *)&thlds->spt_address;
- if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
- in6_sin6_2_sin(&sin_store, sin6);
- addr = (struct sockaddr *)&sin_store;
- } else {
- addr = (struct sockaddr *)&thlds->spt_address;
- }
- } else {
- addr = (struct sockaddr *)&thlds->spt_address;
- }
- #else
- addr = (struct sockaddr *)&thlds->spt_address;
- #endif
- if (stcb != NULL) {
- net = sctp_findnet(stcb, addr);
- } else {
- /* We increment here since sctp_findassociation_ep_addr() wil
- * do a decrement if it finds the stcb as long as the locked
- * tcb (last argument) is NOT a TCB.. aka NULL.
- */
- net = NULL;
- SCTP_INP_INCR_REF(inp);
- stcb = sctp_findassociation_ep_addr(&inp, addr,
- &net, NULL, NULL);
- if (stcb == NULL) {
- SCTP_INP_DECR_REF(inp);
- }
- }
- if ((stcb != NULL) && (net == NULL)) {
- #ifdef INET
- if (addr->sa_family == AF_INET) {
- struct sockaddr_in *sin;
- sin = (struct sockaddr_in *)addr;
- if (sin->sin_addr.s_addr != INADDR_ANY) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- SCTP_TCB_UNLOCK(stcb);
- error = EINVAL;
- break;
- }
- } else
- #endif
- #ifdef INET6
- if (addr->sa_family == AF_INET6) {
- struct sockaddr_in6 *sin6;
- sin6 = (struct sockaddr_in6 *)addr;
- if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- SCTP_TCB_UNLOCK(stcb);
- error = EINVAL;
- break;
- }
- } else
- #endif
- #if defined(__Userspace__)
- if (addr->sa_family == AF_CONN) {
- struct sockaddr_conn *sconn;
- sconn = (struct sockaddr_conn *)addr;
- if (sconn->sconn_addr != NULL) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- SCTP_TCB_UNLOCK(stcb);
- error = EINVAL;
- break;
- }
- } else
- #endif
- {
- error = EAFNOSUPPORT;
- SCTP_TCB_UNLOCK(stcb);
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
- break;
- }
- }
- if (thlds->spt_pathcpthld != 0xffff) {
- if (stcb != NULL) {
- SCTP_TCB_UNLOCK(stcb);
- }
- error = EINVAL;
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
- break;
- }
- if (stcb != NULL) {
- if (net != NULL) {
- net->failure_threshold = thlds->spt_pathmaxrxt;
- net->pf_threshold = thlds->spt_pathpfthld;
- if (net->dest_state & SCTP_ADDR_PF) {
- if ((net->error_count > net->failure_threshold) ||
- (net->error_count <= net->pf_threshold)) {
- net->dest_state &= ~SCTP_ADDR_PF;
- }
- } else {
- if ((net->error_count > net->pf_threshold) &&
- (net->error_count <= net->failure_threshold)) {
- net->dest_state |= SCTP_ADDR_PF;
- sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
- sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT,
- stcb->sctp_ep, stcb, net,
- SCTP_FROM_SCTP_USRREQ + SCTP_LOC_17);
- sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
- }
- }
- if (net->dest_state & SCTP_ADDR_REACHABLE) {
- if (net->error_count > net->failure_threshold) {
- net->dest_state &= ~SCTP_ADDR_REACHABLE;
- sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED);
- }
- } else {
- if (net->error_count <= net->failure_threshold) {
- net->dest_state |= SCTP_ADDR_REACHABLE;
- sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED);
- }
- }
- } else {
- TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
- net->failure_threshold = thlds->spt_pathmaxrxt;
- net->pf_threshold = thlds->spt_pathpfthld;
- if (net->dest_state & SCTP_ADDR_PF) {
- if ((net->error_count > net->failure_threshold) ||
- (net->error_count <= net->pf_threshold)) {
- net->dest_state &= ~SCTP_ADDR_PF;
- }
- } else {
- if ((net->error_count > net->pf_threshold) &&
- (net->error_count <= net->failure_threshold)) {
- net->dest_state |= SCTP_ADDR_PF;
- sctp_send_hb(stcb, net, SCTP_SO_LOCKED);
- sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT,
- stcb->sctp_ep, stcb, net,
- SCTP_FROM_SCTP_USRREQ + SCTP_LOC_18);
- sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net);
- }
- }
- if (net->dest_state & SCTP_ADDR_REACHABLE) {
- if (net->error_count > net->failure_threshold) {
- net->dest_state &= ~SCTP_ADDR_REACHABLE;
- sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED);
- }
- } else {
- if (net->error_count <= net->failure_threshold) {
- net->dest_state |= SCTP_ADDR_REACHABLE;
- sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED);
- }
- }
- }
- stcb->asoc.def_net_failure = thlds->spt_pathmaxrxt;
- stcb->asoc.def_net_pf_threshold = thlds->spt_pathpfthld;
- }
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- (thlds->spt_assoc_id == SCTP_FUTURE_ASSOC))) {
- SCTP_INP_WLOCK(inp);
- inp->sctp_ep.def_net_failure = thlds->spt_pathmaxrxt;
- inp->sctp_ep.def_net_pf_threshold = thlds->spt_pathpfthld;
- SCTP_INP_WUNLOCK(inp);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- }
- break;
- }
- case SCTP_REMOTE_UDP_ENCAPS_PORT:
- {
- struct sctp_udpencaps *encaps;
- struct sctp_nets *net;
- struct sockaddr *addr;
- #if defined(INET) && defined(INET6)
- struct sockaddr_in sin_store;
- #endif
- SCTP_CHECK_AND_CAST(encaps, optval, struct sctp_udpencaps, optsize);
- SCTP_FIND_STCB(inp, stcb, encaps->sue_assoc_id);
- #if defined(INET) && defined(INET6)
- if (encaps->sue_address.ss_family == AF_INET6) {
- struct sockaddr_in6 *sin6;
- sin6 = (struct sockaddr_in6 *)&encaps->sue_address;
- if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
- in6_sin6_2_sin(&sin_store, sin6);
- addr = (struct sockaddr *)&sin_store;
- } else {
- addr = (struct sockaddr *)&encaps->sue_address;
- }
- } else {
- addr = (struct sockaddr *)&encaps->sue_address;
- }
- #else
- addr = (struct sockaddr *)&encaps->sue_address;
- #endif
- if (stcb != NULL) {
- net = sctp_findnet(stcb, addr);
- } else {
- /* We increment here since sctp_findassociation_ep_addr() wil
- * do a decrement if it finds the stcb as long as the locked
- * tcb (last argument) is NOT a TCB.. aka NULL.
- */
- net = NULL;
- SCTP_INP_INCR_REF(inp);
- stcb = sctp_findassociation_ep_addr(&inp, addr, &net, NULL, NULL);
- if (stcb == NULL) {
- SCTP_INP_DECR_REF(inp);
- }
- }
- if ((stcb != NULL) && (net == NULL)) {
- #ifdef INET
- if (addr->sa_family == AF_INET) {
- struct sockaddr_in *sin;
- sin = (struct sockaddr_in *)addr;
- if (sin->sin_addr.s_addr != INADDR_ANY) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- SCTP_TCB_UNLOCK(stcb);
- error = EINVAL;
- break;
- }
- } else
- #endif
- #ifdef INET6
- if (addr->sa_family == AF_INET6) {
- struct sockaddr_in6 *sin6;
- sin6 = (struct sockaddr_in6 *)addr;
- if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- SCTP_TCB_UNLOCK(stcb);
- error = EINVAL;
- break;
- }
- } else
- #endif
- #if defined(__Userspace__)
- if (addr->sa_family == AF_CONN) {
- struct sockaddr_conn *sconn;
- sconn = (struct sockaddr_conn *)addr;
- if (sconn->sconn_addr != NULL) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- SCTP_TCB_UNLOCK(stcb);
- error = EINVAL;
- break;
- }
- } else
- #endif
- {
- error = EAFNOSUPPORT;
- SCTP_TCB_UNLOCK(stcb);
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
- break;
- }
- }
- if (stcb != NULL) {
- if (net != NULL) {
- net->port = encaps->sue_port;
- } else {
- stcb->asoc.port = encaps->sue_port;
- }
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- (encaps->sue_assoc_id == SCTP_FUTURE_ASSOC))) {
- SCTP_INP_WLOCK(inp);
- inp->sctp_ep.port = encaps->sue_port;
- SCTP_INP_WUNLOCK(inp);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- }
- break;
- }
- case SCTP_ECN_SUPPORTED:
- {
- struct sctp_assoc_value *av;
- SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
- SCTP_FIND_STCB(inp, stcb, av->assoc_id);
- if (stcb) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- (av->assoc_id == SCTP_FUTURE_ASSOC))) {
- SCTP_INP_WLOCK(inp);
- if (av->assoc_value == 0) {
- inp->ecn_supported = 0;
- } else {
- inp->ecn_supported = 1;
- }
- SCTP_INP_WUNLOCK(inp);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- }
- break;
- }
- case SCTP_PR_SUPPORTED:
- {
- struct sctp_assoc_value *av;
- SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
- SCTP_FIND_STCB(inp, stcb, av->assoc_id);
- if (stcb) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- (av->assoc_id == SCTP_FUTURE_ASSOC))) {
- SCTP_INP_WLOCK(inp);
- if (av->assoc_value == 0) {
- inp->prsctp_supported = 0;
- } else {
- inp->prsctp_supported = 1;
- }
- SCTP_INP_WUNLOCK(inp);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- }
- break;
- }
- case SCTP_AUTH_SUPPORTED:
- {
- struct sctp_assoc_value *av;
- SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
- SCTP_FIND_STCB(inp, stcb, av->assoc_id);
- if (stcb) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- (av->assoc_id == SCTP_FUTURE_ASSOC))) {
- if ((av->assoc_value == 0) &&
- (inp->asconf_supported == 1)) {
- /* AUTH is required for ASCONF */
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- } else {
- SCTP_INP_WLOCK(inp);
- if (av->assoc_value == 0) {
- inp->auth_supported = 0;
- } else {
- inp->auth_supported = 1;
- }
- SCTP_INP_WUNLOCK(inp);
- }
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- }
- break;
- }
- case SCTP_ASCONF_SUPPORTED:
- {
- struct sctp_assoc_value *av;
- SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
- SCTP_FIND_STCB(inp, stcb, av->assoc_id);
- if (stcb) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- (av->assoc_id == SCTP_FUTURE_ASSOC))) {
- if ((av->assoc_value != 0) &&
- (inp->auth_supported == 0)) {
- /* AUTH is required for ASCONF */
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- } else {
- SCTP_INP_WLOCK(inp);
- if (av->assoc_value == 0) {
- inp->asconf_supported = 0;
- sctp_auth_delete_chunk(SCTP_ASCONF,
- inp->sctp_ep.local_auth_chunks);
- sctp_auth_delete_chunk(SCTP_ASCONF_ACK,
- inp->sctp_ep.local_auth_chunks);
- } else {
- inp->asconf_supported = 1;
- sctp_auth_add_chunk(SCTP_ASCONF,
- inp->sctp_ep.local_auth_chunks);
- sctp_auth_add_chunk(SCTP_ASCONF_ACK,
- inp->sctp_ep.local_auth_chunks);
- }
- SCTP_INP_WUNLOCK(inp);
- }
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- }
- break;
- }
- case SCTP_RECONFIG_SUPPORTED:
- {
- struct sctp_assoc_value *av;
- SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
- SCTP_FIND_STCB(inp, stcb, av->assoc_id);
- if (stcb) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- (av->assoc_id == SCTP_FUTURE_ASSOC))) {
- SCTP_INP_WLOCK(inp);
- if (av->assoc_value == 0) {
- inp->reconfig_supported = 0;
- } else {
- inp->reconfig_supported = 1;
- }
- SCTP_INP_WUNLOCK(inp);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- }
- break;
- }
- case SCTP_NRSACK_SUPPORTED:
- {
- struct sctp_assoc_value *av;
- SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
- SCTP_FIND_STCB(inp, stcb, av->assoc_id);
- if (stcb) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- (av->assoc_id == SCTP_FUTURE_ASSOC))) {
- SCTP_INP_WLOCK(inp);
- if (av->assoc_value == 0) {
- inp->nrsack_supported = 0;
- } else {
- inp->nrsack_supported = 1;
- }
- SCTP_INP_WUNLOCK(inp);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- }
- break;
- }
- case SCTP_PKTDROP_SUPPORTED:
- {
- struct sctp_assoc_value *av;
- SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
- SCTP_FIND_STCB(inp, stcb, av->assoc_id);
- if (stcb) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- (av->assoc_id == SCTP_FUTURE_ASSOC))) {
- SCTP_INP_WLOCK(inp);
- if (av->assoc_value == 0) {
- inp->pktdrop_supported = 0;
- } else {
- inp->pktdrop_supported = 1;
- }
- SCTP_INP_WUNLOCK(inp);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- }
- break;
- }
- case SCTP_MAX_CWND:
- {
- struct sctp_assoc_value *av;
- struct sctp_nets *net;
- SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
- SCTP_FIND_STCB(inp, stcb, av->assoc_id);
- if (stcb) {
- stcb->asoc.max_cwnd = av->assoc_value;
- if (stcb->asoc.max_cwnd > 0) {
- TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
- if ((net->cwnd > stcb->asoc.max_cwnd) &&
- (net->cwnd > (net->mtu - sizeof(struct sctphdr)))) {
- net->cwnd = stcb->asoc.max_cwnd;
- if (net->cwnd < (net->mtu - sizeof(struct sctphdr))) {
- net->cwnd = net->mtu - sizeof(struct sctphdr);
- }
- }
- }
- }
- SCTP_TCB_UNLOCK(stcb);
- } else {
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) &&
- (av->assoc_id == SCTP_FUTURE_ASSOC))) {
- SCTP_INP_WLOCK(inp);
- inp->max_cwnd = av->assoc_value;
- SCTP_INP_WUNLOCK(inp);
- } else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- }
- break;
- }
- default:
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
- error = ENOPROTOOPT;
- break;
- } /* end switch (opt) */
- return (error);
- }
- #if !defined(__Userspace__)
- int
- sctp_ctloutput(struct socket *so, struct sockopt *sopt)
- {
- #if defined(__FreeBSD__)
- struct epoch_tracker et;
- struct sctp_inpcb *inp;
- #endif
- void *optval = NULL;
- void *p;
- size_t optsize = 0;
- int error = 0;
- #if defined(__FreeBSD__)
- if ((sopt->sopt_level == SOL_SOCKET) &&
- (sopt->sopt_name == SO_SETFIB)) {
- inp = (struct sctp_inpcb *)so->so_pcb;
- if (inp == NULL) {
- SCTP_LTRACE_ERR_RET(so->so_pcb, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOBUFS);
- return (EINVAL);
- }
- SCTP_INP_WLOCK(inp);
- inp->fibnum = so->so_fibnum;
- SCTP_INP_WUNLOCK(inp);
- return (0);
- }
- #endif
- if (sopt->sopt_level != IPPROTO_SCTP) {
- /* wrong proto level... send back up to IP */
- #ifdef INET6
- if (INP_CHECK_SOCKAF(so, AF_INET6))
- error = ip6_ctloutput(so, sopt);
- #endif /* INET6 */
- #if defined(INET) && defined(INET6)
- else
- #endif
- #ifdef INET
- error = ip_ctloutput(so, sopt);
- #endif
- return (error);
- }
- optsize = sopt->sopt_valsize;
- if (optsize > SCTP_SOCKET_OPTION_LIMIT) {
- SCTP_LTRACE_ERR_RET(so->so_pcb, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOBUFS);
- return (ENOBUFS);
- }
- if (optsize) {
- SCTP_MALLOC(optval, void *, optsize, SCTP_M_SOCKOPT);
- if (optval == NULL) {
- SCTP_LTRACE_ERR_RET(so->so_pcb, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOBUFS);
- return (ENOBUFS);
- }
- error = sooptcopyin(sopt, optval, optsize, optsize);
- if (error) {
- SCTP_FREE(optval, SCTP_M_SOCKOPT);
- goto out;
- }
- }
- #if defined(__FreeBSD__) || defined(_WIN32)
- p = (void *)sopt->sopt_td;
- #else
- p = (void *)sopt->sopt_p;
- #endif
- if (sopt->sopt_dir == SOPT_SET) {
- #if defined(__FreeBSD__)
- NET_EPOCH_ENTER(et);
- #endif
- error = sctp_setopt(so, sopt->sopt_name, optval, optsize, p);
- #if defined(__FreeBSD__)
- NET_EPOCH_EXIT(et);
- #endif
- } else if (sopt->sopt_dir == SOPT_GET) {
- error = sctp_getopt(so, sopt->sopt_name, optval, &optsize, p);
- } else {
- SCTP_LTRACE_ERR_RET(so->so_pcb, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- }
- if ((error == 0) && (optval != NULL)) {
- error = sooptcopyout(sopt, optval, optsize);
- SCTP_FREE(optval, SCTP_M_SOCKOPT);
- } else if (optval != NULL) {
- SCTP_FREE(optval, SCTP_M_SOCKOPT);
- }
- out:
- return (error);
- }
- #endif
- #ifdef INET
- #if defined(__Userspace__)
- int
- sctp_connect(struct socket *so, struct sockaddr *addr)
- {
- void *p = NULL;
- #elif defined(__FreeBSD__)
- static int
- sctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
- {
- #elif defined(__APPLE__)
- static int
- sctp_connect(struct socket *so, struct sockaddr *addr, struct proc *p)
- {
- #elif defined(_WIN32)
- static int
- sctp_connect(struct socket *so, struct sockaddr *addr, PKTHREAD p)
- {
- #else
- static int
- sctp_connect(struct socket *so, struct mbuf *nam, struct proc *p)
- {
- struct sockaddr *addr = mtod(nam, struct sockaddr *);
- #endif
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- struct epoch_tracker et;
- #endif
- #ifdef SCTP_MVRF
- int i, fnd = 0;
- #endif
- int error = 0;
- int create_lock_on = 0;
- uint32_t vrf_id;
- struct sctp_inpcb *inp;
- struct sctp_tcb *stcb = NULL;
- inp = (struct sctp_inpcb *)so->so_pcb;
- if (inp == NULL) {
- /* I made the same as TCP since we are not setup? */
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- return (ECONNRESET);
- }
- if (addr == NULL) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- return EINVAL;
- }
- #if defined(__Userspace__)
- /* TODO __Userspace__ falls into this code for IPv6 stuff at the moment... */
- #endif
- #if !defined(_WIN32) && !defined(__linux__) && !defined(__EMSCRIPTEN__)
- switch (addr->sa_family) {
- #ifdef INET6
- case AF_INET6:
- {
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- struct sockaddr_in6 *sin6;
- #endif
- if (addr->sa_len != sizeof(struct sockaddr_in6)) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- return (EINVAL);
- }
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- sin6 = (struct sockaddr_in6 *)addr;
- if (p != NULL && (error = prison_remote_ip6(p->td_ucred, &sin6->sin6_addr)) != 0) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
- return (error);
- }
- #endif
- break;
- }
- #endif
- #ifdef INET
- case AF_INET:
- {
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- struct sockaddr_in *sin;
- #endif
- #if !defined(_WIN32)
- if (addr->sa_len != sizeof(struct sockaddr_in)) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- return (EINVAL);
- }
- #endif
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- sin = (struct sockaddr_in *)addr;
- if (p != NULL && (error = prison_remote_ip4(p->td_ucred, &sin->sin_addr)) != 0) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
- return (error);
- }
- #endif
- break;
- }
- #endif
- default:
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EAFNOSUPPORT);
- return (EAFNOSUPPORT);
- }
- #endif
- SCTP_INP_INCR_REF(inp);
- SCTP_ASOC_CREATE_LOCK(inp);
- create_lock_on = 1;
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- NET_EPOCH_ENTER(et);
- #endif
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) {
- /* Should I really unlock ? */
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EFAULT);
- error = EFAULT;
- goto out_now;
- }
- #ifdef INET6
- if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) &&
- (addr->sa_family == AF_INET6)) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- goto out_now;
- }
- #endif
- #if defined(__Userspace__)
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_CONN) &&
- (addr->sa_family != AF_CONN)) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- goto out_now;
- }
- #endif
- if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) {
- /* Bind a ephemeral port */
- error = sctp_inpcb_bind(so, NULL, NULL, p);
- if (error) {
- goto out_now;
- }
- }
- /* Now do we connect? */
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) &&
- (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE))) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- goto out_now;
- }
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
- (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
- /* We are already connected AND the TCP model */
- SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE);
- error = EADDRINUSE;
- goto out_now;
- }
- if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
- SCTP_INP_RLOCK(inp);
- stcb = LIST_FIRST(&inp->sctp_asoc_list);
- SCTP_INP_RUNLOCK(inp);
- } else {
- /* We increment here since sctp_findassociation_ep_addr() will
- * do a decrement if it finds the stcb as long as the locked
- * tcb (last argument) is NOT a TCB.. aka NULL.
- */
- SCTP_INP_INCR_REF(inp);
- stcb = sctp_findassociation_ep_addr(&inp, addr, NULL, NULL, NULL);
- if (stcb == NULL) {
- SCTP_INP_DECR_REF(inp);
- } else {
- SCTP_TCB_UNLOCK(stcb);
- }
- }
- if (stcb != NULL) {
- /* Already have or am bring up an association */
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
- error = EALREADY;
- goto out_now;
- }
- vrf_id = inp->def_vrf_id;
- #ifdef SCTP_MVRF
- for (i = 0; i < inp->num_vrfs; i++) {
- if (vrf_id == inp->m_vrf_ids[i]) {
- fnd = 1;
- break;
- }
- }
- if (!fnd) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- goto out_now;
- }
- #endif
- /* We are GOOD to go */
- stcb = sctp_aloc_assoc_connected(inp, addr, &error, 0, 0, vrf_id,
- inp->sctp_ep.pre_open_stream_count,
- inp->sctp_ep.port, p,
- SCTP_INITIALIZE_AUTH_PARAMS);
- if (stcb == NULL) {
- /* Gak! no memory */
- goto out_now;
- }
- SCTP_SET_STATE(stcb, SCTP_STATE_COOKIE_WAIT);
- (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
- sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
- SCTP_TCB_UNLOCK(stcb);
- out_now:
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- NET_EPOCH_EXIT(et);
- #endif
- if (create_lock_on) {
- SCTP_ASOC_CREATE_UNLOCK(inp);
- }
- SCTP_INP_DECR_REF(inp);
- return (error);
- }
- #endif
- #if defined(__Userspace__)
- int
- sctpconn_connect(struct socket *so, struct sockaddr *addr)
- {
- #ifdef SCTP_MVRF
- int i, fnd = 0;
- #endif
- void *p = NULL;
- int error = 0;
- int create_lock_on = 0;
- uint32_t vrf_id;
- struct sctp_inpcb *inp;
- struct sctp_tcb *stcb = NULL;
- inp = (struct sctp_inpcb *)so->so_pcb;
- if (inp == NULL) {
- /* I made the same as TCP since we are not setup? */
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- return (ECONNRESET);
- }
- if (addr == NULL) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- return EINVAL;
- }
- switch (addr->sa_family) {
- #ifdef INET
- case AF_INET:
- #ifdef HAVE_SA_LEN
- if (addr->sa_len != sizeof(struct sockaddr_in)) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- return (EINVAL);
- }
- #endif
- break;
- #endif
- #ifdef INET6
- case AF_INET6:
- #ifdef HAVE_SA_LEN
- if (addr->sa_len != sizeof(struct sockaddr_in6)) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- return (EINVAL);
- }
- #endif
- break;
- #endif
- case AF_CONN:
- #ifdef HAVE_SA_LEN
- if (addr->sa_len != sizeof(struct sockaddr_conn)) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- return (EINVAL);
- }
- #endif
- break;
- default:
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EAFNOSUPPORT);
- return (EAFNOSUPPORT);
- }
- SCTP_INP_INCR_REF(inp);
- SCTP_ASOC_CREATE_LOCK(inp);
- create_lock_on = 1;
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) {
- /* Should I really unlock ? */
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EFAULT);
- error = EFAULT;
- goto out_now;
- }
- #ifdef INET6
- if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) &&
- (addr->sa_family == AF_INET6)) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- goto out_now;
- }
- #endif
- if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) {
- /* Bind a ephemeral port */
- error = sctp_inpcb_bind(so, NULL, NULL, p);
- if (error) {
- goto out_now;
- }
- }
- /* Now do we connect? */
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) &&
- (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE))) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- goto out_now;
- }
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
- (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
- /* We are already connected AND the TCP model */
- SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE);
- error = EADDRINUSE;
- goto out_now;
- }
- if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
- SCTP_INP_RLOCK(inp);
- stcb = LIST_FIRST(&inp->sctp_asoc_list);
- SCTP_INP_RUNLOCK(inp);
- } else {
- /* We increment here since sctp_findassociation_ep_addr() will
- * do a decrement if it finds the stcb as long as the locked
- * tcb (last argument) is NOT a TCB.. aka NULL.
- */
- SCTP_INP_INCR_REF(inp);
- stcb = sctp_findassociation_ep_addr(&inp, addr, NULL, NULL, NULL);
- if (stcb == NULL) {
- SCTP_INP_DECR_REF(inp);
- } else {
- SCTP_TCB_UNLOCK(stcb);
- }
- }
- if (stcb != NULL) {
- /* Already have or am bring up an association */
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
- error = EALREADY;
- goto out_now;
- }
- vrf_id = inp->def_vrf_id;
- #ifdef SCTP_MVRF
- for (i = 0; i < inp->num_vrfs; i++) {
- if (vrf_id == inp->m_vrf_ids[i]) {
- fnd = 1;
- break;
- }
- }
- if (!fnd) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- goto out_now;
- }
- #endif
- /* We are GOOD to go */
- stcb = sctp_aloc_assoc_connected(inp, addr, &error, 0, 0, vrf_id,
- inp->sctp_ep.pre_open_stream_count,
- inp->sctp_ep.port, p,
- SCTP_INITIALIZE_AUTH_PARAMS);
- if (stcb == NULL) {
- /* Gak! no memory */
- goto out_now;
- }
- SCTP_SET_STATE(stcb, SCTP_STATE_COOKIE_WAIT);
- (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
- sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
- SCTP_TCB_UNLOCK(stcb);
- out_now:
- if (create_lock_on) {
- SCTP_ASOC_CREATE_UNLOCK(inp);
- }
- SCTP_INP_DECR_REF(inp);
- return (error);
- }
- #endif
- int
- #if defined(__Userspace__)
- sctp_listen(struct socket *so, int backlog, struct proc *p)
- #elif defined(__FreeBSD__)
- sctp_listen(struct socket *so, int backlog, struct thread *p)
- #elif defined(_WIN32)
- sctp_listen(struct socket *so, int backlog, PKTHREAD p)
- #else
- sctp_listen(struct socket *so, struct proc *p)
- #endif
- {
- /*
- * Note this module depends on the protocol processing being called
- * AFTER any socket level flags and backlog are applied to the
- * socket. The traditional way that the socket flags are applied is
- * AFTER protocol processing. We have made a change to the
- * sys/kern/uipc_socket.c module to reverse this but this MUST be in
- * place if the socket API for SCTP is to work properly.
- */
- int error = 0;
- struct sctp_inpcb *inp;
- inp = (struct sctp_inpcb *)so->so_pcb;
- if (inp == NULL) {
- /* I made the same as TCP since we are not setup? */
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- return (ECONNRESET);
- }
- if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE)) {
- /* See if we have a listener */
- struct sctp_inpcb *tinp;
- union sctp_sockstore store;
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) {
- /* not bound all */
- struct sctp_laddr *laddr;
- LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
- memcpy(&store, &laddr->ifa->address, sizeof(store));
- switch (store.sa.sa_family) {
- #ifdef INET
- case AF_INET:
- store.sin.sin_port = inp->sctp_lport;
- break;
- #endif
- #ifdef INET6
- case AF_INET6:
- store.sin6.sin6_port = inp->sctp_lport;
- break;
- #endif
- #if defined(__Userspace__)
- case AF_CONN:
- store.sconn.sconn_port = inp->sctp_lport;
- break;
- #endif
- default:
- break;
- }
- tinp = sctp_pcb_findep(&store.sa, 0, 0, inp->def_vrf_id);
- if (tinp && (tinp != inp) &&
- ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) == 0) &&
- ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
- (SCTP_IS_LISTENING(tinp))) {
- /* we have a listener already and its not this inp. */
- SCTP_INP_DECR_REF(tinp);
- return (EADDRINUSE);
- } else if (tinp) {
- SCTP_INP_DECR_REF(tinp);
- }
- }
- } else {
- /* Setup a local addr bound all */
- memset(&store, 0, sizeof(store));
- #ifdef INET6
- if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
- store.sa.sa_family = AF_INET6;
- #ifdef HAVE_SA_LEN
- store.sa.sa_len = sizeof(struct sockaddr_in6);
- #endif
- }
- #endif
- #if defined(__Userspace__)
- if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_CONN) {
- store.sa.sa_family = AF_CONN;
- #ifdef HAVE_SA_LEN
- store.sa.sa_len = sizeof(struct sockaddr_conn);
- #endif
- }
- #endif
- #ifdef INET
- #if defined(__Userspace__)
- if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) &&
- ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_CONN) == 0)) {
- #else
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) {
- #endif
- store.sa.sa_family = AF_INET;
- #ifdef HAVE_SA_LEN
- store.sa.sa_len = sizeof(struct sockaddr_in);
- #endif
- }
- #endif
- switch (store.sa.sa_family) {
- #ifdef INET
- case AF_INET:
- store.sin.sin_port = inp->sctp_lport;
- break;
- #endif
- #ifdef INET6
- case AF_INET6:
- store.sin6.sin6_port = inp->sctp_lport;
- break;
- #endif
- #if defined(__Userspace__)
- case AF_CONN:
- store.sconn.sconn_port = inp->sctp_lport;
- break;
- #endif
- default:
- break;
- }
- tinp = sctp_pcb_findep(&store.sa, 0, 0, inp->def_vrf_id);
- if (tinp && (tinp != inp) &&
- ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) == 0) &&
- ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
- (SCTP_IS_LISTENING(tinp))) {
- /* we have a listener already and its not this inp. */
- SCTP_INP_DECR_REF(tinp);
- return (EADDRINUSE);
- } else if (tinp) {
- SCTP_INP_DECR_REF(tinp);
- }
- }
- }
- SCTP_INP_INFO_WLOCK();
- SCTP_INP_WLOCK(inp);
- #ifdef SCTP_LOCK_LOGGING
- if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) {
- sctp_log_lock(inp, (struct sctp_tcb *)NULL, SCTP_LOG_LOCK_SOCK);
- }
- #endif
- if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE)) &&
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
- /* The unlucky case
- * - We are in the tcp pool with this guy.
- * - Someone else is in the main inp slot.
- * - We must move this guy (the listener) to the main slot
- * - We must then move the guy that was listener to the TCP Pool.
- */
- if (sctp_swap_inpcb_for_listen(inp)) {
- error = EADDRINUSE;
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
- goto out;
- }
- }
- #if defined(__FreeBSD__) || defined(__Userspace__)
- SOCK_LOCK(so);
- error = solisten_proto_check(so);
- if (error) {
- SOCK_UNLOCK(so);
- goto out;
- }
- #endif
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
- (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
- SOCK_UNLOCK(so);
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- solisten_proto_abort(so);
- #endif
- error = EADDRINUSE;
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
- goto out;
- }
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
- ((inp->sctp_flags & SCTP_PCB_FLAGS_WAS_CONNECTED) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_WAS_ABORTED))) {
- SOCK_UNLOCK(so);
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- solisten_proto_abort(so);
- #endif
- error = EINVAL;
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
- goto out;
- }
- if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) {
- if ((error = sctp_inpcb_bind_locked(inp, NULL, NULL, p))) {
- SOCK_UNLOCK(so);
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- solisten_proto_abort(so);
- #endif
- /* bind error, probably perm */
- goto out;
- }
- }
- #if defined(__FreeBSD__) && !defined(__Userspace__)
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) == 0) {
- solisten_proto(so, backlog);
- SOCK_UNLOCK(so);
- inp->sctp_flags |= SCTP_PCB_FLAGS_ACCEPTING;
- } else {
- solisten_proto_abort(so);
- SOCK_UNLOCK(so);
- if (backlog > 0) {
- inp->sctp_flags |= SCTP_PCB_FLAGS_ACCEPTING;
- } else {
- inp->sctp_flags &= ~SCTP_PCB_FLAGS_ACCEPTING;
- }
- }
- #elif defined(_WIN32) || defined(__Userspace__)
- solisten_proto(so, backlog);
- #endif
- #if !(defined(__FreeBSD__) && !defined(__Userspace__))
- if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
- /* remove the ACCEPTCONN flag for one-to-many sockets */
- #if defined(__Userspace__)
- so->so_options &= ~SCTP_SO_ACCEPTCONN;
- #else
- so->so_options &= ~SO_ACCEPTCONN;
- #endif
- }
- SOCK_UNLOCK(so);
- if (backlog > 0) {
- inp->sctp_flags |= SCTP_PCB_FLAGS_ACCEPTING;
- } else {
- inp->sctp_flags &= ~SCTP_PCB_FLAGS_ACCEPTING;
- }
- #endif
- out:
- SCTP_INP_WUNLOCK(inp);
- SCTP_INP_INFO_WUNLOCK();
- return (error);
- }
- static int sctp_defered_wakeup_cnt = 0;
- int
- sctp_accept(struct socket *so, struct sockaddr **addr)
- {
- struct sctp_tcb *stcb;
- struct sctp_inpcb *inp;
- union sctp_sockstore store;
- #ifdef INET6
- #if defined(SCTP_KAME) && defined(SCTP_EMBEDDED_V6_SCOPE)
- int error;
- #endif
- #endif
- inp = (struct sctp_inpcb *)so->so_pcb;
- if (inp == NULL) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- return (ECONNRESET);
- }
- SCTP_INP_WLOCK(inp);
- if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
- SCTP_INP_WUNLOCK(inp);
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
- return (EOPNOTSUPP);
- }
- if (so->so_state & SS_ISDISCONNECTED) {
- SCTP_INP_WUNLOCK(inp);
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ECONNABORTED);
- return (ECONNABORTED);
- }
- stcb = LIST_FIRST(&inp->sctp_asoc_list);
- if (stcb == NULL) {
- SCTP_INP_WUNLOCK(inp);
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- return (ECONNRESET);
- }
- SCTP_TCB_LOCK(stcb);
- store = stcb->asoc.primary_destination->ro._l_addr;
- SCTP_CLEAR_SUBSTATE(stcb, SCTP_STATE_IN_ACCEPT_QUEUE);
- /* Wake any delayed sleep action */
- if (inp->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) {
- inp->sctp_flags &= ~SCTP_PCB_FLAGS_DONT_WAKE;
- if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEOUTPUT) {
- inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEOUTPUT;
- SOCKBUF_LOCK(&inp->sctp_socket->so_snd);
- if (sowriteable(inp->sctp_socket)) {
- #if defined(__Userspace__)
- /*__Userspace__ calling sowwakup_locked because of SOCKBUF_LOCK above. */
- #endif
- #if defined(__FreeBSD__) || defined(_WIN32) || defined(__Userspace__)
- sowwakeup_locked(inp->sctp_socket);
- #else
- #if defined(__APPLE__)
- /* socket is locked */
- #endif
- sowwakeup(inp->sctp_socket);
- #endif
- } else {
- SOCKBUF_UNLOCK(&inp->sctp_socket->so_snd);
- }
- }
- if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEINPUT) {
- inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEINPUT;
- SOCKBUF_LOCK(&inp->sctp_socket->so_rcv);
- if (soreadable(inp->sctp_socket)) {
- sctp_defered_wakeup_cnt++;
- #if defined(__Userspace__)
- /*__Userspace__ calling sorwakup_locked because of SOCKBUF_LOCK above */
- #endif
- #if defined(__FreeBSD__) || defined(_WIN32) || defined(__Userspace__)
- sorwakeup_locked(inp->sctp_socket);
- #else
- #if defined(__APPLE__)
- /* socket is locked */
- #endif
- sorwakeup(inp->sctp_socket);
- #endif
- } else {
- SOCKBUF_UNLOCK(&inp->sctp_socket->so_rcv);
- }
- }
- }
- SCTP_INP_WUNLOCK(inp);
- if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
- sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
- SCTP_FROM_SCTP_USRREQ + SCTP_LOC_19);
- } else {
- SCTP_TCB_UNLOCK(stcb);
- }
- switch (store.sa.sa_family) {
- #ifdef INET
- case AF_INET:
- {
- struct sockaddr_in *sin;
- SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin);
- if (sin == NULL)
- return (ENOMEM);
- sin->sin_family = AF_INET;
- #ifdef HAVE_SIN_LEN
- sin->sin_len = sizeof(*sin);
- #endif
- sin->sin_port = store.sin.sin_port;
- sin->sin_addr = store.sin.sin_addr;
- *addr = (struct sockaddr *)sin;
- break;
- }
- #endif
- #ifdef INET6
- case AF_INET6:
- {
- struct sockaddr_in6 *sin6;
- SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6);
- if (sin6 == NULL)
- return (ENOMEM);
- sin6->sin6_family = AF_INET6;
- #ifdef HAVE_SIN6_LEN
- sin6->sin6_len = sizeof(*sin6);
- #endif
- sin6->sin6_port = store.sin6.sin6_port;
- sin6->sin6_addr = store.sin6.sin6_addr;
- #if defined(SCTP_EMBEDDED_V6_SCOPE)
- #ifdef SCTP_KAME
- if ((error = sa6_recoverscope(sin6)) != 0) {
- SCTP_FREE_SONAME(sin6);
- return (error);
- }
- #else
- if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr))
- /*
- * sin6->sin6_scope_id =
- * ntohs(sin6->sin6_addr.s6_addr16[1]);
- */
- in6_recoverscope(sin6, &sin6->sin6_addr, NULL); /* skip ifp check */
- else
- sin6->sin6_scope_id = 0; /* XXX */
- #endif /* SCTP_KAME */
- #endif /* SCTP_EMBEDDED_V6_SCOPE */
- *addr = (struct sockaddr *)sin6;
- break;
- }
- #endif
- #if defined(__Userspace__)
- case AF_CONN:
- {
- struct sockaddr_conn *sconn;
- SCTP_MALLOC_SONAME(sconn, struct sockaddr_conn *, sizeof(struct sockaddr_conn));
- if (sconn == NULL) {
- return (ENOMEM);
- }
- sconn->sconn_family = AF_CONN;
- #ifdef HAVE_SCONN_LEN
- sconn->sconn_len = sizeof(struct sockaddr_conn);
- #endif
- sconn->sconn_port = store.sconn.sconn_port;
- sconn->sconn_addr = store.sconn.sconn_addr;
- *addr = (struct sockaddr *)sconn;
- break;
- }
- #endif
- default:
- /* TSNH */
- break;
- }
- return (0);
- }
- #ifdef INET
- int
- #if !defined(__Userspace__)
- sctp_ingetaddr(struct socket *so, struct sockaddr **addr)
- {
- struct sockaddr_in *sin;
- #else
- sctp_ingetaddr(struct socket *so, struct mbuf *nam)
- {
- struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
- #endif
- uint32_t vrf_id;
- struct sctp_inpcb *inp;
- struct sctp_ifa *sctp_ifa;
- /*
- * Do the malloc first in case it blocks.
- */
- #if !defined(__Userspace__)
- SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin);
- if (sin == NULL)
- return (ENOMEM);
- #else
- SCTP_BUF_LEN(nam) = sizeof(*sin);
- memset(sin, 0, sizeof(*sin));
- #endif
- sin->sin_family = AF_INET;
- #ifdef HAVE_SIN_LEN
- sin->sin_len = sizeof(*sin);
- #endif
- inp = (struct sctp_inpcb *)so->so_pcb;
- if (!inp) {
- #if !defined(__Userspace__)
- SCTP_FREE_SONAME(sin);
- #endif
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- return (ECONNRESET);
- }
- SCTP_INP_RLOCK(inp);
- sin->sin_port = inp->sctp_lport;
- if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
- if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
- struct sctp_tcb *stcb;
- struct sockaddr_in *sin_a;
- struct sctp_nets *net;
- int fnd;
- stcb = LIST_FIRST(&inp->sctp_asoc_list);
- if (stcb == NULL) {
- goto notConn;
- }
- fnd = 0;
- sin_a = NULL;
- SCTP_TCB_LOCK(stcb);
- TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
- sin_a = (struct sockaddr_in *)&net->ro._l_addr;
- if (sin_a == NULL)
- /* this will make coverity happy */
- continue;
- if (sin_a->sin_family == AF_INET) {
- fnd = 1;
- break;
- }
- }
- if ((!fnd) || (sin_a == NULL)) {
- /* punt */
- SCTP_TCB_UNLOCK(stcb);
- goto notConn;
- }
- vrf_id = inp->def_vrf_id;
- sctp_ifa = sctp_source_address_selection(inp,
- stcb,
- (sctp_route_t *)&net->ro,
- net, 0, vrf_id);
- if (sctp_ifa) {
- sin->sin_addr = sctp_ifa->address.sin.sin_addr;
- sctp_free_ifa(sctp_ifa);
- }
- SCTP_TCB_UNLOCK(stcb);
- } else {
- /* For the bound all case you get back 0 */
- notConn:
- sin->sin_addr.s_addr = 0;
- }
- } else {
- /* Take the first IPv4 address in the list */
- struct sctp_laddr *laddr;
- int fnd = 0;
- LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
- if (laddr->ifa->address.sa.sa_family == AF_INET) {
- struct sockaddr_in *sin_a;
- sin_a = &laddr->ifa->address.sin;
- sin->sin_addr = sin_a->sin_addr;
- fnd = 1;
- break;
- }
- }
- if (!fnd) {
- #if !defined(__Userspace__)
- SCTP_FREE_SONAME(sin);
- #endif
- SCTP_INP_RUNLOCK(inp);
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
- return (ENOENT);
- }
- }
- SCTP_INP_RUNLOCK(inp);
- #if !defined(__Userspace__)
- (*addr) = (struct sockaddr *)sin;
- #endif
- return (0);
- }
- int
- #if !defined(__Userspace__)
- sctp_peeraddr(struct socket *so, struct sockaddr **addr)
- {
- struct sockaddr_in *sin;
- #else
- sctp_peeraddr(struct socket *so, struct mbuf *nam)
- {
- struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
- #endif
- int fnd;
- struct sockaddr_in *sin_a;
- struct sctp_inpcb *inp;
- struct sctp_tcb *stcb;
- struct sctp_nets *net;
- /* Do the malloc first in case it blocks. */
- #if !defined(__Userspace__)
- SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin);
- if (sin == NULL)
- return (ENOMEM);
- #else
- SCTP_BUF_LEN(nam) = sizeof(*sin);
- memset(sin, 0, sizeof(*sin));
- #endif
- sin->sin_family = AF_INET;
- #ifdef HAVE_SIN_LEN
- sin->sin_len = sizeof(*sin);
- #endif
- inp = (struct sctp_inpcb *)so->so_pcb;
- if ((inp == NULL) ||
- ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) {
- /* UDP type and listeners will drop out here */
- #if !defined(__Userspace__)
- SCTP_FREE_SONAME(sin);
- #endif
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
- return (ENOTCONN);
- }
- SCTP_INP_RLOCK(inp);
- stcb = LIST_FIRST(&inp->sctp_asoc_list);
- if (stcb) {
- SCTP_TCB_LOCK(stcb);
- }
- SCTP_INP_RUNLOCK(inp);
- if (stcb == NULL) {
- #if !defined(__Userspace__)
- SCTP_FREE_SONAME(sin);
- #endif
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- return (ECONNRESET);
- }
- fnd = 0;
- TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
- sin_a = (struct sockaddr_in *)&net->ro._l_addr;
- if (sin_a->sin_family == AF_INET) {
- fnd = 1;
- sin->sin_port = stcb->rport;
- sin->sin_addr = sin_a->sin_addr;
- break;
- }
- }
- SCTP_TCB_UNLOCK(stcb);
- if (!fnd) {
- /* No IPv4 address */
- #if !defined(__Userspace__)
- SCTP_FREE_SONAME(sin);
- #endif
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
- return (ENOENT);
- }
- #if !defined(__Userspace__)
- (*addr) = (struct sockaddr *)sin;
- #endif
- return (0);
- }
- #if !defined(__Userspace__)
- struct pr_usrreqs sctp_usrreqs = {
- #if defined(__FreeBSD__)
- .pru_abort = sctp_abort,
- .pru_accept = sctp_accept,
- .pru_attach = sctp_attach,
- .pru_bind = sctp_bind,
- .pru_connect = sctp_connect,
- .pru_control = in_control,
- .pru_close = sctp_close,
- .pru_detach = sctp_close,
- .pru_sopoll = sopoll_generic,
- .pru_flush = sctp_flush,
- .pru_disconnect = sctp_disconnect,
- .pru_listen = sctp_listen,
- .pru_peeraddr = sctp_peeraddr,
- .pru_send = sctp_sendm,
- .pru_shutdown = sctp_shutdown,
- .pru_sockaddr = sctp_ingetaddr,
- .pru_sosend = sctp_sosend,
- .pru_soreceive = sctp_soreceive
- #elif defined(__APPLE__)
- .pru_abort = sctp_abort,
- .pru_accept = sctp_accept,
- .pru_attach = sctp_attach,
- .pru_bind = sctp_bind,
- .pru_connect = sctp_connect,
- .pru_connect2 = pru_connect2_notsupp,
- .pru_control = in_control,
- .pru_detach = sctp_detach,
- .pru_disconnect = sctp_disconnect,
- .pru_listen = sctp_listen,
- .pru_peeraddr = sctp_peeraddr,
- .pru_rcvd = NULL,
- .pru_rcvoob = pru_rcvoob_notsupp,
- .pru_send = sctp_sendm,
- .pru_sense = pru_sense_null,
- .pru_shutdown = sctp_shutdown,
- .pru_sockaddr = sctp_ingetaddr,
- .pru_sosend = sctp_sosend,
- .pru_soreceive = sctp_soreceive,
- .pru_sopoll = sopoll
- #elif defined(_WIN32) && !defined(__Userspace__)
- sctp_abort,
- sctp_accept,
- sctp_attach,
- sctp_bind,
- sctp_connect,
- pru_connect2_notsupp,
- NULL,
- NULL,
- sctp_disconnect,
- sctp_listen,
- sctp_peeraddr,
- NULL,
- pru_rcvoob_notsupp,
- NULL,
- pru_sense_null,
- sctp_shutdown,
- sctp_flush,
- sctp_ingetaddr,
- sctp_sosend,
- sctp_soreceive,
- sopoll_generic,
- NULL,
- sctp_close
- #endif
- };
- #elif !defined(__Userspace__)
- int
- sctp_usrreq(so, req, m, nam, control)
- struct socket *so;
- int req;
- struct mbuf *m, *nam, *control;
- {
- struct proc *p = curproc;
- int error;
- int family;
- struct sctp_inpcb *inp = (struct sctp_inpcb *)so->so_pcb;
- error = 0;
- family = so->so_proto->pr_domain->dom_family;
- if (req == PRU_CONTROL) {
- switch (family) {
- case PF_INET:
- error = in_control(so, (long)m, (caddr_t)nam,
- (struct ifnet *)control);
- break;
- #ifdef INET6
- case PF_INET6:
- error = in6_control(so, (long)m, (caddr_t)nam,
- (struct ifnet *)control, p);
- break;
- #endif
- default:
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EAFNOSUPPORT);
- error = EAFNOSUPPORT;
- }
- return (error);
- }
- switch (req) {
- case PRU_ATTACH:
- error = sctp_attach(so, family, p);
- break;
- case PRU_DETACH:
- error = sctp_detach(so);
- break;
- case PRU_BIND:
- if (nam == NULL) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- return (EINVAL);
- }
- error = sctp_bind(so, nam, p);
- break;
- case PRU_LISTEN:
- error = sctp_listen(so, p);
- break;
- case PRU_CONNECT:
- if (nam == NULL) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- return (EINVAL);
- }
- error = sctp_connect(so, nam, p);
- break;
- case PRU_DISCONNECT:
- error = sctp_disconnect(so);
- break;
- case PRU_ACCEPT:
- if (nam == NULL) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- return (EINVAL);
- }
- error = sctp_accept(so, nam);
- break;
- case PRU_SHUTDOWN:
- error = sctp_shutdown(so);
- break;
- case PRU_RCVD:
- /*
- * For Open and Net BSD, this is real ugly. The mbuf *nam
- * that is passed (by soreceive()) is the int flags c ast as
- * a (mbuf *) yuck!
- */
- break;
- case PRU_SEND:
- /* Flags are ignored */
- {
- struct sockaddr *addr;
- if (nam == NULL)
- addr = NULL;
- else
- addr = mtod(nam, struct sockaddr *);
- error = sctp_sendm(so, 0, m, addr, control, p);
- }
- break;
- case PRU_ABORT:
- error = sctp_abort(so);
- break;
- case PRU_SENSE:
- error = 0;
- break;
- case PRU_RCVOOB:
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EAFNOSUPPORT);
- error = EAFNOSUPPORT;
- break;
- case PRU_SENDOOB:
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EAFNOSUPPORT);
- error = EAFNOSUPPORT;
- break;
- case PRU_PEERADDR:
- error = sctp_peeraddr(so, nam);
- break;
- case PRU_SOCKADDR:
- error = sctp_ingetaddr(so, nam);
- break;
- case PRU_SLOWTIMO:
- error = 0;
- break;
- default:
- break;
- }
- return (error);
- }
- #endif
- #endif
- #if defined(__Userspace__)
- int
- register_recv_cb(struct socket *so,
- int (*receive_cb)(struct socket *sock, union sctp_sockstore addr, void *data,
- size_t datalen, struct sctp_rcvinfo, int flags, void *ulp_info))
- {
- struct sctp_inpcb *inp;
- inp = (struct sctp_inpcb *) so->so_pcb;
- if (inp == NULL) {
- return (0);
- }
- SCTP_INP_WLOCK(inp);
- inp->recv_callback = receive_cb;
- SCTP_INP_WUNLOCK(inp);
- return (1);
- }
- int
- register_send_cb(struct socket *so, uint32_t sb_threshold, int (*send_cb)(struct socket *sock, uint32_t sb_free, void *ulp_info))
- {
- struct sctp_inpcb *inp;
- inp = (struct sctp_inpcb *) so->so_pcb;
- if (inp == NULL) {
- return (0);
- }
- SCTP_INP_WLOCK(inp);
- inp->send_callback = send_cb;
- inp->send_sb_threshold = sb_threshold;
- SCTP_INP_WUNLOCK(inp);
- /* FIXME change to current amount free. This will be the full buffer
- * the first time this is registered but it could be only a portion
- * of the send buffer if this is called a second time e.g. if the
- * threshold changes.
- */
- return (1);
- }
- int
- register_ulp_info (struct socket *so, void *ulp_info)
- {
- struct sctp_inpcb *inp;
- inp = (struct sctp_inpcb *) so->so_pcb;
- if (inp == NULL) {
- return (0);
- }
- SCTP_INP_WLOCK(inp);
- inp->ulp_info = ulp_info;
- SCTP_INP_WUNLOCK(inp);
- return (1);
- }
- int
- retrieve_ulp_info (struct socket *so, void **pulp_info)
- {
- struct sctp_inpcb *inp;
- if (pulp_info == NULL) {
- return (0);
- }
- inp = (struct sctp_inpcb *) so->so_pcb;
- if (inp == NULL) {
- return (0);
- }
- SCTP_INP_RLOCK(inp);
- *pulp_info = inp->ulp_info;
- SCTP_INP_RUNLOCK(inp);
- return (1);
- }
- #endif
|