精华内容
下载资源
问答
  • CVPR_2019_Chu_Spot_and_Learn_A_Maximum-Entropy_Patch_Sampler_for_Few-Shot_Image PPT讲解
  • CVPR_2019_Chu_Spot_and_Learn_A_Maximum-Entropy_Patch_Sampler_for_Few-Shot_Image 讲稿(配合PPT)
  • 核心思想   本文提出一种基于最大熵图块采样算法的强化学习模型来解决小样本学习问题。作者首先提出常见的目标分类网络都是把一整张图片作为输入,进行特征提取,然后分类。而人类在观察事物的时候通常都会把注意...

    小样本学习&元学习经典论文整理||持续更新

    核心思想

      本文提出一种基于最大熵图块采样算法的强化学习模型来解决小样本学习问题。作者首先提出常见的目标分类网络都是把一整张图片作为输入,进行特征提取,然后分类。而人类在观察事物的时候通常都会把注意力集中在部分感兴趣的区域,也就是所谓的注意力机制,而且当我们第二次看一个物体时,我们的注意力会沿着一定的轨迹移动,也就是说我们每次观察物体的一部分图块,经过多次观察后识别该物体。本文正是利用这一思想,将一幅图片分割成多个图块,组成一个图片序列,依次输入到一个强化学习网络中,经过多次观察后给出分类结果。网络的结构如下图所示
    在这里插入图片描述
      每个图块 p i p_i pi都先经过一个图像特征提取网络 f e f_e fe得到对应的特征向量 e i e_i ei,然后与上一阶段的状态输出 s i − 1 s_{i-1} si1和环境信息 c i − 1 c_{i-1} ci1一起进入状态编码器 f s f_s fs,得到当前时刻对应的状态输出 s i s_i si。这一状态有两个用途,一方面作为输入传递到下一时刻的状态编码器,另一方面输入到最大熵图块采样器(Maximum Entropy Sampler)提取下一个阶段的图块 p i + 1 p_{i+1} pi+1。简单点说,这个最大熵图块采样器就是以原图 x x x和当前时刻的状态信息 s i s_i si作为输入,输出下一时刻的动作信息 a i a_i ai(也就是图块的坐标)。但具体来说,最大熵图块采样器由两个部分组成:Q函数 f Q f_Q fQ和采样策略 π θ \pi_{\theta} πθ,其中 f Q f_Q fQ用来评价当前采取动作有多么“好”,而 π θ \pi_{\theta} πθ会输出下一时刻动作信息 a i a_i ai和原图 x x x对应的特征信息 g g g,而这两部分信息又进入动作环境编码器 f a f_{a} fa用于输出当前时刻的环境信息 c i c_i ci。最后经过 N N N次观察之后,输出状态 s N s_N sN并利用分类器 f c f_c fc得到最终的预测类别标签 y ^ \hat{y} y^。整个过程看似复杂,但其实还是比较常规的强化学习流程,问题的难点在于最大熵图块采样器是如何选择出最合适的图块的?
      作者提出了一种基于最大熵的强化学习算法用于输出采样策略,该算法的优化目标如下
    在这里插入图片描述
    不仅要求最大化回报函数 r t r_t rt,并且在给定状态 s s s的同时最大化策略的熵 H ( π ( ⋅ ∣ s ) ) H(\pi(\cdot|s)) H(π(s)),该问题可采用柔性Q学习的方法来解决
    在这里插入图片描述
    式中 Q s o f t ( s t , a t ) Q_{soft}(s_t,a_t) Qsoft(st,at)表示Q函数, V s o f t V_{soft} Vsoft表示价值函数,用于评定状态的价值,而最大熵策略如下
    在这里插入图片描述
      基于上述的研究,本文提出一种正负样本采样的策略,所谓正样本就是指在感兴趣区域内的图块,而负样本是指背景处的图块。相应的负样本采样策略标识如下
    在这里插入图片描述
    可以看做是正样本采样策略的相反数。每次正向过程(处理一张图片)都会随机选择是采用正样本采样策略还是负样本采样策略,如果是正样本采样策率则希望分类器输出的预测结果是对应的目标物体,如果是负样本采样策略则希望分类器输出的预测结果是背景,根据这一要求设计了回报函数
    在这里插入图片描述
      作者指出采用这一采样策略有双重优势:第一,编码器能够“看到”并学习为错误选择的图块进行编码;第二,这有助于为不同的动作提供不同价值,避免了无论采用何种动作其价值得分都几乎相同的情况。

    实现过程

    网络结构

      图像特征提取器 f e f_e fe是一个CNN网络,状态编码器 f s f_s fs是一个RNN网络,Q函数 f Q f_Q fQ和采样策略 π θ \pi_{\theta} πθ的结构完全相同,都是一个带有全连接层的小型CNN,动作环境编码器 f a f_a fa和分类器 f c f_c fc结构未介绍。

    损失函数

      分类损失根据采取不同的采样策略,计算正负样本对应的损失
    在这里插入图片描述
    M 1 M_1 M1 M 2 M_2 M2分别表示两种采样模式, j j j表示第 j j j幅图片。图像特征提取器 f e f_e fe,状态编码器 f s f_s fs,动作环境编码器 f a f_a fa和分类器 f c f_c fc利用该损失进行更新。

    训练策略

      整个网络的训练过程如下
    在这里插入图片描述

    创新点

    • 通过将图片分割成图块序列,采用深度强化学习的方式,实现小样本分类任务
    • 设计了最大熵图块采样策略

    算法评价

      本文采用深度强化学习的方式实现小样本分类任务,在本质上可以看做是一种基于数据增强的方法,只不过作者是将一幅图片分割成若干个图块,并组成图块序列进行学习。这一方法能够引导网络有针对性的选取图片中有价值的部分进行观察,而不需要在背景区域浪费精力,这在一定程度上提高了模型的学习效率,使得其在少量样本的情况下就能够有效学习分类方法。根据实验结果来看,该算法效果改进不大,但作为一种全新的思路和结构,该算法仍具有进一步研究和改进的价值。

    如果大家对于深度学习与计算机视觉领域感兴趣,希望获得更多的知识分享与最新的论文解读,欢迎关注我的个人公众号“深视”。在这里插入图片描述

    展开全文
  • 文章目录Spot the Difference by Object Detection1. Introduction2. Q&A3. Future Work Spot the Difference by Object Detection 由清华大学和JD Group联合产出的技术报告,挂在Arxiv 2018上。感谢作者的分享...

    Spot the Difference by Object Detection

    由清华大学和JD Group联合产出的技术报告,挂在Arxiv 2018上。感谢作者的分享。

    1. Introduction

      文章需要是想找出两张图书封面图片中不同的区域 (change detection),其中一张图片为数字设计版,另一张是传送带上方相机拍摄的图片。图书封面的数字设计版会经常改变,但是销售商打印图书的时候封面数据库中图片可能没有更新,该文章设计了一套设备和对应的算法,提出的方法可以自动核对数字版封面设计与印刷版封面是否相同,这样可以节省人工核对消耗的时间和人力。
      传统的变化区域检测可以使用验证算法实现,基于验证算法的变化区域检测通常需要借助一些关键特征,例如人脸关键点。因为图书封面不存在关键特征。所以不能使用验证算法框架。视频中的变化检测通常需要借助图像序列。遥感图像的变化检测通常需要先对图像进行分割和分类。文本图像的变化检测则需要先检测出图像中的文本。综上,变化区域检测用于不同场景就有不同算法,但这些算法不适用于图书封面变化区域检测。大家来找茬游戏是一种理想化的变化区域检测,但是现实场景更复杂,算法需要在不同光照、色彩及其他噪声环境下保持鲁棒。
      因此,本文提出了基于物体检测算法的变化区域检测,算法可以学习到两张图片之间的关系,并且可以判断候选框内区域在两张图片内是否相同。算法流程如下:第一步是图像对齐,两张图像中包含相机拍摄的图像,因此存在位置偏移,需要对图像进行对齐;第二步是合成训练图像,通过Figure 4中三种方式进行合成,这一步还有个关键的作用是产生物体检测中的GT;第三步是图片的通道堆叠,即两张RGB3通道图像通过通道堆叠变为6通道;第四步是网络训练,网络结构包含主体CNN网络,RPN网络和分类器。RPN网络产生bounding boxes,然后借助分类器判断候选框是否为前景,该概率即为该区域存在差异的概率。
    图1 训练数据生成
      该算法相比传统的验证算法可以得到更好的性能,相同性能下也可以得到更快的速度。并且训练数据只依赖于一对样本之间的标签,而不需要单独标注候选框。

    2. Q&A

      当时看文章时候还是有点问题的,主要是关于文章说不需要进行Ground-truth的标注,我当时的疑问是那么GT是怎么产生的。后来,在知乎回答上偶然看到了文章二作Yun Ye的一个回答,就在回答下面进行了交流:
    Q1: 文章3.2节倒数第二段在说foreground和background。既然没有bounding box的话,那么foreground和background是怎么确定的呢?(我当时问错了,想问的是既然没有ground-truth的标注,前景和背景是怎么确定的)
      对于这个问题我自己能说服我自己的理解是,文章中说了数据合成的时候是用了一个patch去复制粘贴到别的地方等其他两个操作,在这两个操作中实际就产生了一个类似于ground-truth的框,不知道理解的是否正确?如果理解的是正确的话,那么不是合成图像的时候,前景和背景又是怎么确定的呢?
    A1: bounding box是生成的,我们当时的方法比较粗暴,直接在一个图片上生成一个bounding box将其内部图像替换成另一个domain的随机patch,就得到一个difference roi作为GT,3.2部分以及fig 4有详述。

    Q2: 文章中使用了RPN网络,RPN是根据最后的特征图生成anchor boxes。我看Faster RCNN里面,RPN产生proposal之后,会经过一个NMS进行框筛除。那么您的文章中,有类似的操作吗?如果有的话,NMS里面有一个与Groundtruth去求IOU的过程,那么又回到第一个问题中,GT是怎么确定的呢?
    A2: 可以有这一步,不过具体到我们文章中的那种需求,就是图书封面差异,是不需要的,因为如果IOU较大就直接标注成一个了。

    Q3: 我理解的网络结构最后的分类器是对于RPN产生的proposal的分类,如果是正确的话,那么图9中给出的概率是什么呢?是分成same或者different的概率吗?如果是这么个二分类的话,那么是如何定义RPN产生的proposal的标签的呢?
    A3: 你的理解是对的,其实就是一个background/object的二分类检测问题,核心在于将判断图像差异转化为difference region detection,换成任何一种检测框架按理说都可以,产生标签因为是synthetic sample,所以自然就有标签了。

       感谢Yun Ye的回答。

    3. Future Work

      这篇文章感觉不是个很典型的CV类的文章,作者自己也说了只是技术报告。该文章是很好的技术报告,很详细易懂。如果非要鸡蛋里挑骨头,假设文章想投CV类会议,我个人觉得文章方面有以下几点可以改进(个人观点,欢迎友好交流,喷子绕行):
    (1)文章有个较大的问题是没有公开数据集的比较结果,并且也没有量化的比较结果,当然Figure 8里有一个AUC指标,但是像传统CV类文章中数字化表格的结果可能更显著一些。
    (2)文章Algorithm需要再整理一下。这篇文章题目是说通过物体检测方法去做变化区域检测。那么在Algorithm里可能需要重点突出一下怎么通过物体检测方法去做,相关流程可以一带而过。文中的Algorithm里把重点放在了合成数据,我第一遍看文章是有点疑惑的,感觉这块也没啥东西啊,为啥花那么大篇幅去说呢?跟作者交流之后才知道,这块确实很重要,因为文章的基本结构都是已有技术,那么如何产生GT而避免人为标注就是该文章一个重要工作。而数据合成的过程也是产生GT的过程。所以我觉得可以在3.2一开始说这块工作motivation的时候就跟物体检测联系上,而不是从收集数据角度去说。
    (3)文中方法和其它方法对比的时候,4.3.5中有一句话是说其它传统方法只能找到global的区别,而文中方法可以找到local的区别,其实理解起来没有难度。但是光靠Figure 8不能很充分的解释这个论点。我觉得可以增加一些传统方法的可视化结果,这样方便更好的对比。
    (4)文章有少数语病和拼写错误。例如:4.3.5节中有:”The relation between two images are leaned from the beginning”。

    展开全文
  • (The first version of a patch need not say "v1", just [PATCH] is sufficient.) For patch series, the version applies to the whole series -- even if you only change one patch, you resend the entire ...

    http://wiki.qemu.org/Contribute/SubmitAPatch

    QEMU welcomes contributions of code (either fixing bugs or adding new functionality). However, we get a lot of patches, and so we have some guidelines about submitting patches. If you follow these, you'll help make our task of code review easier and your patch is likely to be committed faster.


    All contributions to QEMU must be sent as patches to the qemu-develmailing list. Patch contributions should not be posted on the bug tracker, posted on forums, or externally hosted and linked to.

    You do not have to subscribe to post (list policy is to reply-to-all to preserve CCs and keep non-subscribers in the loop on the threads they start), although you may find it easier as a subscriber to pick up good ideas from other posts. If you do subscribe, be prepared for a high volume of email, often over one thousand messages in a week. The list is moderated; first-time posts from an email address (whether or not you subscribed) may be subject to some delay while waiting for a moderator to whitelist your address.

    Send patches to the mailing list and CC the relevant maintainer -- look in the MAINTAINERS file to find out who that is. Also try using scripts/getmaintainer.pl from the repository for learning the most common committers for the files you touched.

    Send patches inline so they are easy to reply to with review comments. Do not put patches in attachments.

    Use the right patch format. git format-patch will produce patch emails in the right format (check the documentation to find out how to drive it). You can then edit the cover letter before usinggit send-email to mail the files to the mailing list. (We recommend git send-email because mail clients often mangle patches by wrapping long lines or messing up whitespace. Some distributions do not include send-email in a default install of git; you may need to download additional packages, such as 'git-email' on Fedora-based systems.) Patch series need a cover letter, with shallow threading (all patches in the series are in-reply-to the cover letter, but not to each other); single unrelated patches do not need a cover letter (but if you do send a cover letter, use --numbered so the cover and the patch have distinct subject lines). Patches are easier to find if they start a new top-level thread, rather than being buried in-reply-to another existing thread.

    Patch emails must include a Signed-off-by: line. For more information seeSubmittingPatches 1.12. This is vital or we will not be able to apply your patch! Please use your real name to sign a patch (not an alias name).

    Make the cover letter meaningful. When reviewers don't know your goal at the start of their review, they may object to early changes that don't make sense until the end of the series, because they do not have enough context yet at that point of their review. A series where the goal is unclear also risks a higher number of review-fix cycles because the reviewers haven't bought into the idea yet. It is in everyone's interest to explain the goal in the cover letter. Then the patches get reviewed more smoothly and merged faster. Make sure your cover letter includes a diffstat of changes made over the entire series, as it is easier for a potential reviewer to check your cover letter than it is to check every letter in the series when determining if the series touches files they are interested in.

    Follow the coding style and run scripts/checkpatch.pl <patchfile> before submitting. (Be aware that checkpatch.pl is not infallible, though, especially where C preprocessor macros are involved; use some common sense too.) See also:

    Correct English is appreciated. If you are not sure, codespell or other programs help finding the most common spelling mistakes in code and documentation.

    Patches should be against current git master. There's no point submitting a patch which is based on a released version of QEMU because development will have moved on from then and it probably won't even apply to master. We only apply selected bugfixes to release branches and then only as backports once the code has gone into master.

    Split up longer patches into a patch series of logical code changes. Each change should compile and execute successfully. For instance, don't add a file to the makefile in patch one and then add the file itself in patch two. (This rule is here so that people can later use tools like git bisect without hitting points in the commit history where QEMU doesn't work for reasons unrelated to the bug they're chasing.) Put documentation first, not last, so that someone reading the series can do a clean-room evaluation of the documentation, then validate that the code matched the documentation. A commit message that mentions "Also, ..." is often a good candidate for splitting into multiple patches. For more thoughts on properly splitting patches and writing good commit messages, seethis advice from OpenStack.

    Make code motion patches easy to review. If a series requires large blocks of code motion, there are tricks for making the refactoring easier to review. Split up the series so that semantic changes (or even function renames) are done in a separate patch from the raw code motion. Use a one-time setup of git config diff.renames true; git config diff.algorithm patience. The 'diff.renames' property ensures file rename patches will be given in a more compact representation that focuses only on the differences across the file rename, instead of showing the entire old file as a deletion and the new file as an insertion. Meanwhile, the 'diff.algorithm' property ensures that extracting a non-contiguous subset of one file into a new file, but where all extracted parts occur in the same order both before and after the patch, will reduce churn in trying to treat unrelated } lines in the original file as separating hunks of changes. Ideally, a code motion patch can be reviewed by doinggit format-patch --stdout -1 > patch; diff -u <(sed -n 's/^-//p' patch) <(sed -n 's/^\+//p' patch), to focus on the few changes that weren't wholesale code motion.

    Don't include irrelevant changes. In particular, don't include formatting, coding style or whitespace changes to bits of code that would otherwise not be touched by the patch. (It's OK to fix coding style issues in the immediate area (few lines) of the lines you're changing.) If you think a section of code really does need a reindent or other large-scale style fix, submit this as a separate patch which makes no semantic changes; don't put it in the same patch as your bug fix.

    For smaller patches in less frequently changed areas of QEMU, consider using thetrivial patches process.

    Write a good commit message. QEMU follows the usual standard for git commit messages: the first line (which becomes the email subject line) is "subsystem: single line summary of change". Whether the "single line summary of change" starts with a capital is a matter of taste, but we prefer that the summary does not end in ".". Look atgit short-log 30 for an idea of sample subject lines. Then there is a blank line and a more detailed description of the patch, another blank and your Signed-off-by: line. The body of the commit message is a good place to document why your change is important. Don't include comments like "This is a suggestion for fixing this bug" (they can go below the "---" line in the email so they don't go into the final commit message). Make sure the body of the commit message can be read in isolation even if the reader's mailer displays the subject line some distance apart (that is, a body that starts with "... so that" as a continuation of the subject line is harder to follow).

    Stay around to fix problems raised in code review. Not many patches get into QEMU straight away -- it is quite common that developers will identify bugs, or suggest a cleaner approach, or even just point out code style issues or commit message typos. You'll need to respond to these, and then send a second version of your patches with the issues fixed. This takes a little time and effort on your part, but if you don't do it then your changes will never get into QEMU. It's also just polite -- it is quite disheartening for a developer to spend time reviewing your code and suggesting improvements, only to find that you're not going to do anything further and it was all wasted effort.

    When replying to comments on your patches reply to all and not just the sender -- keeping discussion on the mailing list means everybody can follow it.

    Pay attention to review comments. Someone took their time to review your work, and it pays to respect that effort; repeatedly submitting a series without addressing all comments from the previous round tends to alienate reviewers and stall your patch. Reviewers aren't always perfect, so it is okay if you want to argue that your code was correct in the first place instead of blindly doing everything the reviewer asked. On the other hand, if someone pointed out a potential issue during review, then even if your code turns out to be correct, it's probably a sign that you should improve your commit message and/or comments in the code explaining why the code is correct.

    If you fix issues that are raised during review resend the entire patch series not just the one patch that was changed. This allows maintainers to easily apply the fixed series without having to manually identify which patches are relevant. Send the new version as a complete fresh email or series of emails -- don't try to make it a followup to version 1. (This helps automatic patch email handling tools distinguish between v1 and v2 emails.)

    When resending patches add a v2/v3 suffix (eg [PATCH v2]). This means people can easily identify whether they're looking at the most recent version. (The first version of a patch need not say "v1", just [PATCH] is sufficient.) For patch series, the version applies to the whole series -- even if you only change one patch, you resend the entire series and mark it as "v2". Don't try to track versions of different patches in the series separately.git format-patch and git send-email both understand the -v2 option to make this easier. Send each new revision as a new top-level thread, rather than burying it in-reply-to an earlier revision, as many reviewers are not looking inside deep threads for new patches.

    For later versions of patches include a summary of changes from previous versions, but not in the commit message itself. In an email formatted as a git patch, the commit message is the part above the "---" line, and this will go into the git changelog when the patch is committed. This part should be a self-contained description of what this version of the patch does, written to make sense to anybody who comes back to look at this commit in git in six months' time. The part below the "---" line and above the patch proper (git format-patch puts the diffstat here) is a good place to put remarks for people reading the patch email, and this is where the "changes since previous version" summary belongs. Thegit-publish script can help with tracking a good summary across versions. Also, thegit-backport-diff script can help focus reviewers on what changed between revisions.

    Use RFC suffix if needed (eg [PATCH RFC v2]). git format-patch --subject-prefix=RFC can help.

    "RFC" means "Request For Comments" and is a statement that you don'tintend for your patchset to be applied to master, but would like somereview on it anyway. Reasons for doing this include:

    • the patch depends on some pending kernel changes which haven't yet been accepted, so the QEMU patch series is blocked until that dependency has been dealt with, but is worth reviewing anyway
    • the patch set is not finished yet (perhaps it doesn't cover all use cases or work with all targets) but you want early review of a major API change or design structure before continuing

    In general, since it's asking other people to do review workon a patchset that the submitter themselves is saying shouldn'tbe applied, it's best to:

    • use it sparingly
    • in the cover letter, be clear about why a patch is an RFC, what areas of the patchset you're looking for review on, and why reviewers should care

    Proper use of Reviewed-by: tags can aid review. When reviewing a large series, a reviewer can reply to some of the patches with a Reviewed-by tag, stating that they are happy with that patch in isolation (sometimes conditional on minor cleanup, like fixing whitespace, that doesn't affect code content). You should then update those commit messages by hand to include the Reviewed-by tag, so that in the next revision, reviewers can spot which patches were already clean from the previous round. Conversely, if you significantly modify a patch that was previously reviewed, remove the reviewed-by tag out of the commit message, as well as listing the changes from the previous version, to make it easier to focus a reviewer's attention to your changes.

    If your patch seems to have been ignored you should "ping" it after a week or two, by sending an email as a reply-to-all to the patch mail, including the word "ping" and ideally also a link to the page for the patch onpatchwork or GMANE. It's worth double-checking for reasons why your patch might have been ignored (forgot to CC the maintainer? annoyed people by failing to respond to review comments on an earlier version?), but often for less-maintained areas of QEMU patches do just slip through the cracks. If your ping is also ignored, ping again after another week or so. As the submitter, you are the person with the most motivation to get your patch applied, so you have to be persistent.

    Is my patch in? Once your patch has had enough review on list, the maintainer for that area of code will send notification to the list that they are including your patch in a particular staging branch. Periodically, the maintainer then sends a pull request for aggregating topic branches into mainline qemu. Generally, you do not need to send a pull request unless you have contributed enough patches to become a maintainer over a particular section of code. Maintainers may further modify your commit, by resolving simple merge conflicts or fixing minor typos pointed out during review, but will always add a Signed-off-by line in addition to yours, indicating that it went through their tree. Occasionally, the maintainer's pull request may hit more difficult merge conflicts, where you may be requested to help rebase and resolve the problems. It may take a couple of weeks between when your patch first had a positive review to when it finally lands in qemu.git; release cycle freezes may extend that time even longer.

    Return the favor. Peer review only works if everyone chips in a bit of review time. If everyone submitted more patches than they reviewed, we would have a patch backlog. A good goal is to try to review at least as many patches from others as what you submit. Don't worry if you don't know the code base as well as a maintainer; it's perfectly fine to admit when your review is weak because you are unfamiliar with the code.


    展开全文
  • Patch android wifi to enable IBSS/WEP support

    千次阅读 2013-03-22 16:49:57
    Only To developers. wpa_supplicant 0.8.X, wpa_supplicant_drvier nl80211, wifi chip bcm4330. 转载请注明出处:... Patch 修改Settings/wifi中的代码以显示[IBSS][WEP

    Only To developers.

    wpa_supplicant 0.8.X, wpa_supplicant_drvier nl80211, wifi chip bcm4330.

    转载请注明出处:http://blog.csdn.net/zirconsdu/article/details/8571260 

    Patch

    1. 修改Settings/wifi中的代码以显示[IBSS][WEP] ssid或没有名字的ssid.

    UI显示SSID列表时,会获取从wpa_supplicant最近扫描到的APswpa_supplicant的输出扫描结果并没有过滤掉IBSS或隐藏的APs

    In constructAccessPoints()@WifiSettings.java,

            final List<ScanResult> results = mWifiManager.getScanResults(); //同步操作

            if (results != null) {

                for (ScanResult result : results) {

                    // Ignore hidden and ad-hoc networks.

     

                   if (result.SSID == null || result.SSID.length() == 0 /* || result.capabilities.contains("[IBSS]")*/  ) {

                       continue;

                   }

    1. 修改wpa_supplicant,设置IBSS spot工作模式配置和连接时避免跳过

    当第一次点击连接IBSS/ADHOC AP时,会弹出输入密码对话框,wpa_supplicant会将AP configuration信息保存到wpa_supplicant.conf中;此时保存该IBSS AP的工作模式为mode=1,保存到wpa_supplicant.conf中。

    In  wpa_supplicant_ctrl_iface_set_network(…)@ctrl_iface.c

    static int wpa_supplicant_ctrl_iface_set_network(

                    struct wpa_supplicant *wpa_s, char *cmd)

    {

                    int id;

                    struct wpa_ssid *ssid;

                    char *name, *value;

                    struct wpa_bss *bss;

     

                    /* cmd: "<network id> <variable name> <value>" */

                    name = os_strchr(cmd, ' ');

                    if (name == NULL)

                                    return -1;

                    *name++ = '\0';

     

                    value = os_strchr(name, ' ');

                    if (value == NULL)

                                    return -1;

                    *value++ = '\0';

     

                    id = atoi(cmd);

                    wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_NETWORK id=%d name='%s'",

                                       id, name);

     

                    wpa_hexdump_ascii_key(MSG_INFO, "CTRL_IFACE: value",

                                                          (u8 *) value, os_strlen(value));

     

                    ssid = wpa_config_get_network(wpa_s->conf, id);

                    if (ssid == NULL) {

                                    wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "

                                                       "id=%d", id);

                                    return -1;

                    }

     

                    if (wpa_config_set(ssid, name, value, 0) < 0) {

                                    wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set network "

                                                       "variable '%s'", name);

                                    return -1;

                    }

                   

                   if (os_strcmp(name, "ssid") == 0) {

                                   wpa_printf(MSG_DEBUG, "CTRL_IFACE: check if hook %s ssid->mode to 1(IBSS) ", value);

                                   

                                   bss = NULL;

                                   dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {

                                                   if(bss->ssid) {

                                                   wpa_printf(MSG_DEBUG, "CTRL_IFACE: bss ssid foreach '%s'", bss->ssid);

                                                   if(os_strncmp(bss->ssid, value+1, os_strlen(bss->ssid))==0 && (bss->caps & IEEE80211_CAP_IBSS))

                                                   {

                                                                   wpa_printf(MSG_DEBUG, "CTRL_IFACE: find matched ssid for '%d', try to set IBSS mode", id);

                                                                   if (wpa_config_set(ssid, "mode", "1", 0) < 0) {

                                                                                   wpa_printf(MSG_DEBUG, "CTRL_IFACE: failed to set IBSS mode on '%d'", id);

                                                                                   return -1;

                                                                   }

                                                                   wpa_printf(MSG_DEBUG, "CTRL_IFACE: hook to set IBSS mode on '%d' successfully", id);

                                                   }

                                                   }

                                                   /* loop all bssid for the ssid */

                                   }

                   }

    当长按AP点击连接时,wpa_supplicant会将AP和扫描结果与配置库中的AP比对,如果为IBSS,则被跳过。  

    wpa_scan_res_match(…)@events.c中,修改

                                    if (bss->caps & IEEE80211_CAP_IBSS) {

                                                    wpa_dbg(wpa_s, MSG_DEBUG, "   skip - IBSS (adhoc) "

                                                                    "network");

                                                    continue;

                                    }

                                    if ((bss->caps & IEEE80211_CAP_IBSS)&& (ssid->mode!=IEEE80211_MODE_IBSS)) {

                                                    wpa_dbg(wpa_s, MSG_DEBUG, "   skip - IBSS (adhoc) "

                                                                    "network");

                                                    continue;

                                    }

    1. linux内核nl80211驱动和bcm4330驱动

    wpa_driver_nl80211_ibss发送NL80211_CMD_SET_INTERFACE NL80211_CMD_JOIN_IBSSlinux nl80211 driver交给bcm4330 common driver处理。

    NL80211_CMD_SET_INTERFACE投递给wl_cfg80211_change_virtual_iface时,需要切换bcm4330固件工作模式到IBSS模式;增加网卡工作模式INFRA/ADHOC设置代码如下,

    In wl_cfg80211_change_virtual_iface(…) @ wl_cfg80211.c

                    if (ap) {

                                   wl_set_mode_by_netdev(wl, ndev, mode);

                                    if (wl->p2p_supported && wl->p2p->vif_created) {

                                    ……………………………….

                                    }

                   } else {

                                   wl_set_mode_by_netdev(wl, ndev, mode);

                                    printk("try to set infra in wl_cfg80211_change_virtual_iface: value=%d, mode=%s", infra, (infra==1)?"INFRA":"ADHOC");

                                   err = wldev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(infra), true);

                                    if (unlikely(err)) {

                                                    WL_ERR(("WLC_SET_INFRA mode failed with error (%d)\n", err));

                                                    return err;

                                    }

                    }

    NL80211_CMD_JOIN_IBSS投递给wl_cfg80211_join_ibss时,修改代码如下,

    In wl_cfg80211_join_ibss @ wl_cfg80211.c

    static s32

    wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,

                    struct cfg80211_ibss_params *params)

    {

                    struct wl_priv *wl = wiphy_priv(wiphy);

                    struct cfg80211_bss *bss;

                    struct ieee80211_channel *chan;

                    struct wl_join_params join_params;

                    struct cfg80211_ssid ssid;

                    s32 scan_retry = 0;

                    s32 err = 0;

     

                    //WL_TRACE(("In\n"));

                    printk("In wl_cfg80211_join_ibss\n");

                    CHECK_SYS_UP(wl);

                   if (params->bssid) {

    //                           WL_ERR(("Invalid bssid\n"));

                                   printk("wl_cfg80211_join_ibss: with bssid, overwrite EOPNOTSUPP originally\n");

    //                           return -EOPNOTSUPP;

                   }

                   bss = cfg80211_get_ibss(wiphy, NULL, params->ssid, params->ssid_len);

     

                    /* scarely bss==null */

                    if (!bss) {

                                    memcpy(ssid.ssid, params->ssid, params->ssid_len);

                                    ssid.ssid_len = params->ssid_len;

                                    do {

                                                    if (unlikely

                                                                    (__wl_cfg80211_scan(wiphy, dev, NULL, &ssid) ==

                                                                     -EBUSY)) {

                                                                    wl_delay(150);

                                                    } else {

                                                                    break;

                                                    }

                                    } while (++scan_retry < WL_SCAN_RETRY_MAX);

                                    /* to allow scan_inform to propagate to cfg80211 plane */

                                    if (rtnl_is_locked()) {

                                                    rtnl_unlock();

                                                    rollback_lock = true;

                                    }

     

                                    /* wait 4 secons till scan done.... */

                                    schedule_timeout_interruptible(4 * HZ);

                                    if (rollback_lock)

                                                    rtnl_lock();

                                    bss = cfg80211_get_ibss(wiphy, NULL,

                                                    params->ssid, params->ssid_len);

                    }

     

                    if (bss) {

                                    wl->ibss_starter = false;

                                    //WL_DBG(("Found IBSS\n"));

                                    printk("wl_cfg80211_join_ibss: Found IBSS\n");

                    } else {

                                    wl->ibss_starter = true;

                                    printk("wl_cfg80211_join_ibss: Still not Found IBSS\n");

                    }

                    

                   chan = params->channel;

                   if (chan) { 

                                   wl->channel = ieee80211_frequency_to_channel(chan->center_freq);

                   } else {

                                   printk("wl_cfg80211_join_ibss: with zero wl->channel\n");

                                   wl->channel = 0;

                   }

                   

                   /*

                    * Join with specific BSSID and cached SSID

                    * If SSID is zero join based on BSSID only

                    */

                   memset(&join_params, 0, sizeof(join_params));

                   memcpy((void *)join_params.ssid.SSID, (void *)params->ssid, params->ssid_len);

                   join_params.ssid.SSID_len = htod32(params->ssid_len);

                   wl_update_prof(wl, dev, NULL, &join_params.ssid, WL_PROF_SSID);

                   

                   if (params->bssid) {

                                   memcpy(&join_params.params.bssid, params->bssid, ETHER_ADDR_LEN);

                   } else {

                                   memset(&join_params.params.bssid, 0, ETHER_ADDR_LEN);

                   }

                   wl_update_prof(wl, dev, NULL, &join_params.params.bssid, WL_PROF_BSSID);

     

                   printk("wl_cfg80211_join_ibss: before wldev_ioctl\n");

                  err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, sizeof(join_params), false);  // no need to change false to true

                   if (unlikely(err)) {

                                   WL_ERR(("Error (%d)\n", err));

                                   printk("wl_cfg80211_join_ibss:: Error (%d)\n", err);

                                   return err;

                   }

                      return err;

    }

    In __wl_cfg80211_scan(…) @ wl_cfg80211.c

                    if (request) {                      /* scan bss */

    改为

                    if (request && !wl_is_ibssmode(wl, ndev)) {    /* scan bss */

     

    增加函数wl_inform_ibss  @ wl_cfg80211.c

    static s32

    wl_inform_ibss(struct wl_priv *wl, struct net_device *dev, const u8 *bssid)

    {

                    struct wiphy *wiphy = wl_to_wiphy(wl);

                    struct ieee80211_channel *notify_channel;

                    struct wl_bss_info *bi = NULL;

                    struct ieee80211_supported_band *band;

                    u8 *buf = NULL;

                    s32 err = 0;

                    u16 channel;

                    u32 freq;

                    u64 notify_timestamp;

                    u16 notify_capability;

                    u16 notify_interval;

                    u8 *notify_ie;

                    size_t notify_ielen;

                    s32 notify_signal;

     

                    printk("Enter wl_inform_ibss\n");

     

                    buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);

                    if (buf == NULL) {

                                    WL_ERR(("kzalloc() failed\n"));

                                    err = -ENOMEM;

                                    goto CleanUp;

                    }

     

                    *(u32 *)buf = htod32(WL_BSS_INFO_MAX);

     

                    err = wldev_ioctl(dev, WLC_GET_BSS_INFO, buf, WL_BSS_INFO_MAX, false);

                    if (unlikely(err)) {

                                    WL_ERR(("WLC_GET_BSS_INFO failed: %d\n", err));

                                    goto CleanUp;

                    }

     

                    bi = (wl_bss_info_t *)(buf + 4);

     

                    channel = bi->ctl_ch ? bi->ctl_ch :

                                                                    CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));

     

                    if (channel <= CH_MAX_2G_CHANNEL)

                                    band = wiphy->bands[IEEE80211_BAND_2GHZ];

                    else

                                    band = wiphy->bands[IEEE80211_BAND_5GHZ];

     

                    freq = ieee80211_channel_to_frequency(channel, band->band);

                    notify_channel = ieee80211_get_channel(wiphy, freq);

     

                    notify_timestamp = jiffies_to_msecs(jiffies)*1000; /* uSec */

                    notify_capability = le16_to_cpu(bi->capability);

                    notify_interval = le16_to_cpu(bi->beacon_period);

                    notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);

                    notify_ielen = le16_to_cpu(bi->ie_length);

                    notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;

     

                    WL_DBG(("channel: %d(%d)\n", channel, freq));

                    WL_DBG(("capability: %X\n", notify_capability));

                    WL_DBG(("beacon interval: %d\n", notify_interval));

                    WL_DBG(("signal: %d\n", notify_signal));

                    WL_DBG(("notify_timestamp: %#018llx\n", notify_timestamp));

     

                    cfg80211_inform_bss(wiphy, notify_channel, bssid,

                                    notify_timestamp, notify_capability, notify_interval,

                                    notify_ie, notify_ielen, notify_signal, GFP_KERNEL);

     

    CleanUp:

                    kfree(buf);

                    printk("Exit wl_inform_ibss\n");

                    return err;

    }

    当得到WLC_E_LINK成功和WLC_E_SET_SSID成功时,通知用户态。

    In wl_notify_connect_status(…)@ wl_cfg80211.c

                    } else {

                                    WL_DBG(("wl_notify_connect_status : event %d status : %d \n",

                                    ntoh32(e->event_type), ntoh32(e->status)));

                                    

                                    if (wl_is_linkup(wl, e, ndev)) {

                                                    wl_link_up(wl);

                                                    act = true;

                                                   wl_update_prof(wl, ndev, e, &act, WL_PROF_ACT);

                                                   wl_update_prof(wl, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID);

                                                   if (wl_is_ibssmode(wl, ndev)) {

                                                                   printk("linkup in ibss mode, before to call cfg80211_ibss_joined\n");

                                                                   wl_inform_ibss(wl, ndev, (s8 *)&e->addr);

                                                                   cfg80211_ibss_joined(ndev, (s8 *)&e->addr,

                                                                                   GFP_KERNEL);

                                                                    WL_DBG(("joined in IBSS network\n"));

                                                    } else {

                                                    …………………………….

                                                    }

                                                    if (wl_get_drv_status(wl, CONNECTING, ndev)) {

                                                                 wl_bss_connect_done(wl, ndev, e, data, false);

                                                    }

                                    } else {

                                                    printk("%s nothing\n", __FUNCTION__);

                                    }

                    }

    Patch END.

     

    Control flow

    1. Settings/Wifi UI part structure

    WifiSettings是主对话框

    167

    168    @Override

    169    public void onActivityCreated(Bundle savedInstanceState) {

    170        // We don't call super.onActivityCreated() here, since it assumes we already set up

    171        // Preference (probably in onCreate()), while WifiSettings exceptionally set it up in

    172        // this method.

    173

    174       mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);

    175       mWifiManager.asyncConnect(getActivity(), new WifiServiceHandler());

    176        if (savedInstanceState != null

    177                && savedInstanceState.containsKey(SAVE_DIALOG_ACCESS_POINT_STATE)) {

    178            mDlgEdit = savedInstanceState.getBoolean(SAVE_DIALOG_EDIT_MODE);

    179            mAccessPointSavedState = savedInstanceState.getBundle(SAVE_DIALOG_ACCESS_POINT_STATE);

    180        }

    1101     public void asyncConnect(Context srcContext, Handler srcHandler) {

    1102        mAsyncChannel.connect(srcContext, srcHandler, getMessenger());

    1103     }

    establish a half connect between WifiManager and WifiService.

    1117    public void connectNetwork(WifiConfiguration config) {

    1118        if (config == null) {

    1119            return;

    1120        }

    1121        mAsyncChannel.sendMessage(CMD_CONNECT_NETWORK, config);

    1122    }

     

    ContextMenu是长按的三菜单Menu

        @Override

        public boolean onContextItemSelected(MenuItem item) {

            if (mSelectedAccessPoint == null) {

                return super.onContextItemSelected(item);

            }

            switch (item.getItemId()) {

                case MENU_ID_CONNECT: {

                    if (mSelectedAccessPoint.networkId != INVALID_NETWORK_ID) {

                        if (!requireKeyStore(mSelectedAccessPoint.getConfig())) {

                            mWifiManager.connectNetwork(mSelectedAccessPoint.networkId);

                        }

                    } else if (mSelectedAccessPoint.security == AccessPoint.SECURITY_NONE) {

                        /** Bypass dialog for unsecured networks */

                        mSelectedAccessPoint.generateOpenNetworkConfig();

                        mWifiManager.connectNetwork(mSelectedAccessPoint.getConfig());

                    } else {

                        showConfigUi(mSelectedAccessPoint, true);

                    }

                    return true;

                }

                case MENU_ID_FORGET: {

                    mWifiManager.forgetNetwork(mSelectedAccessPoint.networkId);

                    return true;

                }

                case MENU_ID_MODIFY: {

                    showConfigUi(mSelectedAccessPoint, true);

                    return true;

                }

            }

            return super.onContextItemSelected(item);

        }

    onPreferenceTreeClick是点击使能选项,使能Wifi

    WifiConfigControllerMVC中的Controller

    WifiDialog是单击的config对话框

     

    In IWifiManager.aidl

    32interface IWifiManager {};

    In WifiService.java   

    public class WifiService extends IWifiManager.Stub {};

     

    In WifiManager.java, NOT the intermediate file of IWifiManager.aidl

    485    public WifiManager(IWifiManager service, Handler handler) {

    486        mService = service;

    487        mHandler = handler;

    488    }

    In ContextImpl.java       

    449        registerService(WIFI_SERVICE, new ServiceFetcher() {

    450                public Object createService(ContextImpl ctx) {

    451                   IBinder b = ServiceManager.getService(WIFI_SERVICE);

    452                    IWifiManager service = IWifiManager.Stub.asInterface(b);

    453                    returnnew WifiManager(service, ctx.mMainThread.getHandler());

    454                }});

     

    In WifiSettings.java

            final List<ScanResult> results = mWifiManager.getScanResults(); //同步操作

            if (results != null) {

                for (ScanResult result : results) {

                    // Ignore hidden and ad-hoc networks.

                   if (result.SSID == null || result.SSID.length() == 0 || result.capabilities.contains("[IBSS]")) {

                       continue;

                   }

                    if (result.SSID == null || result.SSID.length() == 0 ) {

                        continue;

                    }

     

                    boolean found = false;

                    for (AccessPoint accessPoint : apMap.getAll(result.SSID)) {

                        if (accessPoint.update(result))

                            found = true;

                    }

                    if (!found) {

                        AccessPoint accessPoint = new AccessPoint(getActivity(), result);

                        accessPoints.add(accessPoint);

                        apMap.put(accessPoint.ssid, accessPoint);

                    }

                }

            }

     

        private void updateAccessPoints() {

            final int wifiState = mWifiManager.getWifiState();

     

            switch (wifiState) {

                case WifiManager.WIFI_STATE_ENABLED:

                    // AccessPoints are automatically sorted with TreeSet.

                    final Collection<AccessPoint> accessPoints = constructAccessPoints();

                    getPreferenceScreen().removeAll();

                    if (mInXlSetupWizard) {

                        ((WifiSettingsForSetupWizardXL)getActivity()).onAccessPointsUpdated(

                                getPreferenceScreen(), accessPoints);

                    } else {

                        for (AccessPoint accessPoint : accessPoints) {

                            // When WAPI is not customized to be on all

                            // WAPI APs will be invisible

                           if (accessPoint.isVisible()) {

                                getPreferenceScreen().addPreference(accessPoint);

                            }

                        }

                    }

                    break;

     

                case WifiManager.WIFI_STATE_ENABLING:

                    getPreferenceScreen().removeAll();

                    break;

     

                case WifiManager.WIFI_STATE_DISABLING:

                    addMessagePreference(R.string.wifi_stopping);

                    break;

     

                case WifiManager.WIFI_STATE_DISABLED:

                    addMessagePreference(R.string.wifi_empty_list_wifi_off);

                    break;

            }

        }

    Scanner使用定时器,周期性向WifiService请求扫描,相关代码如下。

        private class Scanner extends Handler {

            private int mRetry = 0;

     

            void resume() {

                if (!hasMessages(0)) {

                    sendEmptyMessage(0);

                }

            }

     

            void forceScan() {

                removeMessages(0);

                sendEmptyMessage(0);

            }

     

            void pause() {

                mRetry = 0;

                removeMessages(0);

            }

     

            @Override

            public void handleMessage(Message message) {

                if (mWifiManager.startScanActive()) {

                    mRetry = 0;

                } else if (++mRetry >= 3) {

                    mRetry = 0;

                    Toast.makeText(getActivity(), R.string.wifi_fail_to_scan,

                            Toast.LENGTH_LONG).show();

                    return;

                }

                sendEmptyMessageDelayed(0, WIFI_RESCAN_INTERVAL_MS);

            }

        }

     

    几个重要操作的控制流:

    WifiSettings=>WifiManager::connect(…)

    Scanner=>WifiManager:: startScanActive()

    WifiEnabler=> WifiManager:: setWifienabled() ||||  =>WifiService::setWifiEnabled()=>WifiStateMachine ::setWifiEnabled()

    总之,发出SCANCONNECT的异步命令,等待事件通知做界面响应。主要就是不停的AP列表、信号强度刷新。其余命令是同步命令。

    连接过程中显示的字符串

    In /packages/apps/Settings/res/values/arrays.xml

    223    <!-- Wi-Fi settings -->

    224

    225    <!-- Match this with the order of NetworkInfo.DetailedState. --> <skip />

    226    <!-- Wi-Fi settings. The status messages when the network is unknown. -->

    227    <string-array name="wifi_status">

    228        <!-- Status message of Wi-Fi when it is idle. -->

    229        <item></item>

    230        <!-- Status message of Wi-Fi when it is scanning. -->

    231        <item>Scanning\u2026</item>

    232        <!-- Status message of Wi-Fi when it is connecting. -->

    233        <item>Connecting\u2026</item>

    234        <!-- Status message of Wi-Fi when it is authenticating. -->

    235        <item>Authenticating\u2026</item>

    236        <!-- Status message of Wi-Fi when it is obtaining IP address. -->

    237        <item>Obtaining IP address\u2026</item>

    238        <!-- Status message of Wi-Fi when it is connected. -->

    239        <item>Connected</item>

    240        <!-- Status message of Wi-Fi when it is suspended. -->

    241        <item>Suspended</item>

    242        <!-- Status message of Wi-Fi when it is disconnecting. -->

    243        <item>Disconnecting\u2026</item>

    244        <!-- Status message of Wi-Fi when it is disconnected. -->

    245        <item>Disconnected</item>

    246        <!-- Status message of Wi-Fi when it is a failure. -->

    247        <item>Unsuccessful</item>

    248    </string-array>

     

     

    1. WifiService Part structure

    In WifiService.java   

    public class WifiService extends IWifiManager.Stub {};

    WifiService线程的启动如下

    In SystemServer.java

    384           try {

    385                Slog.i(TAG, "Wi-Fi P2pService");

    386                wifiP2p = new WifiP2pService(context);

    387                ServiceManager.addService(Context.WIFI_P2P_SERVICE, wifiP2p);

    388            } catch (Throwable e) {

    389                reportWtf("starting Wi-Fi P2pService", e);

    390            }

    391

    392           try {

    393                Slog.i(TAG, "Wi-Fi Service");

    394                wifi = new WifiService(context);

    395                ServiceManager.addService(Context.WIFI_SERVICE, wifi);

    396            } catch (Throwable e) {

    397                reportWtf("starting Wi-Fi Service", e);

    398            }

    WifiService的构造函数本质是启动了一个带有消息队列的线程做WifiService,两个Handler attach到该消息队列上。

    428        HandlerThread wifiThread = new HandlerThread("WifiService");

    429        wifiThread.start();

    430        mAsyncServiceHandler = new AsyncServiceHandler(wifiThread.getLooper());

    431        mWifiStateMachineHandler = new WifiStateMachineHandler(wifiThread.getLooper());

     

    WifiSerivce作为一个serviceWifiService.javaframeworks/base/services/java/com/android/server/目录下。但其实现使用的WifiStateMachineframeworks/base/wifi/java/android/net/wifi/目录下。

    WifiStateMachine状态机使用WifiNative wpa_ctrlwpa_supplicant通讯, WifiMonitor监听WifiNative的异步消息。客户端传来的命令和WifiMonitor监听到的响应汇入WifiStateMachine的消息队列,驱动WifiStateMachine转动起来。

    WifiStateMachine的方法中同步的带有’sync’字样,异步的是直接发送消息,通过WifiMonitor异步收集结果,WifiMonitor就是个ReceiverThread加消息协议转换。WifiMonitor在使用unix domain socket ctrl interface时是pollsocket上,有wpa_supplicant发回的数据时,recv

     

    In WifiStateMachine.java

    680    public void setWifiEnabled(boolean enable) {

    681        mLastEnableUid.set(Binder.getCallingUid());

    682        if (enable) {

    683            /* Argument is the state that is entered prior to load */

    684            sendMessage(obtainMessage(CMD_LOAD_DRIVER, WIFI_STATE_ENABLING, 0));

    685            sendMessage(CMD_START_SUPPLICANT);

    686        } else {

    687            sendMessage(CMD_STOP_SUPPLICANT);

    688            /* Argument is the state that is entered upon success */

    689            sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_DISABLED, 0));

    690        }

    691    }

     

    In WifiStateMachine.java

    553    public WifiStateMachine(Context context, String wlanInterface) {

    649        if (DBG) setDbg(true);

    650

    651        //start the state machine

    652        start();

    653    }

     

    2024    class InitialState extends State {

    2025        @Override

    2026        //TODO: could move logging into a common class

    2027        public void enter() {

    2028            if (DBG) log(getName() + "\n");

    2029            // [31-8] Reserved for future use

    2030            // [7 - 0] HSM state change

    2031            // 50021 wifi_state_changed (custom|1|5)

    2032            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());

    2033

    2034            if (WifiNative.isDriverLoaded()) {

    2035                transitionTo(mDriverLoadedState);

    2036            }

    2037            else {

    2038               transitionTo(mDriverUnloadedState);

    2039            }

    2040

    2041            //Connect to WifiP2pService

    2042            mWifiP2pManager = (WifiP2pManager) mContext.getSystemService(Context.WIFI_P2P_SERVICE);

    2043            mWifiP2pChannel.connect(mContext, getHandler(), mWifiP2pManager.getMessenger());

    2044

    2045            /* IPv6 is disabled at boot time and is controlled by framework

    2046             * to be enabled only as long as we are connected to an access point

    2047             *

    2048             * This fixes issues, a few being:

    2049             * - IPv6 addresses and routes stick around after disconnection

    2050             * - When connected, the kernel is unaware and can fail to start IPv6 negotiation

    2051             * - The kernel sometimes starts autoconfiguration when 802.1x is not complete

    2052             */

    2053            try {

    2054                mNwService.disableIpv6(mInterfaceName);

    2055            } catch (RemoteException re) {

    2056                loge("Failed to disable IPv6: " + re);

    2057            } catch (IllegalStateException e) {

    2058                loge("Failed to disable IPv6: " + e);

    2059            }

    2060        }

    2061    }

     

    2276    class DriverUnloadedState extends State {

    2277        @Override

    2278        public void enter() {

    2279            if (DBG) log(getName() + "\n");

    2280            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());

    2281        }

    2282        @Override

    2283        public boolean processMessage(Message message) {

    2284            if (DBG) log(getName() + message.toString() + "\n");

    2285            switch (message.what) {

    2286               case CMD_LOAD_DRIVER:

    2287                   mWifiP2pChannel.sendMessage(WIFI_ENABLE_PENDING);

    2288                   transitionTo(mWaitForP2pDisableState);

    2289                    break;

    2290                case WifiP2pService.P2P_ENABLE_PENDING:

    2291                    mReplyChannel.replyToMessage(message, P2P_ENABLE_PROCEED);

    2292                    break;

    2293                default:

    2294                    return NOT_HANDLED;

    2295            }

    2296            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);

    2297            return HANDLED;

    2298        }

    2299    }

     

    WifiP2pService.javaP2p的各状态下对WIFI_ENABLE_PENDING进行处理,同时WifiStateMachine进入等待p2p结束的状态。

    3542    class WaitForP2pDisableState extends State {

    3543        private int mSavedArg;

    3544        @Override

    3545        public void enter() {

    3546            if (DBG) log(getName() + "\n");

    3547            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());

    3548

    3549            //Preserve the argument arg1 that has information used in DriverLoadingState

    3550            mSavedArg = getCurrentMessage().arg1;

    3551        }

    3552        @Override

    3553        public boolean processMessage(Message message) {

    3554            if (DBG) log(getName() + message.toString() + "\n");

    3555            switch(message.what) {

    3556                case WifiP2pService.WIFI_ENABLE_PROCEED:

    3557                    //restore argument from original message (CMD_LOAD_DRIVER)

    3558                    message.arg1 = mSavedArg;

    3559                   transitionTo(mDriverLoadingState);

    3560                    break;

        

    收到P2pManager传来的WIFI_ENABLE_PROCEED,转到DriverLoadingState,开始加载driver

    2063    class DriverLoadingState extends State {

    2064        @Override

    2065        public void enter() {

    2066            if (DBG) log(getName() + "\n");

    2067            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());

    2068

    2069            final Message message = new Message();

    2070            message.copyFrom(getCurrentMessage());

    2071            /* TODO: add a timeout to fail when driver load is hung.

    2072             * Similarly for driver unload.

    2073             */

    2074            new Thread(new Runnable() {

    2075                public void run() {

    2076                    mWakeLock.acquire();

    2077                    //enabling state

    2078                    switch(message.arg1) {

    2079                        case WIFI_STATE_ENABLING:

    2080                            setWifiState(WIFI_STATE_ENABLING);

    2081                            break;

    2082                        case WIFI_AP_STATE_ENABLING:

    2083                            setWifiApState(WIFI_AP_STATE_ENABLING);

    2084                            break;

    2085                    }

    2086

    2087                    if(WifiNative.loadDriver()) {

    2088                        if (DBG) log("Driver load successful");

    2089                       sendMessage(CMD_LOAD_DRIVER_SUCCESS);

    2090                    } else {

    2091                        loge("Failed to load driver!");

    2092                        switch(message.arg1) {

    2093                            case WIFI_STATE_ENABLING:

    2094                                setWifiState(WIFI_STATE_UNKNOWN);

    2095                                break;

    2096                            case WIFI_AP_STATE_ENABLING:

    2097                                setWifiApState(WIFI_AP_STATE_FAILED);

    2098                                break;

    2099                        }

    2100                        sendMessage(CMD_LOAD_DRIVER_FAILURE);

    2101                    }

    2102                    mWakeLock.release();

    2103                }

    2104            }).start();

    2105        }

    2106

    2107        @Override

    2108        public boolean processMessage(Message message) {

    2109            if (DBG) log(getName() + message.toString() + "\n");

    2110            switch (message.what) {

    2111               case CMD_LOAD_DRIVER_SUCCESS:

    2112                    transitionTo(mDriverLoadedState);

    2113                    break;

    2114                case CMD_LOAD_DRIVER_FAILURE:

    2115                    transitionTo(mDriverFailedState);

    2116                    break;

    2117                case CMD_LOAD_DRIVER:

    2118                case CMD_UNLOAD_DRIVER:

    2119                case CMD_START_SUPPLICANT:

    2120                case CMD_STOP_SUPPLICANT:

    2121                case CMD_START_AP:

    2122                case CMD_STOP_AP:

    2123                case CMD_START_DRIVER:

    2124                case CMD_STOP_DRIVER:

    2125                case CMD_SET_SCAN_MODE:

    2126                case CMD_SET_SCAN_TYPE:

    2127                case CMD_SET_HIGH_PERF_MODE:

    2128                case CMD_SET_COUNTRY_CODE:

    2129                case CMD_SET_FREQUENCY_BAND:

    2130                case CMD_START_PACKET_FILTERING:

    2131                case CMD_STOP_PACKET_FILTERING:

    2132                    deferMessage(message);

    2133                    break;

    2134                default:

    2135                    return NOT_HANDLED;

    2136            }

    2137            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);

    2138            return HANDLED;

    2139        }

    2140    }

    加载驱动成功会进入DriverLoadedState状态,在该状态下继续下一条加载wifi soc固件和启动wpa_supplicant的处理。

    2142    class DriverLoadedState extends State {

    2143        @Override

    2144        public void enter() {

    2145            if (DBG) log(getName() + "\n");

    2146            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());

    2147        }

    2148        @Override

    2149        public boolean processMessage(Message message) {

    2150            if (DBG) log(getName() + message.toString() + "\n");

    2151            switch(message.what) {

    2152                case CMD_UNLOAD_DRIVER:

    2153                    transitionTo(mDriverUnloadingState);

    2154                    break;

    2155                case CMD_START_SUPPLICANT:

    2156                    try {

    2157                        mNwService.wifiFirmwareReload(mInterfaceName, "STA");

    2158                    } catch (Exception e) {

    2159                        loge("Failed to reload STA firmware " + e);

    2160                        // continue

    2161                    }

    2162                   try {

    2163                       //A runtime crash can leave the interface up and

    2164                       //this affects connectivity when supplicant starts up.

    2165                       //Ensure interface is down before a supplicant start.

    2166                       mNwService.setInterfaceDown(mInterfaceName);

    2167                        //Set privacy extensions

    2168                        mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true);

    2169                    } catch (RemoteException re) {

    2170                        loge("Unable to change interface settings: " + re);

    2171                    } catch (IllegalStateException ie) {

    2172                        loge("Unable to change interface settings: " + ie);

    2173                    }

    2174

    2175                    if(WifiNative.startSupplicant()) {

    2176                        if (DBG) log("Supplicant start successful");

    2177                        mWifiMonitor.startMonitoring();

    2178                        transitionTo(mSupplicantStartingState);

    2179                    } else {

    2180                        loge("Failed to start supplicant!");

    2181                        sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_UNKNOWN, 0));

    2182                    }

    2183                    break;

    2184                case CMD_START_AP:

    2185                    transitionTo(mSoftApStartingState);

    2186                    break;

    2187                default:

    2188                    return NOT_HANDLED;

    2189            }

    2190            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);

    2191            return HANDLED;

    2192        }

    2193    }

     

    2315    class SupplicantStartingState extends State {

    2316        @Override

    2317        public void enter() {

    2318            if (DBG) log(getName() + "\n");

    2319            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());

    2320        }

    2321        @Override

    2322        public boolean processMessage(Message message) {

    2323            if (DBG) log(getName() + message.toString() + "\n");

    2324            switch(message.what) {

    2325                case WifiMonitor.SUP_CONNECTION_EVENT:

    2326                    if (DBG) log("Supplicant connection established");

    2327                    WifiNative.setP2pDisable(1);

    2328                    setWifiState(WIFI_STATE_ENABLED);

    2329                    mSupplicantRestartCount = 0;

    2330                    /* Reset the supplicant state to indicate the supplicant

    2331                     * state is not known at this time */

    2332                    mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);

    2333                    mWpsStateMachine.sendMessage(CMD_RESET_WPS_STATE);

    2334                    /* Initialize data structures */

    2335                    mLastBssid = null;

    2336                    mLastNetworkId = WifiConfiguration.INVALID_NETWORK_ID;

    2337                    mLastSignalLevel = -1;

    2338

    2339                    mWifiInfo.setMacAddress(WifiNative.getMacAddressCommand());

    2340

    2341                    WifiConfigStore.initialize(mContext);

    2342

    2343                    sendSupplicantConnectionChangedBroadcast(true);

    2344                    transitionTo(mDriverStartedState);

    2345                    break;

    2346                case WifiMonitor.SUP_DISCONNECTION_EVENT:

    2347                    if (++mSupplicantRestartCount <= SUPPLICANT_RESTART_TRIES) {

    2348                        loge("Failed to setup control channel, restart supplicant");

    2349                        WifiNative.killSupplicant();

    2350                        transitionTo(mDriverLoadedState);

    2351                        sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);

    2352                    } else {

    2353                        loge("Failed " + mSupplicantRestartCount +

    2354                                " times to start supplicant, unload driver");

    2355                        mSupplicantRestartCount = 0;

    2356                        transitionTo(mDriverLoadedState);

    2357                        sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_STATE_UNKNOWN, 0));

    2358                    }

    2359                    break;

    2360                case CMD_LOAD_DRIVER:

    2361                case CMD_UNLOAD_DRIVER:

    2362                case CMD_START_SUPPLICANT:

    2363                case CMD_STOP_SUPPLICANT:

    2364                case CMD_START_AP:

    2365                case CMD_STOP_AP:

    2366                case CMD_START_DRIVER:

    2367                case CMD_STOP_DRIVER:

    2368                case CMD_SET_SCAN_MODE:

    2369                case CMD_SET_SCAN_TYPE:

    2370                case CMD_SET_HIGH_PERF_MODE:

    2371                case CMD_SET_COUNTRY_CODE:

    2372                case CMD_SET_FREQUENCY_BAND:

    2373                case CMD_START_PACKET_FILTERING:

    2374                case CMD_STOP_PACKET_FILTERING:

    2375                    deferMessage(message);

    2376                    break;

    2377                default:

    2378                    return NOT_HANDLED;

    2379            }

    2380            EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);

    2381            return HANDLED;

    2382        }

    2383    }

    2384

    2385    class SupplicantStartedState extends State {

    2386        @Override

    2387        public void enter() {

    2388            if (DBG) log(getName() + "\n");

    2389            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());

    2390            /* Initialize for connect mode operation at start */

    2391            mIsScanMode = false;

    2392            /* Wifi is available as long as we have a connection to supplicant */

    2393            mNetworkInfo.setIsAvailable(true);

    2394            /* Set scan interval */

    2395            long supplicantScanIntervalMs = Settings.Secure.getLong(mContext.getContentResolver(),

    2396                    Settings.Secure.WIFI_SUPPLICANT_SCAN_INTERVAL_MS,

    2397                    mDefaultSupplicantScanIntervalMs);

    2398            WifiNative.setScanIntervalCommand((int)supplicantScanIntervalMs / 1000);

    2399        }

    2400        @Override

    2401        public boolean processMessage(Message message) {

    2402            if (DBG) log(getName() + message.toString() + "\n");

    2403            WifiConfiguration config;

    2404            boolean eventLoggingEnabled = true;

    2405            switch(message.what) {

    2406                case CMD_STOP_SUPPLICANT:   /* Supplicant stopped by user */

    2407                    transitionTo(mSupplicantStoppingState);

    2408                    break;

    2409                case WifiMonitor.SUP_DISCONNECTION_EVENT:  /* Supplicant connection lost */

    2410                    loge("Connection lost, restart supplicant");

    2411                    WifiNative.killSupplicant();

    2412                    WifiNative.closeSupplicantConnection();

    2413                    mNetworkInfo.setIsAvailable(false);

    2414                    handleNetworkDisconnect();

    2415                    sendSupplicantConnectionChangedBroadcast(false);

    2416                    mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);

    2417                    mWpsStateMachine.sendMessage(CMD_RESET_WPS_STATE);

    2418                    transitionTo(mDriverLoadedState);

    2419                    sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);

    2420                    break;

    2421                case WifiMonitor.SCAN_RESULTS_EVENT:

    2422                    eventLoggingEnabled = false;

    2423                    setScanResults(WifiNative.scanResultsCommand());

    2424                    sendScanResultsAvailableBroadcast();

    2425                    mScanResultIsPending = false;

    2426                    break;

    2427                case CMD_PING_SUPPLICANT:

    2428                    boolean ok = WifiNative.pingCommand();

    2429                    mReplyChannel.replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);

    2430                    break;

    2431                case CMD_ADD_OR_UPDATE_NETWORK:

    2432                    config = (WifiConfiguration) message.obj;

    2433                    mReplyChannel.replyToMessage(message, CMD_ADD_OR_UPDATE_NETWORK,

    2434                            WifiConfigStore.addOrUpdateNetwork(config));

    2435                    break;

    2436                case CMD_REMOVE_NETWORK:

    2437                    ok = WifiConfigStore.removeNetwork(message.arg1);

    2438                    mReplyChannel.replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);

    2439                    break;

    2440                case CMD_ENABLE_NETWORK:

    2441                    ok = WifiConfigStore.enableNetwork(message.arg1, message.arg2 == 1);

    2442                    mReplyChannel.replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);

    2443                    break;

    2444                case CMD_ENABLE_ALL_NETWORKS:

    2445                    long time =  android.os.SystemClock.elapsedRealtime();

    2446                    if (time - mLastEnableAllNetworksTime > MIN_INTERVAL_ENABLE_ALL_NETWORKS_MS) {

    2447                        WifiConfigStore.enableAllNetworks();

    2448                        mLastEnableAllNetworksTime = time;

    2449                    }

    2450                    break;

    2451                case CMD_DISABLE_NETWORK:

    2452                    ok = WifiConfigStore.disableNetwork(message.arg1, message.arg2);

    2453                    mReplyChannel.replyToMessage(message, message.what, ok ? SUCCESS : FAILURE);

    2454                    break;

    2455                case CMD_BLACKLIST_NETWORK:

    2456                    WifiNative.addToBlacklistCommand((String)message.obj);

    2457                    break;

    2458                case CMD_CLEAR_BLACKLIST:

    2459                    WifiNative.clearBlacklistCommand();

    2460                    break;

    2461                case CMD_SAVE_CONFIG:

    2462                    ok = WifiConfigStore.saveConfig();

    2463                    mReplyChannel.replyToMessage(message, CMD_SAVE_CONFIG, ok ? SUCCESS : FAILURE);

    2464

    2465                    // Inform the backup manager about a data change

    2466                    IBackupManager ibm = IBackupManager.Stub.asInterface(

    2467                            ServiceManager.getService(Context.BACKUP_SERVICE));

    2468                    if (ibm != null) {

    2469                        try {

    2470                            ibm.dataChanged("com.android.providers.settings");

    2471                        } catch (Exception e) {

    2472                            // Try again later

    2473                        }

    2474                    }

    2475                    break;

    2476                    /* Cannot start soft AP while in client mode */

    2477                case CMD_START_AP:

    2478                    loge("Failed to start soft AP with a running supplicant");

    2479                    setWifiApState(WIFI_AP_STATE_FAILED);

    2480                    break;

    2481                case CMD_SET_SCAN_MODE:

    2482                    mIsScanMode = (message.arg1 == SCAN_ONLY_MODE);

    2483                    break;

    2484                case CMD_SAVE_NETWORK:

    2485                    config = (WifiConfiguration) message.obj;

    2486                    WifiConfigStore.saveNetwork(config);

    2487                    break;

    2488                case CMD_FORGET_NETWORK:

    2489                    WifiConfigStore.forgetNetwork(message.arg1);

    2490                    break;

    2491                default:

    2492                    return NOT_HANDLED;

    2493            }

    2494            if (eventLoggingEnabled) {

    2495                EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);

    2496            }

    2497            return HANDLED;

    2498        }

    2499

    2500        @Override

    2501        public void exit() {

    2502            mNetworkInfo.setIsAvailable(false);

    2503        }

    2504    }

     

    233    private class AsyncServiceHandler extends Handler {

    234

    235        AsyncServiceHandler(android.os.Looper looper) {

    236            super(looper);

    237        }

    238

    239        @Override

    240        public void handleMessage(Message msg) {

    241            switch (msg.what) {

    242                case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {

    243                    if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {

    244                        Slog.d(TAG, "New client listening to asynchronous messages");

    245                        mClients.add((AsyncChannel) msg.obj);

    246                    } else {

    247                        Slog.e(TAG, "Client connection failure, error=" + msg.arg1);

    248                    }

    249                    break;

    250                }

    251                case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {

    252                    if (msg.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) {

    253                        Slog.d(TAG, "Send failed, client connection lost");

    254                    } else {

    255                        Slog.d(TAG, "Client connection lost with reason: " + msg.arg1);

    256                    }

    257                    mClients.remove((AsyncChannel) msg.obj);

    258                    break;

    259                }

    260                case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {

    261                    AsyncChannel ac = new AsyncChannel();

    262                    ac.connect(mContext, this, msg.replyTo);

    263                    break;

    264                }

    265                case WifiManager.CMD_ENABLE_TRAFFIC_STATS_POLL: {

    266                    mEnableTrafficStatsPoll = (msg.arg1 == 1);

    267                    mTrafficStatsPollToken++;

    268                    if (mEnableTrafficStatsPoll) {

    269                        notifyOnDataActivity();

    270                        sendMessageDelayed(Message.obtain(this, WifiManager.CMD_TRAFFIC_STATS_POLL,

    271                                mTrafficStatsPollToken, 0), POLL_TRAFFIC_STATS_INTERVAL_MSECS);

    272                    }

    273                    break;

    274                }

    275                case WifiManager.CMD_TRAFFIC_STATS_POLL: {

    276                    if (msg.arg1 == mTrafficStatsPollToken) {

    277                        notifyOnDataActivity();

    278                        sendMessageDelayed(Message.obtain(this, WifiManager.CMD_TRAFFIC_STATS_POLL,

    279                                mTrafficStatsPollToken, 0), POLL_TRAFFIC_STATS_INTERVAL_MSECS);

    280                    }

    281                    break;

    282                }

    283                case WifiManager.CMD_CONNECT_NETWORK: {

    284                    if (msg.obj != null) {

    285                        mWifiStateMachine.connectNetwork((WifiConfiguration)msg.obj);

    286                    } else {

    287                        mWifiStateMachine.connectNetwork(msg.arg1);

    288                    }

    289                    break;

    290                }

    291                case WifiManager.CMD_SAVE_NETWORK: {

    292                    mWifiStateMachine.saveNetwork((WifiConfiguration)msg.obj);

    293                    break;

    294                }

    295                case WifiManager.CMD_FORGET_NETWORK: {

    296                    mWifiStateMachine.forgetNetwork(msg.arg1);

    297                    break;

    298                }

    299                case WifiManager.CMD_START_WPS: {

    300                    //replyTo has the original source

    301                    mWifiStateMachine.startWps(msg.replyTo, (WpsInfo)msg.obj);

    302                    break;

    303                }

    304                case WifiManager.CMD_DISABLE_NETWORK: {

    305                    mWifiStateMachine.disableNetwork(msg.replyTo, msg.arg1, msg.arg2);

    306                    break;

    307                }

    308                default: {

    309                    Slog.d(TAG, "WifiServicehandler.handleMessage ignoring msg=" + msg);

    310                    break;

    311                }

    312            }

    313        }

    314    }

     

    调用WifiStateMachineconnectNetwork方法。

    935    public void connectNetwork(int netId) {

    936        sendMessage(obtainMessage(CMD_CONNECT_NETWORK, netId, 0));

    937    }

    938

    939    public void connectNetwork(WifiConfiguration wifiConfig) {

    940        /* arg1 is used to indicate netId, force a netId value of

    941         * WifiConfiguration.INVALID_NETWORK_ID when we are passing

    942         * a configuration since the default value of 0 is a valid netId

    943         */

    944        sendMessage(obtainMessage(CMD_CONNECT_NETWORK, WifiConfiguration.INVALID_NETWORK_ID,

    945                0, wifiConfig));

    946    }

    ConnectedState时,新选择network,连接,并且在收到连接好前转到disconnectState

    2969                case CMD_CONNECT_NETWORK:

    2970                    int netId = message.arg1;

    2971                    WifiConfiguration config = (WifiConfiguration) message.obj;

    2972

    2973                    /* We connect to a specific network by issuing a select

    2974                     * to the WifiConfigStore. This enables the network,

    2975                     * while disabling all other networks in the supplicant.

    2976                     * Disabling a connected network will cause a disconnection

    2977                     * from the network. A reconnectCommand() will then initiate

    2978                     * a connection to the enabled network.

    2979                     */

    2980                    if (config != null) {

    2981                        netId = WifiConfigStore.selectNetwork(config);

    2982                    } else {

    2983                        WifiConfigStore.selectNetwork(netId);

    2984                    }

    2985

    2986                    /* The state tracker handles enabling networks upon completion/failure */

    2987                    mSupplicantStateTracker.sendMessage(CMD_CONNECT_NETWORK);

    2988

    2989                    WifiNative.reconnectCommand();

    2990                    mLastExplicitNetworkId = netId;

    2991                    mLastNetworkChoiceTime  = SystemClock.elapsedRealtime();

    2992                    mNextWifiActionExplicit = true;

    2993                    if (DBG) log("Setting wifi connect explicit for netid " + netId);

    2994                    /* Expect a disconnection from the old connection */

    2995                    transitionTo(mDisconnectingState);

    2996                    break;

    SupplicantStateTracker.java收到CMD_CONNECT_NETWORK消息后追踪状态。主要是在reconnectCommand中做的连接

    152

    153    class DefaultState extends State {

    154        @Override

    155         public void enter() {

    156             if (DBG) Log.d(TAG, getName() + "\n");

    157         }

    158        @Override

    159        public boolean processMessage(Message message) {

    160            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");

    161            switch (message.what) {

    162                case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:

    163                    mAuthenticationFailuresCount++;

    164                    mAuthFailureInSupplicantBroadcast = true;

    165                    break;

    166                case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:

    167                    StateChangeResult stateChangeResult = (StateChangeResult) message.obj;

    168                    SupplicantState state = stateChangeResult.state;

    169                    sendSupplicantStateChangedBroadcast(state, mAuthFailureInSupplicantBroadcast);

    170                    mAuthFailureInSupplicantBroadcast = false;

    171                    transitionOnSupplicantStateChange(stateChangeResult);

    172                    break;

    173                case WifiStateMachine.CMD_RESET_SUPPLICANT_STATE:

    174                    transitionTo(mUninitializedState);

    175                    break;

    176                case WifiStateMachine.CMD_CONNECT_NETWORK:

    177                    mNetworksDisabledDuringConnect = true;

    178                    break;

    179                default:

    180                    Log.e(TAG, "Ignoring " + message);

    181                    break;

    182            }

    183            return HANDLED;

    184        }

    185    }

     

    WifiNative.java

    104    public native static boolean reconnectCommand();

    android_net_wifi_Wifi.cpp        

    603 { "reconnectCommand", "()Z", (void *)android_net_wifi_reconnectCommand },

    WifiNative.java中使用reconnectCommand方法时没有检查返回值,所以消息估计是异步传回。

    static jboolean doBooleanCommand(const char* expect, const char* fmt, ...)

    static int doCommand(const char *cmd, char *replybuf, int replybuflen)

    call int wifi_command(const char *command, char *reply, size_t *reply_len)  @ wifi_bcm.c

     

     

    wpa_supplicant的扫描结果中有IBSS WEP,在Java层被过滤掉。

     

    android_net_wifi_Wifi.cpp

    120static jboolean android_net_wifi_loadDriver(JNIEnv* env, jobject)

    121{

    122    return (jboolean)(::wifi_load_driver() == 0);

    123}

     

    wifi_bcm.c

    wifi_bcm.c有设置KMGT update_ctrl_interface ,就是从config file里面找ctrl_interface=wlan0这项,生成unix domain socket的监听端口文件名。wlan0时,系统会生成/dev/socket/wpa_wlan0;是目录的时候,可能在该目录下生成一个什么名称的文件。

    875int wifi_command(const char *command, char *reply, size_t *reply_len)

    876{

    877    return wifi_send_command(ctrl_conn, command, reply, reply_len);

    878}

    发送命令到wpa_supplicant的监听socket上,该socketrecv函数是wpa_supplicant_ctrl_iface_receive,在wpa_supplicant的初始化过程中注册

    main() => wpa_supplicant_add_iface  => wpa_supplicant_init_iface => wpa_supplicant_ctrl_iface_init => eloop_register_read_sock.

    wpa_supplicant_ctrl_iface_receive => wpa_supplicant_ctrl_iface_process

    3286       } else if (os_strcmp(buf, "RECONNECT") == 0) {

    3287                       if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)

    3288                                       reply_len = -1;

    3289                       else if (wpa_s->disconnected) {

    3290                                       wpa_s->disconnected = 0;

    3291                                       wpa_s->reassociate = 1;

    3292                                       wpa_supplicant_req_scan(wpa_s, 0, 0);

    3293                       }

    3521       } else if (os_strcmp(buf, "SCAN") == 0) {

    3522                       if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)

    3523                                       reply_len = -1;

    3524                       else {

    3525                                       if (!wpa_s->scanning &&

    3526                                           ((wpa_s->wpa_state <= WPA_SCANNING) ||

    3527                                            (wpa_s->wpa_state == WPA_COMPLETED))) {

    3528                                                       wpa_s->scan_req = 2;

    3529                                                       wpa_supplicant_req_scan(wpa_s, 0, 0);

    3530                                       } else {

    3531                                                       wpa_printf(MSG_DEBUG, "Ongoing scan action - "

    3532                                                                          "reject new request");

    3533                                                       reply_len = os_snprintf(reply, reply_size,

    3534                                                                                                       "FAIL-BUSY\n");

    3535                                       }

    3536                       }

    3537       } else if (os_strcmp(buf, "SCAN_RESULTS") == 0) {

    3538                       reply_len = wpa_supplicant_ctrl_iface_scan_results(

    3539                                       wpa_s, reply, reply_size);

    3540       } else if (os_strncmp(buf, "SELECT_NETWORK ", 15) == 0) {

    3541                       if (wpa_supplicant_ctrl_iface_select_network(wpa_s, buf + 15))

    3542                                       reply_len = -1;

    3543       } else if (os_strncmp(buf, "ENABLE_NETWORK ", 15) == 0) {

    3544                       if (wpa_supplicant_ctrl_iface_enable_network(wpa_s, buf + 15))

    3545                                       reply_len = -1;

    3546       } else if (os_strncmp(buf, "DISABLE_NETWORK ", 16) == 0) {

    3547                       if (wpa_supplicant_ctrl_iface_disable_network(wpa_s, buf + 16))

    3548                                       reply_len = -1;

    3549       } else if (os_strcmp(buf, "ADD_NETWORK") == 0) {

    3550                       reply_len = wpa_supplicant_ctrl_iface_add_network(

    3551                                       wpa_s, reply, reply_size);

    3552       } else if (os_strncmp(buf, "REMOVE_NETWORK ", 15) == 0) {

    3553                       if (wpa_supplicant_ctrl_iface_remove_network(wpa_s, buf + 15))

    3554                                       reply_len = -1;

    3555       } else if (os_strncmp(buf, "SET_NETWORK ", 12) == 0) {

    3556                       if (wpa_supplicant_ctrl_iface_set_network(wpa_s, buf + 12))

    3557                                       reply_len = -1;

    3558       } else if (os_strncmp(buf, "GET_NETWORK ", 12) == 0) {

    3559                       reply_len = wpa_supplicant_ctrl_iface_get_network(

    3560                                       wpa_s, buf + 12, reply, reply_size);

    3561#ifndef CONFIG_NO_CONFIG_WRITE

    3562       } else if (os_strcmp(buf, "SAVE_CONFIG") == 0) {

    3563                       if (wpa_supplicant_ctrl_iface_save_config(wpa_s))

    3564                                       reply_len = -1;

    3565#endif /* CONFIG_NO_CONFIG_WRITE */

    3566       } else if (os_strncmp(buf, "GET_CAPABILITY ", 15) == 0) {

    3567                       reply_len = wpa_supplicant_ctrl_iface_get_capability(

    3568                                       wpa_s, buf + 15, reply, reply_size);

    3569       } else if (os_strncmp(buf, "AP_SCAN ", 8) == 0) {

    3570                       if (wpa_supplicant_ctrl_iface_ap_scan(wpa_s, buf + 8))

    3571                                       reply_len = -1;

    3572       } else if (os_strncmp(buf, "SCAN_INTERVAL ", 14) == 0) {

     

    hardware/libhardware_legacy/wifi/Android.mk

    3LOCAL_CFLAGS += -DCONFIG_CTRL_IFACE_CLIENT_DIR=\"/data/misc/wifi/sockets\"

    4LOCAL_CFLAGS += -DCONFIG_CTRL_IFACE_CLIENT_PREFIX=\"wpa_ctrl_\"

     

    /data/misc/wifi/sockets是使用wpa_cli库接口建立unix domain socket时,本地文件名。这两个宏构成如/data/misc/wifi/sockets/ wpa_ctrl_pid-nn的文件名,就是unix domain socket的文件名。

    目标文件名是/dev/socket/wpa_wlan0,是socket的另一端,这个是由wpa_supplicant打开的。参见init.Manufacture.rcwpa_cli去连接这个服务端口。

    使用单独的wpa_cli端时,如下使用

    wpa_cli -p /dev/socket/ -i wpa_wlan0

    单独的wpa_cli会新建两个unix domain socket的两个local文件名。

    wpa_ctrl_11762-1

    wpa_ctrl_11762-2

    如果wpa_supplicantlogger输出时,wpa_cli会得到消息输出。

    9738 log        0:00 /system/bin/logwrapper /system/bin/wpa_supplicant -iwlan0 -puse_p2p_group_interface=1 -Dnl80211 -iwlan0 -c/data/misc/wifi/wpa_supplicant.conf -ddd

     9740 wifi       0:23 /system/bin/wpa_supplicant -iwlan0 -puse_p2p_group_interface=1 -Dnl80211 -iwlan0 -c/data/misc/wifi/wpa_supplicant.conf -ddd

    wifi驱动可能是

    #define WIFI_DRIVER_MODULE_PATH "/system/lib/modules/wlan.ko"              

    可能是

    #WIFI_DRIVER_MODULE_PATH := "/system/etc/bcm4330/dhd.ko"

    insmod(DRIVER_MODULE_PATH, DRIVER_MODULE_ARG)

    也可能是builtIn的。in wifi_bcm.c

    LOGI("Using BuildIn WiFi driver");

    property_set(DRIVER_PROP_NAME, "ok");

    加载wpa_supplicant

        property_get("wifi.interface", iface, WIFI_TEST_INTERFACE);

        property_get("persist.wpa_supplicant.debug", supp_debug, "false");

        if (strcmp(supp_debug, "true") == 0) {

            SLOGI("persist.wpa_supplicant.debug property true");

            snprintf(daemon_cmd, PROPERTY_VALUE_MAX, "%s:-i%s -c%s -ddd", SUPPLICANT_NAME, iface, config_file);

        } else {

            SLOGI("persist.wpa_supplicant.debug property false");

            snprintf(daemon_cmd, PROPERTY_VALUE_MAX, "%s:-i%s -c%s", SUPPLICANT_NAME, iface, config_file);

        }

        property_set("ctl.start", daemon_cmd);

     

    driver扫描完后发出 wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, &event);

    2155       case EVENT_SCAN_RESULTS:

    2156                       wpa_supplicant_event_scan_results(wpa_s, data);

    2157                       break;

    wpa_supplicant_event_scan_results

    _wpa_supplicant_event_scan_results

    wpa_supplicant_pick_network

    wpa_supplicant_select_bss

    wpa_scan_res_match

    现在的是match之后,下一个是什么过程。要找到:从Connect命令后找,启动搜索,搜索结果,configed匹配到?

    连接前启动扫描,扫描结果匹配后,自然是连接。就从_wpa_supplicant_event_scan_resultspick netwoerk之后看。

                    if (selected) {

                                    int skip;

                                    skip = !wpa_supplicant_need_to_roam(wpa_s, selected, ssid, scan_res);

                                    wpa_scan_results_free(scan_res);

                                    if (skip)

                                                    return 0;

                                   wpa_supplicant_connect(wpa_s, selected, ssid);

                                   wpa_supplicant_rsn_preauth_scan_results(wpa_s);

                    }

     

    wpa_supplicant_connect  =>  wpa_supplicant_associate

                                   

    @ssid: wpa_ssid structure for a configured network or %NULL for any network

    wpa_supplicant_ctrl_iface_select_network => wpa_supplicant_select_network =>wpa_supplicant_req_scan(wpa_s, 0, 0);

    wpa_supplicant_enable_network - Mark a configured network as enabled

    @ssid: wpa_ssid structure for a configured network or %NULL

    wpa_supplicant_ctrl_iface_enable_network => wpa_supplicant_enable_network =>wpa_supplicant_req_scan(wpa_s, 0, 0);

     

    当扫描时wpa_supplicant_scan with ap_scan==0 => wpa_supplicant_gen_assoc_event

    32static void wpa_supplicant_gen_assoc_event(struct wpa_supplicant *wpa_s)

    33{

    34           struct wpa_ssid *ssid;

    35           union wpa_event_data data;

    36

    37           ssid = wpa_supplicant_get_ssid(wpa_s);

    38           if (ssid == NULL)

    39                           return;

    40

    41           if (wpa_s->current_ssid == NULL) {

    42                           wpa_s->current_ssid = ssid;

    43                           if (wpa_s->current_ssid != NULL)

    44                                           wpas_notify_network_changed(wpa_s);

    45           }

    46           wpa_supplicant_initiate_eapol(wpa_s);

    47           wpa_dbg(wpa_s, MSG_DEBUG, "Already associated with a configured "

    48                           "network - generating associated event");

    49           os_memset(&data, 0, sizeof(data));

    50           wpa_supplicant_event(wpa_s, EVENT_ASSOC, &data);

    51}

    或者当连接bss后,

    wpa_driver_nl80211_event_receive  => process_event() => mlme_event_join_ibss() => wpa_supplicant_event(drv->ctx,EVENT_ASSOC, NULL);

    wpa_driver_nl80211_init_nl中,wpa_driver_nl80211_event_receive注册到netlink socket的读处理上。

    eloop_register_read_sock(nl_socket_get_fd(drv->nl_handle_event),

                                                                     wpa_driver_nl80211_event_receive, drv,

                                                                     drv->nl_handle_event);

    或者当INFRA时,

    直接wpa_driver_nl80211_connect发送NL80211_CMD_CONNECT,会收到NL80211_CMD_CONNECT响应,用mlme_event_connect=>wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);处理

     

    好像是用来做AUTH+ASSOCIATE阶段的。

    case EVENT_ASSOC: wpa_supplicant_event_assoc(wpa_s, data);

     

    driver可以找到是kernel/drivers/net/wireless/bcmdhd/wl_cfg80211.c

    按照driver的要求打包数据。

     

    wpa_supplicant_associate是连接和验证的入口。

    wpa_supplicant_associate

    calls => wpa_drv_associate

    calls => wpa_driver_nl80211_associate when drvier_nl80211 is used.

    calls => wpa_driver_nl80211_ibss for IBSS mode.

    wpa_driver_nl80211_ibss首先将驱动和固件设置到IBSS工作模式,然后发送JOIN_IBSS命令。

    4709static int wpa_driver_nl80211_ibss(struct wpa_driver_nl80211_data *drv,

    4710                                                          struct wpa_driver_associate_params *params)

    4711{

    4712       struct nl_msg *msg;

    4713       int ret = -1;

    4714       int count = 0;

    4715

    4716       wpa_printf(MSG_DEBUG, "nl80211: Join IBSS (ifindex=%d)", drv->ifindex);

    4717

    4718       if (wpa_driver_nl80211_set_mode(&drv->first_bss, params->mode)) {

    4719                       wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "

    4720                                          "IBSS mode");

    4721                       return -1;

    4722       }

    4723

    4724retry:

    4725       msg = nlmsg_alloc();

    4726       if (!msg)

    4727                       return -1;

    4728

    4729       genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,

    4730                          NL80211_CMD_JOIN_IBSS, 0);

    4731       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);

    4732

    4733       if (params->ssid == NULL || params->ssid_len > sizeof(drv->ssid))

    4734                       goto nla_put_failure;

    4735

    4736       wpa_hexdump_ascii(MSG_DEBUG, "  * SSID",

    4737                                         params->ssid, params->ssid_len);

    4738       NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,

    4739                       params->ssid);

    4740       os_memcpy(drv->ssid, params->ssid, params->ssid_len);

    4741       drv->ssid_len = params->ssid_len;

    4742

    4743       wpa_printf(MSG_DEBUG, "  * freq=%d", params->freq);

    4744       NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);

    4745

    4746       ret = nl80211_set_conn_keys(params, msg);

    4747       if (ret)

    4748                       goto nla_put_failure;

    4749

    4750       if (params->wpa_ie) {

    4751                       wpa_hexdump(MSG_DEBUG,

    4752                                           "  * Extra IEs for Beacon/Probe Response frames",

    4753                                           params->wpa_ie, params->wpa_ie_len);

    4754                       NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len,

    4755                                       params->wpa_ie);

    4756       }

    4757

    4758       ret = send_and_recv_msgs(drv, msg, NULL, NULL);

    4759       msg = NULL;

    4760       if (ret) {

    4761                       wpa_printf(MSG_DEBUG, "nl80211: Join IBSS failed: ret=%d (%s)",

    4762                                          ret, strerror(-ret));

    4763                       count++;

    4764                       if (ret == -EALREADY && count == 1) {

    4765                                       wpa_printf(MSG_DEBUG, "nl80211: Retry IBSS join after "

    4766                                                          "forced leave");

    4767                                       nl80211_leave_ibss(drv);

    4768                                       nlmsg_free(msg);

    4769                                       goto retry;

    4770                       }

    4771

    4772                       goto nla_put_failure;

    4773       }

    4774       ret = 0;

    4775       wpa_printf(MSG_DEBUG, "nl80211: Join IBSS request sent successfully");

    4776

    4777nla_put_failure:

    4778       nlmsg_free(msg);

    4779       return ret;

    4780}

    首先看设置网卡工作模式 INFRA还是ADHOC

    5148static int nl80211_set_mode(struct wpa_driver_nl80211_data *drv,

    5149                                           int ifindex, int mode)

    5150{

    5151       struct nl_msg *msg;

    5152       int ret = -ENOBUFS;

    5153

    5154       msg = nlmsg_alloc();

    5155       if (!msg)

    5156                       return -ENOMEM;

    5157

    5158       genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,

    5159                           0,NL80211_CMD_SET_INTERFACE, 0);

    5160       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);

    5161       NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, mode);

    5162

    5163       ret = send_and_recv_msgs(drv, msg, NULL, NULL);

    5164       if (!ret)

    5165                       return 0;

    5166nla_put_failure:

    5167       wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface %d to mode %d:"

    5168                          " %d (%s)", ifindex, mode, ret, strerror(-ret));

    5169       return ret;

    5170}

    NL80211_CMD_SET_INTERFACE command to kernel space driver =>

    static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)

    =>

    1586       if (change)

    1587                       err =cfg80211_change_iface(rdev, dev, ntype, flags, &params);

    cfg80211_change_iface instead calls =>

    => wl_cfg80211_change_virtual_iface

    此处wl_cfg80211在设置到IBSS模式时没有执行,需要patchWLC_SET_INFRA

    err = wldev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(infra), true);

    另外地,wldev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(infra), true)wl_config_ifmode中也被调用,而wl_config_ifmodewl_cfg80211_up(void *para)=>__wl_cfg80211_up中被调用。

    wl_cfg80211_up只在dhd驱动的open函数dhd_open(struct net_device *net)中使用一次,用于网卡打开进行配置使用,所以iwconfig可以使能网卡IBSS模式,但是wpa_supplicant不能使能网卡IBSS模式的原因大概在此。

    static s32 wl_config_ifmode(struct wl_priv *wl, struct net_device *ndev, s32 iftype)

    {

                    s32 infra = 0;

                    s32 err = 0;

                    s32 mode = 0;

                    switch (iftype) {

                    case NL80211_IFTYPE_MONITOR:

                    case NL80211_IFTYPE_WDS:

                                    WL_ERR(("type (%d) : currently we do not support this mode\n",

                                                    iftype));

                                    err = -EINVAL;

                                    return err;

                    case NL80211_IFTYPE_ADHOC:

                                    mode = WL_MODE_IBSS;

                                    break;

                    case NL80211_IFTYPE_STATION:

                    case NL80211_IFTYPE_P2P_CLIENT:

                                    mode = WL_MODE_BSS;

                                    infra = 1;

                                    break;

                    case NL80211_IFTYPE_AP:

                    case NL80211_IFTYPE_P2P_GO:

                                    mode = WL_MODE_AP;

                                    infra = 1;

                                    break;

                    default:

                                    err = -EINVAL;

                                    WL_ERR(("invalid type (%d)\n", iftype));

                                    return err;

                    }

                    infra = htod32(infra);

                    err = wldev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(infra), true);

                    if (unlikely(err)) {

                                    WL_ERR(("WLC_SET_INFRA error (%d)\n", err));

                                    return err;

                    }

     

                    wl_set_mode_by_netdev(wl, ndev, mode);

     

                    return 0;

    }

     

    再看第二个步骤发送JOIN_IBSS

    join_ibss in driver_nl80211.c

    wpa_driver_nl80211_ibss

                    genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,

                                       NL80211_CMD_JOIN_IBSS, 0);

                    NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);

     

    kernel/net/wireless/nl80211.c is one driver top file for JOIN_IBSS

    4330static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)

    4331{

    4332       struct cfg80211_registered_device *rdev = info->user_ptr[0];

    4333       struct net_device *dev = info->user_ptr[1];

    4334       struct cfg80211_ibss_params ibss;

    4335       struct wiphy *wiphy;

    4336       struct cfg80211_cached_keys *connkeys = NULL;

    4337       int err;

    4338

    4339       memset(&ibss, 0, sizeof(ibss));

    4340

    4341       if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))

    4342                       return -EINVAL;

    4343

    4344       if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] ||

    4345           !info->attrs[NL80211_ATTR_SSID] ||

    4346           !nla_len(info->attrs[NL80211_ATTR_SSID]))

    4347                       return -EINVAL;

    4348

    4349       ibss.beacon_interval = 100;

    4350

    4351       if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) {

    4352                       ibss.beacon_interval =

    4353                                       nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);

    4354                       if (ibss.beacon_interval < 1 || ibss.beacon_interval > 10000)

    4355                                       return -EINVAL;

    4356       }

    4357

    4358       if (!rdev->ops->join_ibss)

    4359                       return -EOPNOTSUPP;

    4360

    4361      if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC)

    4362                      return -EOPNOTSUPP;   //这个东西并不影响IBSS逻辑

    4363

    4364       wiphy = &rdev->wiphy;

    4365

    4366       if (info->attrs[NL80211_ATTR_MAC])

    4367                       ibss.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);

    4368       ibss.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);

    4369       ibss.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);

    4370

    4371       if (info->attrs[NL80211_ATTR_IE]) {

    4372                       ibss.ie = nla_data(info->attrs[NL80211_ATTR_IE]);

    4373                       ibss.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);

    4374       }

    4375

    4376       ibss.channel = ieee80211_get_channel(wiphy,

    4377                       nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));

    4378       if (!ibss.channel ||

    4379           ibss.channel->flags & IEEE80211_CHAN_NO_IBSS ||

    4380           ibss.channel->flags & IEEE80211_CHAN_DISABLED)

    4381                       return -EINVAL;

    4382

    4383       ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED];

    4384       ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];

    4385

    4386       if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) {

    4387                       u8 *rates =

    4388                                       nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);

    4389                       int n_rates =

    4390                                       nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);

    4391                       struct ieee80211_supported_band *sband =

    4392                                       wiphy->bands[ibss.channel->band];

    4393                       int err;

    4394                       err = ieee80211_get_ratemask(sband, rates, n_rates,

    4395                                                                            &ibss.basic_rates);

    4396                       if (err)

    4397                                       return err;

    4398       }

    4399

    4400       if (info->attrs[NL80211_ATTR_MCAST_RATE] &&

    4401           !nl80211_parse_mcast_rate(rdev, ibss.mcast_rate,

    4402                                       nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE])))

    4403                       return -EINVAL;

    4404

    4405       if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) {

    4406                       connkeys = nl80211_parse_connkeys(rdev,

    4407                                                                       info->attrs[NL80211_ATTR_KEYS]);

    4408                       if (IS_ERR(connkeys))

    4409                                       return PTR_ERR(connkeys);

    4410       }

    4411

    4412       err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys);

    4413       if (err)

    4414                       kfree(connkeys);

    4415       return err;

    4416}

     

    In wl_cfg80211.c

    1758static s32

    1759wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,

    1760       struct cfg80211_ibss_params *params)

    1761{

    1762       struct wl_priv *wl = wiphy_priv(wiphy);

    1763       struct cfg80211_bss *bss;

    1764       struct ieee80211_channel *chan;

    1765       struct wl_join_params join_params;

    1766       struct cfg80211_ssid ssid;

    1767       s32 scan_retry = 0;

    1768       s32 err = 0;

    1769       bool rollback_lock = false;

    1770

    1771       WL_TRACE(("In\n"));

    1772       CHECK_SYS_UP(wl);

    1773      if (params->bssid) {                         // remove the ibss-blocking code

    1774                      WL_ERR(("Invalid bssid\n"));

    1775                      return -EOPNOTSUPP;  

    1776       }

    1777       bss = cfg80211_get_ibss(wiphy, NULL, params->ssid, params->ssid_len);

    1778       if (!bss) {

    1779                       memcpy(ssid.ssid, params->ssid, params->ssid_len);

    1780                       ssid.ssid_len = params->ssid_len;

    1781                       do {

    1782                                       if (unlikely

    1783                                                       (__wl_cfg80211_scan(wiphy, dev, NULL, &ssid) ==

    1784                                                       -EBUSY)) {

    1785                                                       wl_delay(150);

    1786                                       } else {

    1787                                                       break;

    1788                                       }

    1789                       } while (++scan_retry < WL_SCAN_RETRY_MAX);

    1790                       /* to allow scan_inform to propagate to cfg80211 plane */

    1791                       if (rtnl_is_locked()) {

    1792                                       rtnl_unlock();

    1793                                       rollback_lock = true;

    1794                       }

    1795

    1796                       /* wait 4 secons till scan done.... */

    1797                       schedule_timeout_interruptible(4 * HZ);

    1798                       if (rollback_lock)

    1799                                       rtnl_lock();

    1800                       bss = cfg80211_get_ibss(wiphy, NULL,

    1801                                       params->ssid, params->ssid_len);

    1802       }

    1803       if (bss) {

    1804                       wl->ibss_starter = false;

    1805                       WL_DBG(("Found IBSS\n"));

    1806       } else {

    1807                       wl->ibss_starter = true;

    1808       }

    1809       chan = params->channel;

    1810       if (chan)

    1811                       wl->channel = ieee80211_frequency_to_channel(chan->center_freq);

    1812       /*

    1813       * Join with specific BSSID and cached SSID

    1814       * If SSID is zero join based on BSSID only

    1815       */

    1816       memset(&join_params, 0, sizeof(join_params));

    1817       memcpy((void *)join_params.ssid.SSID, (void *)params->ssid,

    1818                       params->ssid_len);

    1819       join_params.ssid.SSID_len = htod32(params->ssid_len);

    1820       if (params->bssid)

    1821                       memcpy(&join_params.params.bssid, params->bssid,

    1822                                       ETHER_ADDR_LEN);

    1823       else

    1824                       memset(&join_params.params.bssid, 0, ETHER_ADDR_LEN);

    1825

    1826       err = wldev_ioctl(dev, WLC_SET_SSID, &join_params,

    1827                       sizeof(join_params), false);

    1828       if (unlikely(err)) {

    1829                       WL_ERR(("Error (%d)\n", err));

    1830                       return err;

    1831       }

    1832       return err;

    1833}

    发送给dhd固件,err0,表发送成功;

    WLC_SET_SSID的结果以异步形式由固件发送回来。此时收到的WLC_E_SET_SSIDstatusWLC_E_STATUS_NO_NETWORKS

    设置WLC_SET_INFRA后,修改join_ibss相关代码,可以收到WLC_E_SET_SSID with status WLC_E_STATUS_SUCCESSFUL,连接上IBSS

     

    驱动中在IBSS时收到的主要是WLC_E_LINKWLC_E_JOINWLC_E_SET_SSID,会通过event_handler处理或通知wpa_supplicant.

     

    wpa_driver_nl80211_event_rtm_newlink是在wpa_driver_nl80211_init中注册的

    cfg->newlink_cb = wpa_driver_nl80211_event_rtm_newlink;

    cfg->dellink_cb = wpa_driver_nl80211_event_rtm_dellink;

     

    wl_notify_connect_status是在wl_init_event_handler中注册的。

    5255static void wl_init_event_handler(struct wl_priv *wl)

    5256{

    5257       memset(wl->evt_handler, 0, sizeof(wl->evt_handler));

    5258

    5259       wl->evt_handler[WLC_E_SCAN_COMPLETE] = wl_notify_scan_status;

    5260       wl->evt_handler[WLC_E_LINK] = wl_notify_connect_status;

    5261       wl->evt_handler[WLC_E_DEAUTH_IND] = wl_notify_connect_status;

    5262       wl->evt_handler[WLC_E_DEAUTH] = wl_notify_connect_status;

    5263       wl->evt_handler[WLC_E_DISASSOC_IND] = wl_notify_connect_status;

    5264       wl->evt_handler[WLC_E_ASSOC_IND] = wl_notify_connect_status;

    5265       wl->evt_handler[WLC_E_REASSOC_IND] = wl_notify_connect_status;

    5266       wl->evt_handler[WLC_E_ROAM] = wl_notify_roaming_status;

    5267       wl->evt_handler[WLC_E_MIC_ERROR] = wl_notify_mic_status;

    5268       wl->evt_handler[WLC_E_SET_SSID] = wl_notify_connect_status;

    5269       wl->evt_handler[WLC_E_ACTION_FRAME_RX] = wl_notify_rx_mgmt_frame;

    5270       wl->evt_handler[WLC_E_PROBREQ_MSG] = wl_notify_rx_mgmt_frame;

    5271       wl->evt_handler[WLC_E_P2P_PROBREQ_MSG] = wl_notify_rx_mgmt_frame;

    5272       wl->evt_handler[WLC_E_P2P_DISC_LISTEN_COMPLETE] = wl_cfgp2p_listen_complete;

    5273       wl->evt_handler[WLC_E_ACTION_FRAME_COMPLETE] = wl_cfgp2p_action_tx_complete;

    5274       wl->evt_handler[WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE] = wl_cfgp2p_action_tx_complete;

    5275

    5276}

     

     

    以下BoardConfig.mk中的好像没用到,没有定义WIFI_DRIVER_MODULE_PATH

    device/qcom/msm7627a/BoardConfig.mk

    7ifeq ($(QC_PROP),true)

    8    BOARD_USES_QCOM_HARDWARE := true

    9    DYNAMIC_SHARED_LIBV8SO := true

    10    BOARD_USES_ADRENO_200 := true

    11    HAVE_ADRENO200_SOURCE := true

    12    HAVE_ADRENO200_SC_SOURCE := true

    13    HAVE_ADRENO200_FIRMWARE := true

    14    BOARD_USES_QCNE := true

    15    USE_OPENGL_RENDERER := true

    16    BOARD_USE_QCOM_LLVM_CLANG_RS := true

    17    ifneq ($(BUILD_TINY_ANDROID), true)

    18    BOARD_VENDOR_QCOM_GPS_LOC_API_AMSS_VERSION := 50001

    19    BOARD_VENDOR_QCOM_GPS_LOC_API_HARDWARE := default

    20    BOARD_CAMERA_LIBRARIES := libcamera

    21    BOARD_HAVE_BLUETOOTH := true

    22    BOARD_HAVE_BLUETOOTH_BCM := true

    23    BOARD_HAVE_QCOM_FM := false

    24    #BOARD_USES_GENERIC_AUDIO := true

    25    HOSTAPD_VERSION := VER_2_0_DEV_BCM

    26    BOARD_HOSTAPD_DRIVER := NL80211

    27    #BOARD_HAS_QCOM_WLAN := true

    28    BOARD_WPA_SUPPLICANT_DRIVER := NL80211

    29    WPA_SUPPLICANT_VERSION := VER_0_8_X_BCM

    30

    31    #WIFI_DRIVER_MODULE_PATH := "/system/etc/bcm4330/dhd.ko"

    32    WIFI_DRIVER_MODULE_NAME := "dhd"

    33    WIFI_DRIVER_MODULE_ARG  := "firmware_path=/system/etc/bcm4330/sdio-g-pool-pno-pktfilter-keepalive-wapi-wme-p2p-idsup-idauth-sta-aoe.bin nvram_path=/system/etc/bcm4330/bcm94330wlsdgbphone.txt iface_name=wlan"

    34    BOARD_HOTSPOT_SAR_BACKUP := true

    35

    36

    37    #WIFI_SDIO_IF_DRIVER_MODULE_PATH := "/system/lib/modules/librasdioif.ko"

    38    #WIFI_SDIO_IF_DRIVER_MODULE_NAME := "librasdioif"

    39    #WIFI_SDIO_IF_DRIVER_MODULE_ARG  := ""

    40    WIFI_DRIVER_FW_PATH_PARAM := "/sys/module/bcmdhd/parameters/firmware_path"

    41    WIFI_DRIVER_FW_PATH_STA := "/system/etc/bcm4330/sdio_g_pool_pno_pktfilter_keepalive_wapi_wme_idsup_idauth_sta_aoe.bin"

    42    WIFI_DRIVER_FW_PATH_AP  := "/system/etc/bcm4330/sdio_g_pool_pno_pktfilter_keepalive_wapi_wme_idsup_idauth_apsta_aoe.bin"

    43    WIFI_DRIVER_FW_PATH_P2P := "/system/etc/bcm4330/sdio_g_pool_pno_pktfilter_keepalive_wapi_wme_idsup_idauth_p2p_aoe.bin"

    44    BOARD_WPA_SUPPLICANT_PRIVATE_LIB := lib_driver_cmd_bcmdhd

    45    BOARD_HOSTAPD_PRIVATE_LIB := lib_driver_cmd_bcmdhd

    46    BOARD_WLAN_DEVICE := bcmdhd

    47    endif   # !BUILD_TINY_ANDROID

     

    其余在init.rc

        setprop wifi.interface wlan0

     

        # Connectivity: Enable Wifi EAP SIM

        setprop ro.wifi.eap_sim_enabled true

       

        chown wifi wifi /dev/wlandev

        chmod 0660 /dev/wlandev

     

        # Create the directories used by the Wireless subsystem

        mkdir /data/misc/wifi 0770 wifi wifi

        mkdir /data/misc/wifi/sockets 0770 wifi wifi

        mkdir /data/misc/wifi/wpa_supplicant 0770 wifi wifi

        mkdir /data/misc/dhcp 0770 dhcp dhcp

        chown dhcp dhcp /data/misc/dhcp

     

     

    service wpa_supplicant /system/bin/logwrapper /system/bin/wpa_supplicant -iwlan0 -puse_p2p_group_interface=1 -Dnl80211

        class late_start

        user root

        group wifi inet

        socket wpa_wlan0 dgram 660 wifi wifi

        disabled

        oneshot

     

    service dhcpcd_wlan0 /system/bin/dhcpcd -ABKLG

        class late_start

        disabled

        oneshot

     

    service qcom-sh /system/bin/sh /init.qcom.sh

        class late_start

        user root

        oneshot

     

    service qcom-wifi /system/bin/sh /system/etc/init.qcom.wifi.sh

        class late_start

        oneshot

     

    desnt works

    /system/bin/logwrapper /system/bin/wpa_supplicant -iwlan0 -puse_p2p_group_interface=1 -Dnl80211 -C/data/system/wpa_supplicant -c/data/misc/wifi/wpa_supplicant.conf


    展开全文
  • Theres a Warcraft: Legion pre-expansion patch just around the corner, and that means many changes and improvements will probably be finding their way in to the game. Weve recently defined several ...
  • 斑点检测的算法步骤: 图像处理第一步:去噪 1)Gaussian Smoothing(高斯平滑) 2)Isotropic Undecimated Wavelet Denoising 3)Patch-Based Denoising 4)Variance-Stabilizing Techniques 没错,我就只认识第一...
  • [总结]Unix设计哲学 编程艺术>>

    千次阅读 2012-05-29 08:32:12
    SPOT "真理的单点性"原则,DRY更直接! )。  这些原则就是经验总结,代表的是过去,仅供参考. 形式永远只是形式.  既然作者以Unix哲学比较禅宗,但我们也来思考一下. 寒冬下的寺庙内三位和尚:  1. 未加忍耐, 劈开佛像...
  • 计算机视觉论文-2021-03-10

    千次阅读 2021-03-10 09:10:08
    本专栏是计算机视觉方向论文收集积累,时间:2021年3月9日,来源:paper digest ... 直达笔记地址:机器学习手推笔记(GitHub地址) 1, TITLE:Selective Replay Enhances Learning in Online Continual ...
  • Paper:LSTM之父眼中的深度学习十年简史《The 2010s: Our Decade of Deep Learning / Outlook on the 2020s》的解读 The 2010s: Our Decade of Deep Learning / Outlook on the 2020s A previous post[MIR]...
  • Josef Kittler CATEGORY: cs.CV [cs.CV] HIGHLIGHT: In this paper, therefore, we propose a Patch PyramidTransformer(PPT) to effectively address the above issues. 28, TITLE: Human Trajectory Prediction ...
  • 目录 Tomcat v8.5配置文件 context.xml server.xml web.xml tomcat-users.xml ...从上面的目录的截图可以看出,除了catalina.*文件外,其实配置文件就是context.xml server.xml web.xml tomcat-users.xml四个文件...
  • Unity3d 周分享(16期 2019.5.1 )

    千次阅读 2019-05-01 15:02:54
    选自过去1~2周 自己所看到外文内容:https://twitter.com/unity3d 和各种其他博客来源吧 1)、 英国游戏工作室inkle是用于游戏开发的开源发布脚本语言“ink”, 可以在 Unity中工作。 ...
  • 基于计数器的热点探测(Counter Based Hot Spot Detection):采用这种方法的虚拟机会为每个方法(甚至是代码块)建立计数器,统计方法的执行次数,如果执行次数超过一定的阈值就认为它是“热点方法”。 这种统计...
  • 一些小效果的实现

    千次阅读 多人点赞 2016-12-18 11:48:25
    Create 9-Patch file... 创建点九图片。 上图就是最终完成的图片,在上面我有标注各个位置的含义。 替换图片后现在再来看看效果: 是不是看起来好多了。 其实上面介绍的这些内容都是很细节的东西...
  • (1.64 KB, patch) 2016-01-18 11:09 UTC , Mika Kuoppala Details | Diff Kernel bisection between v4.2 v4.1 for sudden freezes (2.53 KB, text/plain) 2016-02-01 22:06 UTC , ...
  • Patch Installer  -使用Composer安装补丁的库 Composer Checker  -校验Composer配置的工具   框架 Web开发框架 Symfony2  -一个独立组件组成的框架 Zend Framework 2  -另一个由独立...
  • MySQL8.03 RC 已发布

    千次阅读 2017-11-05 20:00:23
    Add JSON_MERGE_PATCH, rename JSON_MERGE to JSON_MERGE_PRESERVE (WL#9692) –This work by Knut Anders Hatlen implements two alternative JSON merge functions,JSON_MERGE_PATCH() and JSON_MERGE_PRESERVE()....
  • Unity高频面试题总结

    千次阅读 2016-10-26 11:40:13
    Resources的方式需要把所有资源全部打入安装包,这对游戏的分包发布(微端)和版本升级(patch)是不利的,所以unity推荐的方式是不用它,都用bundle的方式替代,把资源达成几个小的bundle,用哪个就load哪个,这样...
  • Patch Installer  - 一个使用Composer安装补丁的库 Composer Checker  - 一个校验Composer配置的工具 框架 Frameworks Web开发框架 Symfony 2  - 一个独立组件组成的框架 (SF2) Zend Framework ...
  • OpenWrt

    千次阅读 2016-10-25 16:35:45
     2.6.3 Patch Submission Process Chapter 1 The Router 1.1 Getting started 1.1.1 Installation 1.1.2 Initial configuration 1.1.3 Failsafe mode 1.2 Configuring OpenWrt 1.2.1 ...
  • AutodeskUberShader.fx

    千次阅读 2016-10-31 17:17:21
    http://files.crescentinc.co.jp/Autodesk_Maya_2015_dlm/Autodesk_Maya_2015_dlm/x64/Maya/Autodesk/Maya2015/presets/HLSL11/examples/ http://files.crescentinc.co.jp/Autodesk_Maya_2015_dlm/Autodesk_Maya_
  • Visual Tracking via Adaptive Structural Local Sparse Appearance Model
  • 关于三位一体2的渲染(网摘)

    千次阅读 2016-01-04 08:19:15
    Trine 2: Exklusive technical interview - great art design meets amazing lighting Although Trine 2 hit the market in last December, PC Games Hardware decided to talk to Frozenbyte, the Finnish devel
  • Unity 5.0Unity 5.0 is our biggest and boldest release ever. Powerful new features in Unity 5 include:The Physically-based Standard Shader to make your materials look consistent in any lighting envir
  • 高通8x25Q T4K35摄像头调试心得

    万次阅读 2015-04-02 19:20:29
    commit db285ae7f99fa669d65651b11bff78ea1364ef99 Author: wei.qifa Date: Thu Apr 2 15:37:44 2015 +0800  modified: chipcode/LINUX/android/vendor/qcom/proprietary/common/config/device-ven
  • 《游戏引擎架构》中英词汇索引表

    千次阅读 2015-05-05 12:18:29
    bicubic patch 双三次面片 363 bidirectional reflection distribution function/BRDF 双向反射分布函数 389 bidirectional surface scattering reflectance distribution function/...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,055
精华内容 422
关键字:

patchspot