症状:能扫不能用

局域网里一台佳能 iR-ADV C257/357 复合机,打印一切正常,但打开 「系统设置 › 打印机与扫描仪」,展开这台打印机的详情面板,没有「打开扫描仪…」按钮。

同一台机器的兄弟机型 C3926 有这个按钮。两台都是佳能 iR-ADV 系列,一台有、一台没有, 差别到底在哪?

更奇怪的是:打开 macOS 自带的「图像捕捉」,这台机器明明在列表里,点「概览」也能真的 扫出一张图来。所以扫描功能是好的,坏的只是"注册"。

先分清"是谁":一个打印机的身份链

排查这类问题最容易走偏的一步,是先把设备身份搞清楚,尤其是在看到陌生主机名时。

这台打印机的 mDNS 主机名是 MiWiFi-R4AC-srv.local —— 听着像个路由器。实际解析:

$ dscacheutil -q host -a name "MiWiFi-R4AC-srv.local"
name: miwifi-r4ac-srv.local
ip_address: 192.168.100.115

$ arp -n 192.168.100.115
? (192.168.100.115) at 34:9f:7b:bb:72:80 on en0

$ curl -s -D - -o /dev/null http://192.168.100.115/
HTTP/1.1 200 OK
Server: CANON HTTP Server

MAC 前三段 34:9f:7b 在 IEEE OUI 注册表里属于 CANON INC,加上 Server: CANON HTTP Server 和设备自己的自述:

$ curl -s http://192.168.100.115/eSCL/ScannerCapabilities | grep -E "MakeAndModel|SerialNumber"
  <pwg:MakeAndModel>Canon iR-ADV C257/357</pwg:MakeAndModel>
  <pwg:SerialNumber>2UL03800e</pwg:SerialNumber>

结论很明确:这是打印机自己。MiWiFi-R4AC 是它当年前任路由器(小米 R4AC)做 DHCP 时派下的主机名,后来路由器换成了 iStoreOS,这个"孤儿名"就留在了打印机身上。

教训:打印机继承旧 DHCP 主机名是常态,主机名本身不能证明设备身份,MAC 的 OUI 登记 + 设备自述才是。遇到"这是不是有人蹭 WiFi"的疑问,先走完身份链再决定动作。

顺带做了全网段排查(254 个地址,12 台存活,逐个核验),没有发现任何陌生设备。

分层诊断:打印队列 → 注册 → PPD → 发现 → 协议 → 端到端

macOS 上这类问题有明确的分层,逐层往下走,在能解释症状的那一层停下:

#层命令能看出什么
1队列lpstat -p -d、lpstat -v队列在不在、用的什么 URI
2注册system_profiler SPPrintersDataType最快信号:Scanning support: Yes/No
3PPDgrep -iE "APScanner|APICA" /private/etc/cups/ppd/<队列>.ppd队列知不知道自己能扫
4发现dns-sd -B _uscan._tcp local.设备有没有在广播扫描服务
5协议curl /eSCL/ScannerCapabilities、ipptool固件实际实现了哪种扫描协议
6端到端图像捕捉 → 选设备 → 概览扫描到底行不行

第 2 层立刻给出信号:

Canon iR-ADV C257/357:
  Scanning support: No          ← 异常
Canon iR-ADV C3926:
  Scanning support: Yes         ← 正常对照
  Scanner UUID: 96240608-6987-3728-6EA0-6AD33CFEC19A

根因:PPD 少了三个键

第 3 层把两个 PPD 一比,差异一目了然:

$ grep -iE "APScanner|APICA" /private/etc/cups/ppd/Canon_iR_ADV_C3926.ppd
*APScannerUUID: "96240608-6987-3728-6EA0-6AD33CFEC19A"
*APICADriver: True
*APScannerModulePath: "/System/Library/Image Capture/Devices/AirScanScanner.app"

$ grep -ci scan /private/etc/cups/ppd/Canon_iR_ADV_C257_357.ppd
0

三个键全缺。(这里有个容易漏的细节:不止 APScannerUUID 和 APScannerModulePath, 中间还有一个 *APICADriver: True。缺任何一个,表现完全一样。)

这三个键由 macOS 的 ipp2ppd 从设备的 IPP 属性里生成,也就是说,固件必须在 IPP 层 提供 scan-service-info 并响应 /ipp/scan。

第 4、5 层把矛盾摆出来了:

DNS-SD 发现层:Scan=T ✅        (_ipps/_ipp/_scanner/_uscan 的 TXT 都宣告支持扫描)
IPP 属性层:  scan 属性 0 条 ❌   (/ipp/scan → HTTP 404)

设备在发现层说了"我支持扫描",却在 IPP 层没说。 这就是 bug 的确切位置。

一个反直觉的对照:C3926 的固件版本是 Main Controller:16.04,比 C357 的 21.13 更旧,但它的 IPP 层有扫描属性,所以 PPD 拿得到键、显示 Yes。

决定因素不是固件新旧,是 IPP 层有没有 scan-service-info。 新固件在这件事上完全 可能比旧固件更差。

扫描功能其实完全正常

第 6 层必须做,否则很容易把"注册标签缺失"误判成"扫描坏了"。直接打 eSCL:

$ curl -s -o /dev/null -w "%{http_code}\n" http://192.168.100.115/eSCL/ScannerCapabilities
200

用系统发现器(AddPrinter.app)的日志也能确认设备被正常发现:

Added | Canon iR-ADV C257/357
  ICDevice |  +++ Creating [0x10000128]:CCC83054-4B12-351E-623C-F02F6FFACF2D
Dev Browser | Added: Canon iR-ADV C257/357

最终在「图像捕捉」里选这台机器点「概览」,设备侧的 eSCL 作业返回:

<scan:JobUri>/eSCL/ScanJobs/42</scan:JobUri>
<pwg:ImagesCompleted>1</pwg:ImagesCompleted>
<pwg:JobStateReason>JobCompletedSuccessfully</pwg:JobStateReason>

作业成功完成,扫出了 1 张图。 所以整件事是"能用的功能没被登记",不是"功能坏了"。

修复:把设备已有的事实补记回去

既然这台机器确实实现了 eSCL 扫描,那么 PPD 缺的这三个键描述的就是一个真实存在 的能力。补上它不是伪造功能,而是补记固件漏报的事实。

UUID 要用设备自己报的,不能编:

$ curl -s http://192.168.100.115/eSCL/ScannerCapabilities | grep scan:UUID
  <scan:UUID>ccc83054-4b12-351e-623c-f02f6ffacf2d</scan:UUID>

和 _scanner._tcp 广播 TXT 里的 UUID=ccc83054-4b12-351e-623c-f02f6ffacf2d 一致。

完整步骤:

# 1. 备份原 PPD(务必!回滚要用)
cp -p /private/etc/cups/ppd/Canon_iR_ADV_C257_357.ppd /tmp/Canon_iR_ADV_C257_357.ppd.orig

# 2. 追加三个键(UUID 写成大写,与 C3926 同风格)
printf '*APScannerUUID: "CCC83054-4B12-351E-623C-F02F6FFACF2D"\n*APICADriver: True\n*APScannerModulePath: "/System/Library/Image Capture/Devices/AirScanScanner.app"\n' \
  >> /tmp/Canon_iR_ADV_C257_357.ppd

第 3 步有个坑:PPD 目录是 root:_lp,lpadmin -m 会失败:

lpadmin:无法拷贝PPD文件。

lpadmin 想自己拷,但它没有权限写那个目录。改用 macOS 原生授权弹窗直接落盘:

osascript -e 'do shell script "cp /tmp/Canon_iR_ADV_C257_357.ppd /private/etc/cups/ppd/Canon_iR_ADV_C257_357.ppd && chown root:_lp /private/etc/cups/ppd/Canon_iR_ADV_C257_357.ppd && chmod 644 /private/etc/cups/ppd/Canon_iR_ADV_C257_357.ppd" with administrator privileges'

最后让 cupsd 重读(同样要 admin):

killall -HUP cupsd

结果

Canon iR-ADV C257/357:
  Scanning support: Yes                                    ← 修复前 No
  Scanner UUID: CCC83054-4B12-351E-623C-F02F6FFACF2D
  Scanning app: /System/Library/Image Capture/Devices/AirScanScanner.app

「打印机与扫描仪」里展开 C257 的详情面板,「打开扫描仪…」按钮出现了,和 「打印机中的队列…」并排,和 C3926 的布局一模一样。点它能正常唤起图像捕捉并带出这台 设备。

需要知道的三个后续事项

  1. 会回退。 重新添加这台打印机、或 macOS 升级重写 AirPrint PPD,补丁就没了。回滚:
    cp /tmp/Canon_iR_ADV_C257_357.ppd.orig /private/etc/cups/ppd/ && killall -HUP cupsd
    
  2. 长期正解仍是固件升级。 让佳能把 IPP-Scan 支持补上(AirPrint 2.x),Mac 侧就不用打补丁了。
  3. 改主机名是另一件事。 MiWiFi-R4AC-srv → Canon-C257,纯粹是为了以后不再被误认成可疑设备,与扫描无关。

小结

“扫描功能明明能用,系统里却显示没有扫描仪"这类问题,大概率不是驱动没装,而是 注册元数据缺失。

macOS 判定一个队列支持扫描,靠的是 PPD 里那三个键;而这三个键由固件经 IPP 层上报。 固件在 DNS-SD 层宣告了 Scan=T 却在 IPP 层沉默,macOS 就会把一台能扫的机器登记成 “只能打印”。

排查时务必做完端到端那一层——「图像捕捉」点一次「概览」,看设备侧作业是不是真的 JobCompletedSuccessfully。这一步能把"功能坏了"和"标签没了"彻底分开,也能避免白折腾 驱动重装。

至于设备身份:MAC 的 OUI 登记 + 设备自述永远比主机名可靠。打印机带着上一任路由器的 名字,是配置遗留,不是入侵。