Friday, January 2, 2015

[solved] xsane fails to find WLAN Brother scanner

Over the holiday I visited a buddy who put me on his home WLAN, which included a Brother MFC-8840D printer. This printer also has scanning capacity. I added the printer via CUPS, and it printed. I hadn't network scanned previously, so I tried Xsane, hoping for the best. Xsane failed to detect the MFC-8840D. I was skeptical about going straight to port 6566, since forwarding runs the risk of compromising the firewall or causing other security problems, which are easy to do, apparently. So, what to do? Below, I'll describe my solution, and then some of the troubleshooting (6+ hours) that preceded it.

1. overview

Budget a half-hour to forty minutes to accomplish the connection if you already know the steps. Some of my learning steps: 1) SANE and CUPS are entirely different pathways; SANE does not require CUPS to be operating or enabled during scanning, at least on a Brother, 2) determine the correct backend software for your scanner and download (if necessary), 3) if using brscan-skey for special buttons (see below) start the necessary daemons with systemctl. I didn't need brscan-skey however, had I needed it, this step is important, 4) manually install the config file (after backend).

2. scanner backend

This took getting used to. USB scanners typically don't require drivers in Linux so for this WLAN scanner, I was thinking all the scanner would need was a network connection. Over a network, a driver is also needed. Brother has a site for LAN backends. Go there to determine which version you need for your Brother model. There two files:
  • backend - for the older printer my buddy had it was "brscan". In the AUR, it says it's for USB scanners, but that's a misleading typo. Just download and install.
  • scan key - pointless unless you want to use automated physical keys on the scanner such as "scan to fax", "scan to email", etc. Secondly, if you obtained "brscan" in step 1 above from the AUR, then scan-key is included and you don't need this step anyway.
Note: For those who want brscan-skey, documentation shows it's good to omit the "user" and "group" fields, and install the service file to /usr/lib/systemd/user/brscan-skey.service instead of /usr/lib/systemd/system/brscan-skey.service. That's so users can start (or enable) the brscan-skeydaemon as a regular user without sudo, eg:
$ systemctl --user start brscan-skey
If you don't do all those permission changes, you apparently will need the standard:
# systemctl start brscan-skey.service
As noted above, I didn't need brscan-skey, so I disabled it (I also stopped CUPS).

3. install the config file

The following application is supposed to do the installation:
# /usr/share/brother/sane/setupSaneScan -i
This didn't work for me. In other words, after this step, I looked for the scanner and was greeted with the following:
$ scanimage -L
bugchk_free(ptr=(nil))@brother_modelinf.c(467)
Aborted (core dumped)

Strace indicated scanimage failed when looking for "Brother.ini" at /usr/local/Brother/sane/Brsane.ini. The file does exist however, at /usr/share/brother/sane/Brsane.ini, so I created the directory in /usr/local , and copied the file to where it was looking.
# cp /usr/share/brother/sane/Brsane.ini /usr/local/Brother/sane/Brsane.ini
At this point, the program ran through but, as user, could not create a socket connection due to permissions (go figure).
$ scanimage -L
[bjnp] create_broadcast_socket: bind socket to local address failed - Cannot assign requested address
What's apparently happened here is setupSaneScan doesn't work very well. It might even be unnecessary to run. In my case, it certainly failed to write the file /usr/share/brother/sane/brsanenetdevice.cfg, or to install the scanner. This site has the few lines needed to nano into /usr/share/brother/sane/brsanenetdevice.cfg. For example:
# nano /usr/share/brother/sane/brsanenetdevice.cfg
DEVICE=MFC8840D , "MFC-8840D" , 0x4f9:0x160 , IP-ADDRESS=192.168.1.4

In summary:
  • copy /usr/share/brother/sane/Brsane.ini to /usr/local/Brother/sane/Brsane.ini
  • create and enter lines into /usr/share/brother/sane/brsanenetdevice.cfg

4. install the scanner driver

Following the hand-entries in /usr/share/brother/sane/brsanenetdevice.cfg, the printer/scanner still must be installed.
  • unless desired, turn off CUPS and brscan-skey with systemctl
    # systemctl stop org.cups.cupsd.service
    # systemctl stop brscan-skey.service
  • obtain the IP of the printer, you'll recognize it by its operating system
    # nmap -O 192.168.1.1/24 -oG
  • obtain the exact model name for the printer from /usr/share/brother/sane/Brsane.ini
  • let's say the printer IP was 192.168.1.4, and the model name was "MFC-8840D". Using these values, or the ones for your printer, enter /usr/share/brother/sane/brsaneconfig -a name="common name" model="model from INI" ip=xxx.xxx.xx.xx", eg,
    # /usr/share/brother/sane/brsaneconfig -a name=MFC8840D model=MFC-8840D ip=192.168.1.4
  • verify this went through with "brsaneconfig -q", and "scanimage -L"
# /usr/share/brother/sane/brsaneconfig -q
Devices on network 0 MFC8840D MFC-8840D I:192.168.1.4
$ scanimage -L
device `brother:net1;dev0' is a Brother MFC-8840D MFC8840D
So, with scanimage -L showing detection, xsane can be initiated for scanning.

investigation leading to solution (6+ hrs)

This is not necessary to read; it's just crib notes (to save time in the future) of troubleshooting which eventually led to a solution.

To start with, I left the CUPS daemon on. I wasn't sure what might be necessary to detect the scanner. Further down here, I realize CUPS actually gets in the way of installation. Secondly, I read that scanner drivers expect "nobody" should be included in the "scanner" group. You can do this with, eg...
# usermod -a -G scanner nobody
... but I like to directly (not recommended) type into the /etc/group and /etc/passwd files: I added nobody to the scanner group in /etc/group. None of these changes had any effect, but YMMV. I then checked for scanners.
$ scanimage -L
[bjnp] create_broadcast_socket: bind socket to local address failed - Cannot assign requested address
Since BJNP is the Canon-specific CUPS back-end, and since my attempt to connect was to a Brother, the unsolicited appearance of BJNP, and causing scanimage to repeatedly fail, was... annoying.

A more powerful attempt to locate the fail...
# strace scanimage -L 2>&1 |tee bigfile.txt
# chown 500:500 bigfile.txt
$ grep socket bigfile.txt >bigfile2.txt
And here's the portion with the fail...
socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP) = 132 setsockopt(132, SOL_SOCKET, SO_BROADCAST, [1], 4) = 0 setsockopt(132, SOL_IPV6, IPV6_V6ONLY, [1], 4) = 0 bind(132, {sa_family=AF_INET6, sin6_port=htons(8612), inet_pton(AF_INET6, "fe80::b277:2173:31a6:e71", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=if_nametoindex("enp4s0")}, 28) = -1 EADDRNOTAVAIL (Cannot assign requested address) fstat(2, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0 write(2, "[bjnp] ", 7[bjnp] ) = 7 write(2, "create_broadcast_socket: bind so"..., 95create_broadcast_socket: bind socket to local address failed - Cannot assign requested address ) = 95 close(132)
Subroutine 132 is failing. The real fail was scanimage was demanding an IPV6 addresses, which of course is a too rigid restriction to place onto an older IPV4 scanner. Additionally, scanimage was soliciting via "enp4s0", the ethernet LAN NIC. This was a further problem because the LAN NIC was not connected, I was only connecting via my WiFi card. If scanimage demanded these to be present, nothing was going to work on the older Brother on a WAN.

To be sure I wasn't crazy, I nmap-ped the LAN ("nmap -O 192.168.1.1/24 -oG somefile.txt") , found the printer by the Brother OS, and made sure I was able to ping it successfully, using only the WiFi NIC, and leaving the LAN NIC disconnected. This was a success. But I never was able to eliminate the BJNP, IPV6, or LAN NIC failures with the CUPS daemon "on".

/etc/sane.d/saned.conf

Digging through some pages, it appeared the first effort should be to modify /etc/sane.d/saned.conf When I opened the file, all lines were commented, so I added two uncommented lines
localhost 192.168.1.0/24

/etc/saned.d/net.conf

According to http://wiki.archlinux.org/index.php/sane, the file /etc/sane.d/net.conf must be similarly modified.
localhost 192.168.1.0/24

to xinetd or not xinetd?

Xinetd is for allowing anyone on a LAN to use a hardwired (eg. by USB) scanner. My friend's Brother was sitting on a WLAN, independent of any system, so it should have been simpler. Still, after I installed xinetd (pacman), some tweaks were required. For example, in /etc/sane.d/saned.conf,these lines are at the bottom:
# NOTE: /etc/inetd.conf (or /etc/xinetd.conf) and # /etc/services must also be properly configured to start...
Well now. /etc/services is a listing of applications for each port, and sane-port was there at line 6566 for both UDP and TCP. This appeared OK. Next stop was /etc/xinetd.d/sane.
# cat /etc/xinetd.d/sane service sane-port { port = 6566 socket_type = stream wait = no user = nobody group = scanner server = /usr/bin/saned # disabled by default! disable = yes }
So there's nothing allowing LAN access. Using the site above, and this Slackware page, I changed the file by adding "tcp" capability (because WLAN):
# cat /etc/xinetd.d/sane service sane-port { port = 6566 socket_type = stream protocol = tcp wait = no user = nobody group = scanner server = /usr/bin/saned # disabled by default! disable = no }

check loopback

If you went the nuclear route and brought down your firewall during this, a good check to be sure it's re-established is to telnet into it. The connection should be refused.
telnet localhost [service port]
For example, xsane uses port 6566 so...
telnet localhost 6566
Try telnetting as both root and user; if groups are properly set-up, users should be able to telnet the port.

No comments: